Completed
Push — mysql_improvements ( 013528...7b45c6 )
by George
04:40 queued 02:17
created

StatsJsonView::processSingleSource()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 4

Importance

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