Completed
Push — master ( 437185...b9fa04 )
by Michael
05:34
created

StatsJsonView::buildResponseData()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 27
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 27
ccs 0
cts 12
cp 0
rs 8.439
cc 5
eloc 12
nc 8
nop 1
crap 30
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   bool  $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(bool $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
	public function render()
71
	{
72
		$items = $this->model->getItems($this->source);
73
74
		// Null out the model now to free some memory
75
		$this->model = null;
76
77
		if ($this->source)
78
		{
79
			return $this->processSingleSource($items);
80
		}
81
82
		$php_version = [];
83
		$db_type     = [];
84
		$db_version  = [];
85
		$cms_version = [];
86
		$server_os   = [];
87
88
		// If we have the entire database, we have to loop within each group to put it all together
89
		foreach ($items as $group)
90
		{
91
			$this->totalItems += count($group);
92
93
			foreach ($group as $item)
94
			{
95
				foreach ($this->dataSources as $source)
96
				{
97
					if (isset($item[$source]) && !is_null($item[$source]))
98
					{
99
						// Special case, if the server is empty then change the key to "unknown"
100
						if ($source === 'server_os' && empty($item[$source]))
101
						{
102
							if (!isset(${$source}['unknown']))
103
							{
104
								${$source}['unknown'] = 0;
105
							}
106
107
							${$source}['unknown']++;
108
						}
109
						else
110
						{
111 View Code Duplication
							if (!isset(${$source}[$item[$source]]))
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...
112
							{
113
								${$source}[$item[$source]] = 0;
114
							}
115
116
							${$source}[$item[$source]]++;
117
						}
118
					}
119
				}
120
			}
121
		}
122
123
		unset($items);
124
125
		$data = [
126
			'php_version' => $php_version,
127
			'db_type'     => $db_type,
128
			'db_version'  => $db_version,
129
			'cms_version' => $cms_version,
130
			'server_os'   => $server_os,
131
		];
132
133
		$responseData = $this->buildResponseData($data);
134
135
		$responseData['total'] = $this->totalItems;
136
137
		$this->addData('data', $responseData);
138
139
		return parent::render();
140
	}
141
142
	/**
143
	 * Set the data source.
144
	 *
145
	 * @param   string  $source  Data source to return.
146
	 *
147
	 * @return  void
148
	 *
149
	 * @since   1.0
150
	 */
151 1
	public function setSource(string $source)
152
	{
153 1
		$this->source = $source;
154 1
	}
155
156
	/**
157
	 * Process the raw data into the response data format.
158
	 *
159
	 * @param   array  $data  The raw data array.
160
	 *
161
	 * @return  array
162
	 *
163
	 * @since   1.0
164
	 */
165
	private function buildResponseData(array $data) : array
166
	{
167
		$responseData = [];
168
169
		foreach ($data as $key => $value)
170
		{
171
			foreach ($value as $name => $count)
172
			{
173
				if ($name)
174
				{
175
					$responseData[$key][] = [
176
						'name'  => $name,
177
						'count' => $count
178
					];
179
				}
180
			}
181
		}
182
183
		unset($data);
184
185
		if (!$this->authorizedRaw)
186
		{
187
			$responseData = $this->sanitizeData($responseData);
188
		}
189
190
		return $responseData;
191
	}
192
193
	/**
194
	 * Process the response for a single data source.
195
	 *
196
	 * @param   \Generator  $generator  The source items to process.
197
	 *
198
	 * @return  string  The rendered view.
199
	 *
200
	 * @since   1.0
201
	 */
202
	private function processSingleSource(\Generator $generator) : string
203
	{
204
		$data = [
205
			${$this->source} = [],
206
		];
207
208
		foreach ($generator as $group)
209
		{
210
			$this->totalItems += count($group);
211
212
			foreach ($group as $item)
213
			{
214
				foreach ($this->dataSources as $source)
215
				{
216
					if (isset($item[$source]) && !is_null($item[$source]))
217
					{
218
						// Special case, if the server is empty then change the key to "unknown"
219
						if ($source === 'server_os' && empty($item[$source]))
220
						{
221
							if (!isset($data[$source]['unknown']))
222
							{
223
								$data[$source]['unknown'] = 0;
224
							}
225
226
							$data[$source]['unknown']++;
227
						}
228
						else
229
						{
230 View Code Duplication
							if (!isset($data[$source][$item[$source]]))
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...
231
							{
232
								$data[$source][$item[$source]] = 0;
233
							}
234
235
							$data[$source][$item[$source]]++;
236
						}
237
					}
238
				}
239
			}
240
		}
241
242
		unset($generator);
243
244
		$responseData = $this->buildResponseData($data);
245
246
		$responseData['total'] = $this->totalItems;
247
248
		$this->addData('data', $responseData);
249
250
		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...
251
	}
252
253
	/**
254
	 * Sanitize the response data into summarized groups.
255
	 *
256
	 * @param   array  $responseData  The response data to sanitize.
257
	 *
258
	 * @return  array
259
	 *
260
	 * @since   1.0
261
	 */
262
	private function sanitizeData(array $responseData) : array
263
	{
264
		foreach ($responseData as $key => $dataGroup)
265
		{
266
			switch ($key)
267
			{
268
				case 'php_version':
269
				case 'db_version':
270
					// We're going to group by minor version branch here and convert to a percentage
271
					$counts = [];
272
273
					foreach ($dataGroup as $row)
274
					{
275
						$exploded = explode('.', $row['name']);
276
						$version  = $exploded[0] . '.' . (isset($exploded[1]) ? $exploded[1] : '0');
277
278
						// If the container does not exist, add it
279
						if (!isset($counts[$version]))
280
						{
281
							$counts[$version] = 0;
282
						}
283
284
						$counts[$version] += $row['count'];
285
					}
286
287
					$sanitizedData = [];
288
289 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...
290
					{
291
						$sanitizedData[$version] = round(($count / $this->totalItems) * 100, 2);
292
					}
293
294
					$responseData[$key] = $sanitizedData;
295
296
					break;
297
298
				case 'server_os':
299
					// We're going to group by operating system here
300
					$counts = [];
301
302
					foreach ($dataGroup as $row)
303
					{
304
						$fullOs = explode(' ', $row['name']);
305
						$os     = $fullOs[0];
306
307
						// If the container does not exist, add it
308
						if (!isset($counts[$os]))
309
						{
310
							$counts[$os] = 0;
311
						}
312
313
						$counts[$os] += $row['count'];
314
					}
315
316
					$sanitizedData = [];
317
318 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...
319
					{
320
						$sanitizedData[$os] = round(($count / $this->totalItems) * 100, 2);
321
					}
322
323
					$responseData[$key] = $sanitizedData;
324
325
					break;
326
327
				case 'db_type':
328
				case 'cms_version':
329
				default:
330
					// For now, group by the object name and figure out the percentages
331
					$sanitizedData = [];
332
333
					foreach ($dataGroup as $row)
334
					{
335
						$sanitizedData[$row['name']] = round(($row['count'] / $this->totalItems) * 100, 2);
336
					}
337
338
					$responseData[$key] = $sanitizedData;
339
340
					break;
341
			}
342
		}
343
344
		return $responseData;
345
	}
346
}
347