Completed
Push — master ( 4e5c99...220c92 )
by Michael
05:11
created

StatsJsonView::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Stats\Views\Stats;
4
5
use Joomla\View\BaseJsonView;
6
use Stats\Models\StatsModel;
7
8
/**
9
 * JSON response for requesting the stats data.
10
 *
11
 * @since  1.0
12
 */
13
class StatsJsonView extends BaseJsonView
14
{
15
	/**
16
	 * Flag if the response should return the raw data.
17
	 *
18
	 * @var    boolean
19
	 * @since  1.0
20
	 */
21
	private $authorizedRaw = false;
22
23
	/**
24
	 * Array holding the valid data sources.
25
	 *
26
	 * @var    array
27
	 * @since  1.0
28
	 */
29
	private $dataSources = ['php_version', 'db_type', 'db_version', 'cms_version', 'server_os'];
30
31
	/**
32
	 * The data source to return.
33
	 *
34
	 * @var    string
35
	 * @since  1.0
36
	 */
37
	private $source = '';
38
39
	/**
40
	 * Count of the number of items.
41
	 *
42
	 * @var    integer
43
	 * @since  1.0
44
	 */
45
	private $totalItems = 0;
46
47
	/**
48
	 * Instantiate the view.
49
	 *
50
	 * @param   StatsModel  $model  The model object.
51
	 *
52
	 * @since   1.0
53
	 */
54
	public function __construct(StatsModel $model)
55
	{
56
		$this->model = $model;
0 ignored issues
show
Documentation Bug introduced by
It seems like $model of type object<Stats\Models\StatsModel> is incompatible with the declared type object<Joomla\Model\ModelInterface> of property $model.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
57
	}
58
59
	/**
60
	 * Set whether the raw data should be returned.
61
	 *
62
	 * @param   bool  $authorizedRaw  Flag if the response should return the raw data.
63
	 *
64
	 * @return  void
65
	 *
66
	 * @since   1.0
67
	 */
68 1
	public function isAuthorizedRaw(bool $authorizedRaw)
69
	{
70 1
		$this->authorizedRaw = $authorizedRaw;
71 1
	}
72
73
	/**
74
	 * Method to render the view.
75
	 *
76
	 * @return  string  The rendered view.
77
	 *
78
	 * @since   1.0
79
	 * @throws  \InvalidArgumentException
80
	 */
81
	public function render()
82
	{
83
		$items = $this->model->getItems($this->source);
0 ignored issues
show
Bug introduced by
The method getItems() does not seem to exist on object<Joomla\Model\ModelInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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