Passed
Push — main ( 0009be...03a93c )
by Will
02:49
created

devices::getDevice()   F

Complexity

Conditions 16
Paths 1025

Size

Total Lines 78
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 62
CRAP Score 16

Importance

Changes 0
Metric Value
eloc 60
c 0
b 0
f 0
dl 0
loc 78
ccs 62
cts 62
cp 1
rs 1.4
cc 16
nc 1025
nop 1
crap 16

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
declare(strict_types = 1);
3
namespace hexydec\agentzero;
4
5
/**
6
 * @phpstan-import-type MatchConfig from config
7
 */
8
class devices {
9
10
	/**
11
	 * Generates a configuration array for matching devices
12
	 * 
13
	 * @return MatchConfig An array with keys representing the string to match, and a value of an array containing parsing and output settings
0 ignored issues
show
Bug introduced by
The type hexydec\agentzero\MatchConfig was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
	 */
15 78
	public static function get() : array {
16 3
		$fn = [
17 3
			'ios' => function (string $value, int $i, array $tokens) : array {
18 15
				$version = null;
19 15
				$model = null;
20 15
				foreach ($tokens AS $item) {
21 15
					if (\str_starts_with($item, 'Mobile/')) {
22 15
						$model = \mb_substr($item, 7);
23 15
					} elseif (\str_starts_with($item, 'CPU iPhone OS ')) {
24 14
						$version = \str_replace('_', '.', \mb_substr($item, 14, \mb_strpos($item, ' ', 14) - 14));
25 15
					} elseif (\str_starts_with($item, 'CPU OS ')) {
26 2
						$version = \str_replace('_', '.', \mb_substr($item, 7, \mb_strpos($item, ' ', 7) - 7));
27
					}
28
				}
29 15
				return [
30 15
					'type' => 'human',
31 15
					'category' => $value === 'iPad' ? 'tablet' : 'mobile',
32 15
					'architecture' => 'arm',
33 15
					'bits' => $value === 'iPod' ? 32 : 64,
34 15
					'kernel' => 'Linux',
35 15
					'platform' => 'iOS',
36 15
					'platformversion' => $version,
37 15
					'vendor' => 'Apple',
38 15
					'device' => $value,
39 15
					'model' => $model
40 15
				];
41 3
			},
42 3
			'xbox' => fn (string $value) : array => [
43 3
				'type' => 'human',
44 3
				'category' => 'console',
45 3
				'vendor' => 'Microsoft',
46 3
				'device' => 'Xbox',
47 3
				'model' => ($model = \mb_substr($value, 5)) === '' ? null : $model
48 3
			],
49 3
			'playstation' => function (string $value) : array {
50 1
				$parts = \explode(' ', $value);
51 1
				if (\str_contains($parts[1], '/')) {
52 1
					list($parts[1], $parts[2]) = \explode('/', $parts[1]);
53
				}
54 1
				$platform = [
55 1
					4 => 'Orbis OS',
56 1
					5 => 'FreeBSD'
57 1
				];
58 1
				return [
59 1
					'device' => $parts[0],
60 1
					'model' => $parts[1] ?? null,
61 1
					'kernel' => 'Linux',
62 1
					'platform' => $platform[\intval($parts[1])] ?? null,
63 1
					'platformversion' => $parts[2] ?? null,
64 1
					'type' => 'human',
65 1
					'category' => 'console',
66 1
					'vendor' => 'Sony',
67 1
					'processor' => 'AMD',
68 1
					'architecture' => 'x86',
69 1
					'bits' => 64
70 1
				];
71 3
			},
72 3
			'firetablet' => fn (string $value) : array => [
73 2
				'type' => 'human',
74 2
				'category' => 'tablet',
75 2
				'vendor' => 'Amazon',
76 2
				'device' => 'Fire Tablet',
77 2
				'model' => $value
78 2
			]
79 3
		];
80 25
		return [
81 25
			'iPhone' => [
82 25
				'match' => 'exact',
83 25
				'categories' => $fn['ios']
84 25
			],
85 25
			'iPad' => [
86 25
				'match' => 'exact',
87 25
				'categories' => $fn['ios']
88 25
			],
89 25
			'iPod' => [
90 25
				'match' => 'exact',
91 25
				'categories' => $fn['ios']
92 25
			],
93 25
			'iPod touch' => [
94 25
				'match' => 'exact',
95 25
				'categories' => $fn['ios']
96 25
			],
97 25
			'Macintosh' => [
98 25
				'match' => 'exact',
99 25
				'categories' => [
100 25
					'vendor' => 'Apple',
101 25
					'device' => 'Macintosh'
102 25
				]
103 25
			],
104 25
			'Quest' => [
105 25
				'match' => 'start',
106 25
				'categories' => fn (string $value) : array => [
107 3
					'vendor' => 'Oculus',
108 3
					'device' => 'Quest',
109 3
					'model' => ($model = \mb_substr($value, 6)) === '' ? null : $model,
110 3
					'type' => 'human',
111 3
					'category' => 'vr'
112 3
				]
113 25
			],
114 25
			'Pacific' => [
115 25
				'match' => 'start',
116 25
				'categories' => [
117 25
					'vendor' => 'Oculus',
118 25
					'device' => 'Go',
119 25
					'type' => 'human',
120 25
					'category' => 'vr'
121 25
				]
122 25
			],
123
			// 'Nintendo Wii U' => [
124
			// 	'match' => 'exact',
125
			// 	'categories' => [
126
			// 		'device' => 'Wii U',
127
			// 		'type' => 'human',
128
			// 		'category' => 'console',
129
			// 		'architecture' => 'PowerPC',
130
			// 		'vendor' => 'Nintendo'
131
			// 	]
132
			// ],
133
			// 'Nintendo WiiU' => [
134
			// 	'match' => 'exact',
135
			// 	'categories' => [
136
			// 		'device' => 'Wii U',
137
			// 		'type' => 'human',
138
			// 		'category' => 'console',
139
			// 		'architecture' => 'PowerPC',
140
			// 		'vendor' => 'Nintendo'
141
			// 	]
142
			// ],
143
			// 'Nintendo Wii' => [
144
			// 	'match' => 'exact',
145
			// 	'categories' => [
146
			// 		'device' => 'Wii',
147
			// 		'type' => 'human',
148
			// 		'category' => 'console',
149
			// 		'vendor' => 'Nintendo'
150
			// 	]
151
			// ],
152
			// 'Nintendo 3DS' => [
153
			// 	'match' => 'exact',
154
			// 	'categories' => [
155
			// 		'device' => '3DS',
156
			// 		'type' => 'human',
157
			// 		'category' => 'console',
158
			// 		'vendor' => 'Nintendo'
159
			// 	]
160
			// ],
161
			// 'Nintendo Switch' => [
162
			// 	'match' => 'exact',
163
			// 	'categories' => [
164
			// 		'device' => 'Switch',
165
			// 		'type' => 'human',
166
			// 		'category' => 'console',
167
			// 		'vendor' => 'Nintendo'
168
			// 	]
169
			// ],
170 25
			'Nintendo' => [
171 25
				'match' => 'start',
172 25
				'categories' => fn (string $value) : array => [
173 3
					'type' => 'human',
174 3
					'category' => 'console',
175 3
					'vendor' => 'Nintendo',
176 3
					'device' => $value === 'Nintendo WiiU' ? 'Wii U' : \mb_substr($value, 9),
177 3
					'architecture' => \str_ends_with($value, 'U') ? 'PowerPC' : null
178 3
				]
179 25
			],
180 25
			'Xbox Series S' => [
181 25
				'match' => 'exact',
182 25
				'categories' => $fn['xbox']
183 25
			],
184 25
			'Xbox Series X' => [
185 25
				'match' => 'exact',
186 25
				'categories' => $fn['xbox']
187 25
			],
188 25
			'Xbox One' => [
189 25
				'match' => 'exact',
190 25
				'categories' => $fn['xbox']
191 25
			],
192 25
			'Xbox 360' => [
193 25
				'match' => 'exact',
194 25
				'categories' => $fn['xbox']
195 25
			],
196 25
			'Xbox' => [
197 25
				'match' => 'exact',
198 25
				'categories' => $fn['xbox']
199 25
			],
200 25
			'Playstation 4' => [
201 25
				'match' => 'start',
202 25
				'categories' => $fn['playstation']
203 25
			],
204 25
			'Playstation 5' => [
205 25
				'match' => 'start',
206 25
				'categories' => $fn['playstation']
207 25
			],
208 25
			'SHIELD Android TV' => [
209 25
				'match' => 'start',
210 25
				'categories' => [
211 25
					'type' => 'human',
212 25
					'category' => 'console',
213 25
					'vendor' => 'NVIDIA',
214 25
					'device' => 'Shield'
215 25
				]
216 25
			],
217 25
			'CrKey/' => [
218 25
				'match' => 'start',
219 25
				'categories' => fn (string $value) : array => [
220 2
					'type' => 'human',
221 2
					'category' => 'tv',
222 2
					'app' => 'Chromecast',
223 2
					'appversion' => \explode(',', \mb_substr($value, 6), 2)[0]
224 2
				]
225 25
			],
226 25
			'ChromeBook' => [
227 25
				'match' => 'any',
228 25
				'categories' => [
229 25
					'type' => 'human',
230 25
					'category' => 'desktop'
231 25
				]
232 25
			],
233 25
			'GoogleTV' => [
234 25
				'match' => 'exact',
235 25
				'categories' => [
236 25
					'type' => 'human',
237 25
					'category' => 'tv',
238 25
					'device' => 'GoogleTV'
239 25
				]
240 25
			],
241 25
			'CriKey/' => [
242 25
				'match' => 'start',
243 25
				'categories' => fn (string $value) : array => [
244
					'type' => 'human',
245
					'category' => 'tv',
246
					'device' => 'Chromecast',
247
					'vendor' => 'Google',
248
					'platformversion' => \mb_substr($value, 7)
249
				]
250 25
			],
251 25
			'Apple/' => [
252 25
				'match' => 'start',
253 25
				'categories' => function (string $value) : array {
254 1
					$value = \mb_substr($value, 6);
255 1
					$split = \strcspn($value, '0123456789');
256 1
					$device = \mb_substr($value, 0, $split);
257 1
					return [
258 1
						'type' => 'human',
259 1
						'category' => $device === 'iPad' ? 'tablet' : 'mobile',
260 1
						'vendor' => 'Apple',
261 1
						'device' => $device,
262 1
						'model' => \mb_substr($value, $split) ?: null
263 1
					];
264 25
				}
265 25
			],
266 25
			'iPhone/' => [
267 25
				'match' => 'start',
268 25
				'categories' => fn (string $value) : array => [
269
					'platform' => 'iOS',
270
					'platformversion' => \mb_substr($value, 7),
271
					'vendor' => 'Apple',
272
					'device' => 'iPhone'
273
				]
274 25
			],
275 25
			'hw/iPhone' => [
276 25
				'match' => 'start',
277 25
				'categories' => fn (string $value) : array => [
278
					'platform' => 'iOS',
279
					'vendor' => 'Apple',
280
					'device' => 'iPhone',
281
					'model' => \str_replace('_', '.', \mb_substr($value, 9))
282
				]
283 25
			],
284 25
			'KFT' => [
285 25
				'match' => 'start',
286 25
				'categories' => $fn['firetablet']
287 25
			],
288 25
			'KFO' => [
289 25
				'match' => 'start',
290 25
				'categories' => $fn['firetablet']
291 25
			],
292 25
			'KFM' => [
293 25
				'match' => 'start',
294 25
				'categories' => $fn['firetablet']
295 25
			],
296 25
			'AFT' => [
297 25
				'match' => 'start',
298 25
				'categories' => fn (string $value) : array => [
299 1
					'type' => 'human',
300 1
					'category' => 'tv',
301 1
					'vendor' => 'Amazon',
302 1
					'device' => 'Fire TV',
303 1
					'model' => $value
304 1
				]
305 25
			],
306 25
			'Roku/' => [
307 25
				'match' => 'start',
308 25
				'categories' => fn (string $value, int $i, array $tokens) : array => [
309 1
					'type' => 'human',
310 1
					'category' => 'tv',
311 1
					'kernel' => 'Linux',
312 1
					'platform' => 'Roku OS',
313 1
					'platformversion' => \mb_substr($value, 5),
314 1
					'vendor' => 'Roku',
315 1
					'device' => 'Roku',
316 1
					'build' => $tokens[++$i] ?? null
317 1
				]
318 25
			],
319 25
			'AmigaOneX' => [
320 25
				'match' => 'start',
321 25
				'categories' => fn (string $value) : array => [
322 1
					'type' => 'human',
323 1
					'category' => 'desktop',
324 1
					'vendor' => 'A-Eon Technology',
325 1
					'device' => 'AmigaOne',
326 1
					'model' => \mb_substr($value, 8)
327 1
				]
328 25
			],
329 25
			'googleweblight' => [
330 25
				'match' => 'exact',
331 25
				'categories' => [
332 25
					'proxy' => 'googleweblight'
333 25
				]
334 25
			],
335 25
			'SAMSUNG-' => [
336 25
				'match' => 'start',
337 25
				'categories' => function (string $value) : array {
338 2
					$parts = \explode('/', $value, 2);
339 2
					return [
340 2
						'type' => 'human',
341 2
						'category' => 'mobile',
342 2
						'vendor' => 'Samsung',
343 2
						'model' => \mb_substr($parts[0], 8),
344 2
						'build' => $parts[1] ?? null,
345 2
					];
346 25
				}
347 25
			],
348 25
			'Samsung' => [
349 25
				'match' => 'start',
350 12
				'categories' => fn (string $value) : ?array => \str_starts_with($value, 'SamsungBrowser') ? null : [
351 12
					'vendor' => 'Samsung'
352 12
				]
353 25
			],
354 25
			'Acer' => [
355 25
				'match' => 'start',
356 25
				'categories' => [
357 25
					'vendor' => 'Acer'
358 25
				]
359 25
			],
360 25
			'SonyEricsson' => [
361 25
				'match' => 'start',
362 25
				'categories' => function (string $value) : array {
363 1
					$parts = \explode('/', $value, 2);
364 1
					return [
365 1
						'type' => 'human',
366 1
						'category' => 'mobile',
367 1
						'vendor' => 'Sony Ericsson',
368 1
						'model' => \mb_substr($parts[0], 12),
369 1
						'build' => $parts[1] ?? null
370 1
					];
371 25
				}
372 25
			],
373 25
			'LGE' => [
374 25
				'match' => 'exact',
375 25
				'categories' => function (string $value, int $i, array $tokens) : array {
376 1
					$device = $tokens[++$i] ?? null;
377 1
					$platformversion = empty($tokens[++$i]) ? null : \mb_substr(\explode(' ', $tokens[$i])[0], 5);
378 1
					$build = $tokens[++$i] ?? null;
379 1
					return [
380 1
						'type' => 'human',
381 1
						'category' => 'tv',
382 1
						'model' => $device,
383 1
						'build' => $build,
384 1
						'platformversion' => $platformversion,
385 1
						'vendor' => 'LG'
386 1
					];
387 25
				}
388 25
			],
389 25
			'NOKIA' => [
390 25
				'match' => 'start',
391 25
				'categories' => function (string $value) : array {
392 2
					return \array_merge(devices::getDevice($value), [
393 2
						'type' => 'human',
394 2
						'category' => 'mobile',
395 2
						'vendor' => 'Nokia',
396 2
					]);
397 25
				}
398 25
			],
399 25
			'Lumia' => [
400 25
				'match' => 'start',
401 25
				'categories' => fn (string $value) : array => \array_merge(devices::getDevice($value), [
402 25
					'type' => 'human',
403 25
					'category' => 'mobile',
404 25
					'vendor' => 'Nokia'
405 25
				])
406 25
			],
407 25
			'BRAVIA' => [
408 25
				'match' => 'start',
409 25
				'categories' => [
410 25
					'type' => 'human',
411 25
					'category' => 'tv',
412 25
					'vendor' => 'Sony',
413 25
					'device' => 'Bravia'
414 25
				]
415 25
			],
416 25
			'TECNO' => [
417 25
				'match' => 'start',
418 25
				'categories' => fn (string $value) : array =>  [
419 2
					'type' => 'human',
420 2
					'category' => 'mobile',
421 2
					'vendor' => 'Tecno',
422 2
					'model' => \explode(' ', \str_replace('-', ' ', $value), 2)[1] ?? null
423 2
				]
424 25
			],
425 25
			'ThinkPad' => [
426 25
				'match' => 'start',
427 25
				'categories' => function (string $value, int $i, array $tokens) : array {
428 1
					if (\mb_strpos($tokens[++$i] ?? '', 'Build/') === 0) {
429 1
						$device = \explode('_', \mb_substr($tokens[$i], 6));
430
					}
431 1
					return [
432 1
						'type' => 'human',
433 1
						'vendor' => 'Lenovo',
434 1
						'device' => $device[0] ?? null,
435 1
						'model' => $device[1] ?? null,
436 1
						'build' => $device[2] ?? null
437 1
					];
438 25
				}
439 25
			],
440 25
			'Model/' => [
441 25
				'match' => 'start',
442 25
				'categories' => fn (string $value) : array => [
443
					'model' => \mb_substr($value, 6)
444
				]
445 25
			],
446 25
			'Build/' => [
447 25
				'match' => 'any',
448 25
				'categories' => fn (string $value) : array => self::getDevice($value)
449 25
			],
450 25
			'x' => [
451 25
				'match' => 'any',
452 25
				'categories' => function (string $value) : ?array {
453 78
					$parts = \explode('x', $value);
454 78
					if (!isset($parts[2]) && \is_numeric($parts[0]) && \is_numeric($parts[1])) {
455 7
						return [
456 7
							'width' => \intval($parts[0]),
457 7
							'height' => \intval($parts[1])
458 7
						];
459
					}
460 78
					return null;
461 25
				}
462 25
			]
463 25
		];
464
	}
465
466
	/**
467
	 * Extracts device information from a token
468
	 * 
469
	 * @param string $value A token expected to contain device information
470
	 * @return array<string,string|null> An array containing the extracted devices information
471
	 */
472 31
	public static function getDevice(string $value) : array {
473 31
		foreach (['Mobile', 'Tablet', 'Safari', 'AppleWebKit', 'Linux', 'rv:'] AS $item) {
474 31
			if (\mb_stripos($value, $item) === 0) {
475 5
				return [];
476
			}
477
		}
478 29
		$parts = \explode('Build/', \str_ireplace('build/', 'Build/', $value), 2);
0 ignored issues
show
Bug introduced by
It seems like str_ireplace('build/', 'Build/', $value) can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

478
		$parts = \explode('Build/', /** @scrutinizer ignore-type */ \str_ireplace('build/', 'Build/', $value), 2);
Loading history...
479 29
		$parts[0] = \trim($parts[0]);
480 29
		$build = $parts[1] ?? null;
481 29
		$vendors = [
482 29
			'Samsung' => 'Samsung',
483 29
			'OnePlus' => 'OnePlus',
484 29
			'Oppo' => 'Oppo',
485 29
			'CPH' =>'OnePlus',
486 29
			'KB' => 'OnePlus',
487 29
			'Pixel' => 'Google',
488 29
			'SM-' => 'Samsung',
489 29
			'LM-' => 'LG',
490 29
			'LG' => 'LG',
491 29
			'RealMe' => 'RealMe',
492 29
			'RMX' => 'RealMe',
493 29
			'HTC' => 'HTC',
494 29
			'Nexus' => 'Google',
495 29
			'MI ' => 'Xiaomi',
496 29
			'HM ' => 'Xiaomi',
497 29
			'Huawei' => 'Huawei',
498 29
			'Honor' => 'Honor',
499 29
			'Motorola' => 'Motorola',
500 29
			'moto' => 'Motorola',
501 29
			'Intel' => 'Intel',
502 29
			'SonyEricsson' => 'Sony Ericsson',
503 29
			'Tecno' => 'Tecno',
504 29
			'Vivo' => 'Vivo',
505 29
			'Huawei' => 'Huawei',
506 29
			'Oppo' => 'Oppo',
507 29
			'Asus' => 'Asus',
508 29
			'Acer' => 'Acer',
509 29
			'Alcatel' => 'Alcatel',
510 29
			'Xiaomi' => 'Xiaomi',
511 29
			'Infinix' => 'Infinix',
512 29
			'Poco' => 'Poco',
513 29
			'Cubot' => 'Cubot',
514 29
			'Nokia' => 'Nokia'
515 29
		];
516
517
		// find vendor
518 29
		$vendor = null;
519 29
		foreach ($vendors AS $key => $item) {
520 29
			if (($pos = \mb_stripos($value, $key)) !== false) {
521 21
				$vendor = $item;
522
523
				// remove vendor name
524 21
				if ($pos === 0 && ($key === $item || $key === 'SonyEricsson')) {
525 13
					$parts[0] = \trim(\mb_substr($parts[0], \mb_strlen($key)), ' -_/');
526
				}
527 21
				break;
528
			}
529
		}
530 29
		$model = \explode(' ', $parts[0], 2);
531 29
		$device = $model[0] !== '' && \ctype_alpha($model[0]) ? \ucfirst($model[0]) : null; // device name if only letters
532 29
		$model = $device === null ? \implode(' ', $model) : ($model[1] ?? null); // reconstruct remainder of device name
533
534
		// remove everything after a slash
535 29
		if ($build === null && \str_contains($model ?? '', '/')) {
536 1
			$model = \mb_strstr($model, '/', true);
0 ignored issues
show
Bug introduced by
It seems like $model can also be of type null; however, parameter $haystack of mb_strstr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

536
			$model = \mb_strstr(/** @scrutinizer ignore-type */ $model, '/', true);
Loading history...
537
		}
538
539
		// special case for SMART TV
540 29
		if (\strcasecmp($device.$model, 'smarttv') === 0) {
541 1
			$device = 'Smart TV';
542 1
			$model = null;
543
		}
544
		// var_dump($value, $parts, $device, $model);
545 29
		return [
546 29
			'vendor' => $vendor === null ? null : self::getVendor($vendor),
547 29
			'device' => $device,
548 29
			'model' => $model ? \ucwords($model) : null,
549 29
			'build' => $build
550 29
		];
551
	}
552
553 21
	public static function getVendor(string $value) : string {
554 21
		$map = [
555 21
			'oneplus' => 'OnePlus',
556 21
			'lg' => 'LG',
557 21
			'lge' => 'LG',
558 21
			'realme' => 'RealMe',
559 21
			'htc' => 'HTC',
560 21
			'sonyericsson' => 'Sony Ericsson',
561 21
			'tcl' => 'TCL',
562 21
			'zte' => 'ZTE',
563 21
			'hmd' => 'HMD',
564 21
			'lt' => 'LT'
565 21
		];
566 21
		$value = \mb_strtolower($value);
567 21
		return $map[$value] ?? \mb_convert_case($value, MB_CASE_TITLE);
568
	}
569
}