Completed
Push — master ( b56490...a0dacf )
by Michael
05:39
created

StatsJsonView::sanitizeData()   D

Complexity

Conditions 15
Paths 33

Size

Total Lines 84
Code Lines 39

Duplication

Lines 8
Ratio 9.52 %

Code Coverage

Tests 48
CRAP Score 15.0019

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 8
loc 84
ccs 48
cts 49
cp 0.9796
rs 4.9121
cc 15
eloc 39
nc 33
nop 1
crap 15.0019

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Stats\Views\Stats;
4
5
use Joomla\View\BaseJsonView;
6
7
/**
8
 * JSON response for requesting the stats data.
9
 *
10
 * @property-read  \Stats\Models\StatsModel  $model  The model object.
11
 *
12
 * @since          1.0
13
 */
14
class StatsJsonView extends BaseJsonView
15
{
16
	/**
17
	 * Flag if the response should return the raw data.
18
	 *
19
	 * @var    boolean
20
	 * @since  1.0
21
	 */
22
	private $authorizedRaw = false;
23
24
	/**
25
	 * Array holding the valid data sources.
26
	 *
27
	 * @var    array
28
	 * @since  1.0
29
	 */
30
	private $dataSources = ['php_version', 'db_type', 'db_version', 'cms_version', 'server_os'];
31
32
	/**
33
	 * The data source to return.
34
	 *
35
	 * @var    string
36
	 * @since  1.0
37
	 */
38
	private $source;
39
40
	/**
41
	 * Count of the number of items.
42
	 *
43
	 * @var    integer
44
	 * @since  1.0
45
	 */
46
	private $totalItems = 0;
47
48
	/**
49
	 * Set whether the raw data should be returned.
50
	 *
51
	 * @param   boolean  $authorizedRaw  Flag if the response should return the raw data.
52
	 *
53
	 * @return  void
54
	 *
55
	 * @since   1.0
56
	 */
57 1
	public function isAuthorizedRaw($authorizedRaw)
58
	{
59 1
		$this->authorizedRaw = $authorizedRaw;
60 1
	}
61
62
	/**
63
	 * Method to render the view.
64
	 *
65
	 * @return  string  The rendered view.
66
	 *
67
	 * @since   1.0
68
	 * @throws  \InvalidArgumentException
69
	 */
70 4
	public function render()
71
	{
72 4
		$items = $this->model->getItems($this->source);
73
74 4
		$php_version = [];
75 4
		$db_type     = [];
76 4
		$db_version  = [];
77 4
		$cms_version = [];
78 4
		$server_os   = [];
79
80
		// If we have the entire database, we have to loop within each loop to put it all together
81 4
		if ($this->source)
82 4
		{
83 2
			return $this->processSingleSource($items);
84
		}
85
86 2
		foreach ($items as $group)
87
		{
88 2
			$this->totalItems += count($group);
89
90 2
			foreach ($group as $item)
0 ignored issues
show
Bug introduced by
The expression $group of type object<stdClass> is not traversable.
Loading history...
91
			{
92 2
				foreach ($this->dataSources as $source)
93
				{
94 2
					if (isset($item->$source) && !is_null($item->$source))
95 2
					{
96
						// Special case, if the server is empty then change the key to "unknown"
97 2
						if ($source === 'server_os' && empty($item->$source))
98 2
						{
99 2
							if (!isset(${$source}['unknown']))
100 2
							{
101 2
								${$source}['unknown'] = 0;
102 2
							}
103
104 2
							${$source}['unknown']++;
105 2
						}
106 View Code Duplication
						else
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
107
						{
108 2
							if (!isset(${$source}[$item->$source]))
109 2
							{
110 2
								${$source}[$item->$source] = 0;
111 2
							}
112
113 2
							${$source}[$item->$source]++;
114
						}
115 2
					}
116 2
				}
117 2
			}
118 2
		}
119
120
		$data = [
121 2
			'php_version' => $php_version,
122 2
			'db_type'     => $db_type,
123 2
			'db_version'  => $db_version,
124 2
			'cms_version' => $cms_version,
125 2
			'server_os'   => $server_os,
126 2
		];
127
128 2
		$responseData = $this->buildResponseData($data);
129
130 2
		$responseData['total'] = $this->totalItems;
131
132 2
		$this->addData('data', $responseData);
133
134 2
		return parent::render();
135
	}
136
137
	/**
138
	 * Set the data source.
139
	 *
140
	 * @param   string  $source  Data source to return.
141
	 *
142
	 * @return  void
143
	 *
144
	 * @since   1.0
145
	 */
146 1
	public function setSource($source)
147
	{
148 1
		$this->source = $source;
149 1
	}
150
151
	/**
152
	 * Process the raw data into the response data format.
153
	 *
154
	 * @param   array  $data  The raw data array.
155
	 *
156
	 * @return  array
157
	 *
158
	 * @since   1.0
159
	 */
160 4
	private function buildResponseData(array $data)
161
	{
162 4
		$responseData = [];
163
164 4
		foreach ($data as $key => $value)
165
		{
166 4
			foreach ($value as $name => $count)
167
			{
168
				if ($name)
169 4
				{
170 4
					$responseData[$key][] = [
171 4
						'name'  => $name,
172
						'count' => $count
173 4
					];
174 4
				}
175 4
			}
176 4
		}
177
178 4
		if (!$this->authorizedRaw)
179 4
		{
180 3
			$responseData = $this->sanitizeData($responseData);
181 3
		}
182
183 4
		return $responseData;
184
	}
185
186
	/**
187
	 * Process the response for a single data source.
188
	 *
189
	 * @param   array  $items  The source items to process.
190
	 *
191
	 * @return  string  The rendered view.
192
	 *
193
	 * @since   1.0
194
	 */
195 2
	private function processSingleSource(array $items)
196
	{
197
		$data = [
198 2
			${$this->source} = [],
199 2
		];
200
201 2
		$this->totalItems = count($items);
202
203 2
		foreach ($items as $item)
204
		{
205 2
			foreach ($this->dataSources as $source)
206
			{
207 2
				if (isset($item->$source) && !is_null($item->$source))
208 2
				{
209
					// Special case, if the server is empty then change the key to "unknown"
210 2
					if ($source === 'server_os' && empty($item->$source))
211 2
					{
212 1
						if (!isset($data[$source]['unknown']))
213 1
						{
214 1
							$data[$source]['unknown'] = 0;
215 1
						}
216
217 1
						$data[$source]['unknown']++;
218 1
					}
219 View Code Duplication
					else
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
220
					{
221 2
						if (!isset($data[$source][$item->$source]))
222 2
						{
223 2
							$data[$source][$item->$source] = 0;
224 2
						}
225
226 2
						$data[$source][$item->$source]++;
227
					}
228 2
				}
229 2
			}
230 2
		}
231
232 2
		$responseData = $this->buildResponseData($data);
233
234 2
		$responseData['total'] = $this->totalItems;
235
236 2
		$this->addData('data', $responseData);
237
238 2
		return parent::render();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (render() instead of processSingleSource()). Are you sure this is correct? If so, you might want to change this to $this->render().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
239
	}
240
241
	/**
242
	 * Sanitize the response data into summarized groups.
243
	 *
244
	 * @param   array  $responseData  The response data to sanitize.
245
	 *
246
	 * @return  array
247
	 *
248
	 * @since   1.0
249
	 */
250 3
	private function sanitizeData(array $responseData)
251
	{
252 3
		foreach ($responseData as $key => $dataGroup)
253
		{
254
			switch ($key)
255
			{
256 3
				case 'php_version':
257 3
				case 'db_version':
258
					// We're going to group by minor version branch here and convert to a percentage
259 2
					$counts = [];
260
261 2
					foreach ($dataGroup as $row)
262
					{
263 2
						$exploded = explode('.', $row['name']);
264 2
						$version  = $exploded[0] . '.' . (isset($exploded[1]) ? $exploded[1] : '0');
265
266
						// If the container does not exist, add it
267 2
						if (!isset($counts[$version]))
268 2
						{
269 2
							$counts[$version] = 0;
270 2
						}
271
272 2
						$counts[$version] += $row['count'];
273 2
					}
274
275 2
					$sanitizedData = [];
276
277 2 View Code Duplication
					foreach ($counts as $version => $count)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
278
					{
279 2
						$sanitizedData[$version] = round(($count / $this->totalItems) * 100, 2);
280 2
					}
281
282 2
					$responseData[$key] = $sanitizedData;
283
284 2
					break;
285
286 2
				case 'server_os':
287
					// We're going to group by operating system here
288 2
					$counts = [];
289
290 2
					foreach ($dataGroup as $row)
291
					{
292 2
						$fullOs = explode(' ', $row['name']);
293 2
						$os     = $fullOs[0];
294
295
						// If the container does not exist, add it
296 2
						if (!isset($counts[$os]))
297 2
						{
298 2
							$counts[$os] = 0;
299 2
						}
300
301 2
						$counts[$os] += $row['count'];
302 2
					}
303
304 2
					$sanitizedData = [];
305
306 2 View Code Duplication
					foreach ($counts as $os => $count)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
307
					{
308 2
						$sanitizedData[$os] = round(($count / $this->totalItems) * 100, 2);
309 2
					}
310
311 2
					$responseData[$key] = $sanitizedData;
312
313 2
					break;
314
315 1
				case 'db_type':
316 1
				case 'cms_version':
317 1
				default:
318
					// For now, group by the object name and figure out the percentages
319 1
					$sanitizedData = [];
320
321 1
					foreach ($dataGroup as $row)
322
					{
323 1
						$sanitizedData[$row['name']] = round(($row['count'] / $this->totalItems) * 100, 2);
324 1
					}
325
326 1
					$responseData[$key] = $sanitizedData;
327
328 1
					break;
329
			}
330 3
		}
331
332 3
		return $responseData;
333
	}
334
}
335