Passed
Push — main ( 0a2d45...0009be )
by Will
02:48
created

devices   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 519
Duplicated Lines 0 %

Test Coverage

Coverage 96.34%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
eloc 393
c 1
b 0
f 0
dl 0
loc 519
ccs 474
cts 492
cp 0.9634
rs 10

3 Methods

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

460
		$device = \explode('Build/', /** @scrutinizer ignore-type */ \str_ireplace('build/', 'Build/', $value), 2);
Loading history...
461 29
		$device[0] = \trim($device[0]);
462 29
		$vendors = [
463 29
			'Samsung' => 'Samsung',
464 29
			'OnePlus' => 'OnePlus',
465 29
			'Oppo' => 'Oppo',
466 29
			'CPH' =>'OnePlus',
467 29
			'KB' => 'OnePlus',
468 29
			'Pixel' => 'Google',
469 29
			'SM-' => 'Samsung',
470 29
			'LM-' => 'LG',
471 29
			'LG' => 'LG',
472 29
			'RealMe' => 'RealMe',
473 29
			'RMX' => 'RealMe',
474 29
			'HTC' => 'HTC',
475 29
			'Nexus' => 'Google',
476 29
			'MI ' => 'Xiaomi',
477 29
			'HM ' => 'Xiaomi',
478 29
			'Huawei' => 'Huawei',
479 29
			'Honor' => 'Honor',
480 29
			'Motorola' => 'Motorola',
481 29
			'moto' => 'Motorola',
482 29
			'Intel' => 'Intel',
483 29
			'SonyEricsson' => 'Sony Ericsson',
484 29
			'Tecno' => 'Tecno',
485 29
			'Vivo' => 'Vivo',
486 29
			'Huawei' => 'Huawei',
487 29
			'Oppo' => 'Oppo',
488 29
			'Asus' => 'Asus',
489 29
			'Alcatel' => 'Alcatel',
490 29
			'Xiaomi' => 'Xiaomi',
491 29
			'Infinix' => 'Infinix',
492 29
			'Poco' => 'Poco',
493 29
			'Cubot' => 'Cubot'
494 29
		];
495 29
		$vendor = null;
496 29
		foreach ($vendors AS $key => $item) {
497 29
			if (($pos = \mb_stripos($value, $key)) !== false) {
498 19
				$vendor = $item;
499 19
				if ($pos === 0 && ($key === $item || $key === 'SonyEricsson')) {
500 10
					$device[0] = \trim(\mb_substr($device[0], \mb_strlen($key)), ' -_/');
501
				}
502 19
				break;
503
			}
504
		}
505 29
		return [
506 29
			'vendor' => $vendor === null ? null : self::getVendor($vendor),
507 29
			'device' => $device[0] === '' ? null : \ucwords($device[0]),
508 29
			'build' => $device[1] ?? null
509 29
		];
510
	}
511
512 19
	public static function getVendor(string $value) : string {
513 19
		$map = [
514 19
			'oneplus' => 'OnePlus',
515 19
			'lg' => 'LG',
516 19
			'lge' => 'LG',
517 19
			'realme' => 'RealMe',
518 19
			'htc' => 'HTC',
519 19
			'sonyericsson' => 'Sony Ericsson',
520 19
			'tcl' => 'TCL',
521 19
			'zte' => 'ZTE',
522 19
			'hmd' => 'HMD',
523 19
			'lt' => 'LT'
524 19
		];
525 19
		$value = \mb_strtolower($value);
526 19
		return $map[$value] ?? \mb_convert_case($value, MB_CASE_TITLE);
527
	}
528
}