Passed
Push — main ( 55ce30...607587 )
by Will
12:52
created

platforms   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 380
Duplicated Lines 0 %

Test Coverage

Coverage 99.71%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 293
c 3
b 0
f 0
dl 0
loc 380
ccs 346
cts 347
cp 0.9971
rs 8.8798
wmc 44

2 Methods

Rating   Name   Duplication   Size   Complexity  
A getPlatform() 0 14 1
F get() 0 355 43

How to fix   Complexity   

Complex Class

Complex classes like platforms often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use platforms, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types = 1);
3
namespace hexydec\agentzero;
4
5
class platforms {
6
7
	/**
8
	 * Generates a configuration array for matching platforms
9
	 * 
10
	 * @return array<string,props> An array with keys representing the string to match, and values a props object defining how to generate the match and which properties to set
11
	 */
12 60
	public static function get() : array {
13 1
		$fn = [
14 1
			'platformlinux' => function (string $value) : array {
15 14
				if (!\str_starts_with($value, 'Red Hat/') && ($platform = \mb_strstr($value, ' ', true)) !== false) {
16 5
					$value = $platform;
17
				}
18 14
				$parts = \explode('/', $value, 2);
19 14
				if (!isset($parts[1])) {
20 12
					$parts = \explode('-', $value, 2);
21
				}
22 14
				if (!isset($parts[1])) {
23 10
					$parts = \explode(' ', $value, 2);
24
				}
25 14
				return [
26 14
					'type' => 'human',
27 14
					'category' => 'desktop',
28 14
					'kernel' => 'Linux',
29 14
					'platform' => self::getPlatform($parts[0]),
30 14
					'platformversion' => $parts[1] ?? null
31 14
				];
32 1
			},
33 1
			'platformwindows' => function (string $value) : array {
34 46
				$mapping = [
35 46
					'5.0' => '2000',
36 46
					'5.1' => 'XP',
37 46
					'5.2' => 'XP',
38 46
					'6.0' => 'Vista',
39 46
					'6.1' => '7',
40 46
					'6.2' => '8',
41 46
					'6.3' => '8.1',
42 46
					'10.0' => '10'
43 46
				];
44 46
				$version = null;
45 46
				foreach (['Windows NT ', 'Windows '] AS $item) {
46 46
					if (($pos = \mb_stripos($value, $item)) !== false) {
47 46
						$version = \explode(' ', \mb_substr($value, $pos + \mb_strlen($item)))[0];
48 46
						break;
49
					}
50
				}
51 46
				return [
52 46
					'type' => 'human',
53 46
					'category' => 'desktop',
54 46
					'kernel' => 'Windows NT',
55 46
					'platform' => 'Windows',
56 46
					'platformversion' => $mapping[$version] ?? $version
57 46
				];
58 1
			},
59 1
			'android' => function (string $value, int $i, array $tokens) : array {
60 40
				$os = \explode(' ', $value, 3);
61
62
				// skip language
63 40
				if (!empty($tokens[++$i]) && (\strlen($tokens[$i]) === 2 || (\strlen($tokens[$i]) === 5 && \mb_strpos($tokens[$i], '_') === 2))) {
64 2
					$i++;
65
				}
66
67
				// only where the token length is greater than 2, or it doesn't contain a /, or if it does it is Build/
68 40
				$device = empty($tokens[$i]) || \strlen($tokens[$i]) <= 2 || (\str_contains($tokens[$i], '/') && \mb_stripos($tokens[$i], 'Build/') === false) ? [] : devices::getDevice($tokens[$i]);
69 40
				return \array_merge($device, [
70 40
					'type' => 'human',
71 40
					'platform' => 'Android',
72 40
					'platformversion' => isset($os[1]) ? \explode('/', $os[1])[0] : null
73 40
				]);
74 1
			}
75 1
		];
76
77 47
		return [
78
79
			// platforms
80 47
			'PalmSource' => new props('start', fn (string $value) : array => [
81 3
				'type' => 'human',
82 3
				'category' => 'mobile',
83 3
				'platform' => 'PalmOS',
84 3
				'platformversion' => \mb_substr($value, 11) ?: null,
85 3
				'kernel' => 'AMX 68000',
86 3
				'architecture' => 'arm',
87 3
				'bits' => 32,
88 3
			]),
89 47
			'PalmOS' => new props('start', fn (string $value) : array => [
90 2
				'type' => 'human',
91 2
				'category' => 'mobile',
92 2
				'platform' => 'PalmOS',
93 2
				'platformversion' => \mb_substr($value, 7) ?: null,
94 2
				'kernel' => 'AMX 68000',
95 2
				'architecture' => 'arm',
96 2
				'bits' => 32,
97 2
			]),
98 47
			'Windows NT ' => new props('any', $fn['platformwindows']),
99 47
			'Windows Phone' => new props('start', function (string $value) : array {
100 3
				$version = \mb_substr($value, 14);
101 3
				return [
102 3
					'type' => 'human',
103 3
					'category' => 'mobile',
104 3
					'platform' => 'Windows Phone',
105 3
					'platformversion' => $version,
106 3
					'kernel' => \intval($version) >= 8 ? 'Windows NT' : 'Windows CE'
107 3
				];
108 47
			}),
109 47
			'Win98' => new props('start', function (string $value, int $i, array $tokens) : array {
110 2
				foreach ($tokens AS $item) {
111 2
					if (\str_starts_with($item, 'PalmSource')) {
112
						return [];
113
					}
114
				}
115 2
				return [
116 2
					'type' => 'human',
117 2
					'category' => 'desktop',
118 2
					'architecture' => 'x86',
119 2
					'bits' => 32,
120 2
					'kernel' => 'MS-DOS',
121 2
					'platform' => 'Windows',
122 2
					'platformversion' => '98'
123 2
				];
124 47
			}),
125 47
			'Win32' => new props('exact', [
126 47
				'type' => 'human',
127 47
				'category' => 'desktop',
128 47
				'architecture' => 'x86',
129 47
				'bits' => 32,
130 47
				'platform' => 'Windows'
131 47
			]),
132 47
			'Win64' => new props('exact', [
133 47
				'type' => 'human',
134 47
				'category' => 'desktop',
135 47
				'bits' => 64,
136 47
				'platform' => 'Windows'
137 47
			]),
138 47
			'WinNT' => new props('start', fn (string $value) : array => [
139 2
				'type' => 'human',
140 2
				'category' => 'desktop',
141 2
				'architecture' => 'x86',
142 2
				'bits' => 32,
143 2
				'kernel' => 'Windows NT',
144 2
				'platform' => 'Windows',
145 2
				'platformversion' => \mb_substr($value, 5)
146 2
			]),
147 47
			'Windows' => new props('any', function (string $value, int $i, array $tokens) use ($fn) : array {
148 47
				foreach ($tokens AS $item) {
149 47
					if (\str_starts_with($item, 'PalmSource')) {
150 2
						return [];
151
					}
152
				}
153 46
				return $fn['platformwindows']($value, $i, $tokens);
154 47
			}),
155 47
			'Mac OS X' => new props('any', function (string $value) : array {
156 28
				$version = \str_replace('_', '.', \mb_substr($value, \mb_stripos($value, 'Mac OS X') + 9));
157 28
				$register = $version && \intval(\explode('.', $version)[1] ?? 0) >= 6 ? 64 : null;
158 28
				return [
159 28
					'type' => 'human',
160 28
					'category' => 'desktop',
161 28
					'kernel' => 'Linux',
162 28
					'platform' => 'Mac OS X',
163 28
					'platformversion' => $version === '' ? null : $version,
164 28
					'bits' => $register
165 28
				];
166 47
			}),
167 47
			'AppleTV' => new props('exact', [
168 47
				'type' => 'human',
169 47
				'category' => 'tv',
170 47
				'device' => 'AppleTV',
171 47
				'platform' => 'tvOS',
172 47
				'bits' => 64
173 47
			]),
174 47
			'iOS/' => new props('start', fn (string $value) : array => [
175 2
				'type' => 'human',
176 2
				'category' => 'mobile',
177 2
				'platform' => 'iOS',
178 2
				'platformversion' => \mb_substr($value, 4)
179 2
			]),
180 47
			'iOS ' => new props('start', fn (string $value) : array => [
181 3
				'type' => 'human',
182 3
				'category' => 'mobile',
183 3
				'platform' => 'iOS',
184 3
				'platformversion' => \str_replace('_', '.', \mb_substr($value, 4))
185 3
			]),
186 47
			'CrOS' => new props('start', function (string $value) : array {
187 4
				$parts = \explode(' ', $value);
188 4
				return [
189 4
					'type' => 'human',
190 4
					'category' => 'desktop',
191 4
					'platform' => 'Chrome OS',
192 4
					'platformversion' => $parts[2] ?? null
193 4
				];
194 47
			}),
195 47
			'Kindle/' => new props('start', fn (string $value) : array => [
196 2
				'type' => 'human',
197 2
				'category' => 'ebook',
198 2
				'platform' => 'Kindle',
199 2
				'platformversion' => \mb_substr($value, 7)
200 2
			]),
201 47
			'Tizen' => new props('start', function (string $value) : array {
202 1
				$parts = \explode(' ', $value, 2);
203 1
				return [
204 1
					'type' => 'human',
205 1
					'category' => 'desktop',
206 1
					'kernel' => 'Linux',
207 1
					'platform' => 'Tizen',
208 1
					'platformversion' => $parts[1] ?? null
209 1
				];
210 47
			}),
211 47
			'KAIOS/' => new props('start', function (string $value, int $i, array $tokens) : array {
212
213
				// find device
214 1
				foreach ($tokens AS $i => $item) {
215 1
					if ($item === 'Mobile' && !\str_starts_with($tokens[$i++] ?? 'rv:', 'rv:')) {
216 1
						if (\str_contains($tokens[$i], '/')) {
217 1
							$parts = \explode('/', $tokens[$i]);
218
						} else {
219 1
							$parts = \explode(' ', \str_replace('_', ' ', $tokens[$i]), 2);
220
						}
221 1
						break;
222
					}
223
				}
224 1
				return [
225 1
					'type' => 'human',
226 1
					'category' => 'mobile',
227 1
					'kernel' => 'Linux',
228 1
					'architecture' => 'arm',
229 1
					'platform' => 'KaiOS',
230 1
					'platformversion' => \mb_substr($value, 6),
231 1
					'vendor' => !empty($parts[0]) ? devices::getVendor($parts[0]) : null,
232 1
					'device' => $parts[1] ?? null,
233 1
					'build' => $parts[2] ?? null
234 1
				];
235 47
	}		),
236 47
			'Ubuntu' => new props('start', $fn['platformlinux']),
237 47
			'Kubuntu' => new props('start', $fn['platformlinux']),
238 47
			'Mint' => new props('start', $fn['platformlinux']),
239 47
			'SUSE' => new props('start', $fn['platformlinux']),
240 47
			'Red Hat/' => new props('start', $fn['platformlinux']),
241 47
			'Debian' => new props('start', $fn['platformlinux']),
242 47
			'Darwin' => new props('start', $fn['platformlinux']),
243 47
			'Fedora' => new props('start', $fn['platformlinux']),
244 47
			'CentOS' => new props('start', $fn['platformlinux']),
245 47
			'Rocky' => new props('start', $fn['platformlinux']),
246 47
			'Alma' => new props('start', $fn['platformlinux']),
247 47
			'Gentoo' => new props('start', $fn['platformlinux']),
248 47
			'Slackware' => new props('start', $fn['platformlinux']),
249 47
			'OpenSUSE' => new props('start', $fn['platformlinux']),
250 47
			'FreeBSD' => new props('start', $fn['platformlinux']),
251 47
			'OpenBSD' => new props('start', $fn['platformlinux']),
252 47
			'ArchLinux' => new props('exact', fn () : array => [
253 1
				'type' => 'human',
254 1
				'category' => 'desktop',
255 1
				'kernel' => 'Linux',
256 1
				'platform' => 'Arch',
257 1
			]),
258 47
			'Arch' => new props('exact', fn () : array => [
259 1
				'type' => 'human',
260 1
				'category' => 'desktop',
261 1
				'kernel' => 'Linux',
262 1
				'platform' => 'Arch',
263 1
			]),
264 47
			'Web0S' => new props('exact', $fn['platformlinux']),
265 47
			'webOSTV' => new props('exact', [
266 47
				'type' => 'human',
267 47
				'category' => 'tv',
268 47
				'kernel' => 'Linux',
269 47
				'platform' => 'WebOS'
270 47
			]),
271 47
			'WEBOS' => new props('start', fn (string $value) : array => [
272 2
				'type' => 'human',
273 2
				'category' => 'tv',
274 2
				'kernel' => 'Linux',
275 2
				'platform' => 'WebOS',
276 2
				'platformversion' => \mb_substr($value, 5)
277 2
			]),
278 47
			'SunOS' => new props('start', [
279 47
				'type' => 'human',
280 47
				'category' => 'desktop',
281 47
				'kernel' => 'unix',
282 47
				'platform' => 'Solaris',
283 47
			]),
284 47
			'AmigaOS' => new props('any', function (string $value) : array {
285 3
				if (($pos = \mb_stripos($value, 'AmigaOS')) !== false) {
286 3
					$value = \mb_substr($value, $pos);
287
				}
288 3
				$parts = \explode(' ', $value, 2);
289 3
				return [
290 3
					'type' => 'human',
291 3
					'category' => 'desktop',
292 3
					'kernel' => 'Exec',
293 3
					'platform' => 'AmigaOS',
294 3
					'platformversion' => isset($parts[1]) && \strspn($parts[1], '0123456789.-_') === \strlen($parts[1]) ? $parts[1] : null
295 3
				];
296 47
			}),
297 47
			'Fuchsia' => new props('exact', function (string $value, int $i, array $tokens) : array {
298 1
				$os = \explode(' ', $tokens[++$i], 2);
299 1
				return [
300 1
					'type' => 'human',
301 1
					'category' => 'mobile',
302 1
					'kernel' => 'Zircon',
303 1
					'platform' => 'Fuchsia',
304 1
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
305 1
				];
306 47
			}),
307 47
			'Maemo' => new props('exact', function (string $value, int $i, array $tokens) : array {
308 1
				$os = \explode(' ', $tokens[++$i], 2);
309 1
				return [
310 1
					'type' => 'human',
311 1
					'category' => 'mobile',
312 1
					'kernel' => 'Linux',
313 1
					'platform' => 'Maemo',
314 1
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
315 1
				];
316 47
			}),
317 47
			'J2ME/MIDP' => new props('exact', fn (string $value) : array => [
318 3
				'type' => 'human',
319 3
				'category' => 'mobile',
320 3
				'kernel' => 'Java VM',
321 3
				'platform' => $value
322 3
			]),
323 47
			'Haiku' => new props('any', function (string $value) : array {
324 3
				$parts = \explode('/', $value, 2);
325 3
				return [
326 3
					'type' => 'human',
327 3
					'category' => 'desktop',
328 3
					'kernel' => 'Haiku',
329 3
					'platform' => 'Haiku',
330 3
					'platformversion' => $parts[1] ?? null
331 3
				];
332 47
			}),
333 47
			'BeOS' => new props('start', function (string $value) : array {
334 1
				$parts = \explode('/', $value, 2);
335 1
				return [
336 1
					'type' => 'human',
337 1
					'category' => 'desktop',
338 1
					'kernel' => 'BeOS',
339 1
					'platform' => 'BeOS',
340 1
					'platformversion' => $parts[1] ?? null
341 1
				];
342 47
			}),
343 47
			'Android' => new props('exact', $fn['android']),
344 47
			'Android ' => new props('start', $fn['android']),
345 47
			'Linux' => new props('any', function (string $value, int $i, array $tokens) : array {
346 60
				return [
347 60
					'kernel' => 'Linux',
348 60
					'platform' => 'Linux',
349 60
					'platformversion' => \str_contains($tokens[$i + 1] ?? '', '.') && \strspn($tokens[$i + 1], '0123456789.') >= 3 ? \explode(' ', $tokens[$i + 1])[0] : null
350 60
				];
351 47
			}),
352 47
			'X11' => new props('exact', function (string $value, int $i, array $tokens) : array {
353 29
				$os = \explode(' ', $tokens[++$i] ?? '', 2);
354 29
				return [
355 29
					'category' => 'desktop',
356 29
					'kernel' => 'Linux',
357 29
					'platform' => $os[0] ?: 'X11',
358 29
					'platformversion' => isset($os[1]) && \strspn($os[1], '0123456789.-_', \strlen($os[0])) === \strlen($os[1]) ? $os[1] : null
359 29
				];
360 47
			}),
361 47
			'OS/2' => new props('exact', [
362 47
				'category' => 'desktop',
363 47
				'platform' => 'OS/2'
364 47
			]),
365 47
			'Version/' => new props('start', fn (string $value) : array => [
366 44
				'platformversion' => \mb_substr($value, 8)
367 44
			])
368 47
		];
369
	}
370
371 21
	public static function getPlatform(string $value) : string {
372 21
		$map = [
373 21
			'webos' => 'WebOS',
374 21
			'web0s' => 'WebOS',
375 21
			'j2me/midp' => 'J2ME/MIDP',
376 21
			'centos' => 'CentOS',
377 21
			'suse' => 'SUSE',
378 21
			'freebsd' => 'FreeBSD',
379 21
			'openbsd' => 'OpenBSD',
380 21
			'netbsd' => 'NetBSD',
381 21
			'opensuse' => 'OpenSUSE'
382 21
		];
383 21
		$value = \mb_strtolower($value);
384 21
		return $map[$value] ?? \mb_convert_case($value, MB_CASE_TITLE);
385
	}
386
}