Passed
Push — main ( 5a01f2...ad28d2 )
by Will
03:19
created

versions::load()   B

Complexity

Conditions 11
Paths 7

Size

Total Lines 34
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 12.1908

Importance

Changes 0
Metric Value
cc 11
eloc 13
c 0
b 0
f 0
nc 7
nop 3
dl 0
loc 34
ccs 11
cts 14
cp 0.7856
crap 12.1908
rs 7.3166

How to fix   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
class versions {
6
7
	protected static array|false|null $versions = null;
8
9 96
	protected static function load(string $source, ?string $cache = null, ?int $life = 604800) : array|false {
10
11
		// cache for this session
12 96
		$data = self::$versions;
13 96
		if ($data === null) {
14
15
			// fetch from cache
16 1
			if (\file_exists($cache) && \filemtime($cache) > \time() - $life && ($json = \file_get_contents($cache)) !== false) {
0 ignored issues
show
Bug introduced by
It seems like $cache can also be of type null; however, parameter $filename of file_get_contents() 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

16
			if (\file_exists($cache) && \filemtime($cache) > \time() - $life && ($json = \file_get_contents(/** @scrutinizer ignore-type */ $cache)) !== false) {
Loading history...
Bug introduced by
It seems like $cache can also be of type null; however, parameter $filename of file_exists() 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

16
			if (\file_exists(/** @scrutinizer ignore-type */ $cache) && \filemtime($cache) > \time() - $life && ($json = \file_get_contents($cache)) !== false) {
Loading history...
Bug introduced by
It seems like $cache can also be of type null; however, parameter $filename of filemtime() 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

16
			if (\file_exists($cache) && \filemtime(/** @scrutinizer ignore-type */ $cache) > \time() - $life && ($json = \file_get_contents($cache)) !== false) {
Loading history...
17
18
			// fetch from server
19 1
			} elseif (($json = \file_get_contents($source)) === false) {
20
21
				// get stale cache
22
				if ($cache !== null && ($json = \file_get_contents($cache)) !== false) {
23
					self::$versions = false;
24
					return false;
25
				}
26
27
			// update cache
28 1
			} elseif ($cache !== null) {
29
30
				// create directory
31 1
				$dir = \dirname($cache);
32 1
				if (!\is_dir($dir) && \mkdir($dir, 0755)) {
33
34
					// cache file
35 1
					\file_put_contents($cache, $json);
36
				}
37
			}
38
39
			// decode JSON
40 1
			self::$versions = $data = \json_decode($json, true);
41
		}
42 96
		return $data ?? false;
43
	}
44
45 91
	protected static function latest(array $versions, ?\DateTime $now = null) : ?string {
46
47
		// no date restriction
48 91
		if ($now === null) {
49 91
			return \strval(\array_key_first($versions));
50
		} else {
51
			$date = \intval($now->format('Ymd'));
52
			foreach ($versions AS $key => $item) {
53
				if ($date < $item) {
54
					return \strval($key);
55
				}
56
			}
57
		}
58
		return null;
59
	}
60
61 90
	protected static function released(array $data, string $version) : ?string {
62 90
		$major = \intval($version);
63 90
		$len = 0;
64 90
		$i = 0;
65 90
		$vlen = \strlen($version);
66 90
		$released = null;
67 90
		foreach ($data AS $ver => $date) {
68 90
			if (\intval($ver) === $major) {
69 90
				$ver = \strval($ver); // cast as string to get letters, string keys cast to int when array keys
70 90
				$match = 0;
71 90
				for ($n = 0; $n < $vlen; $n++) {
72 90
					if ($version[$n] === ($ver[$n] ?? null)) {
73 90
						$match++;
74
					} else {
75 83
						break;
76
					}
77
				}
78 90
				if ($match > $len) {
79 90
					$len = $match;
80 90
					$released = $date;
81
				}
82
			}
83 90
			$i++;
84
		}
85 90
		return $released !== null ? (new \DateTime(\strval($released)))->format('Y-m-d') : null;
0 ignored issues
show
introduced by
The condition $released !== null is always false.
Loading history...
86
	}
87
88 96
	public static function get(string $browser, string $version, array $config) : array {
89 96
		if (($versions = self::load($config['source'], $config['cache'])) !== false) {
90 96
			$data = [];
91 96
			if (isset($versions[$browser])) {
92
93
				// get latest version of the browser
94 91
				$data['browserlatest'] = self::latest($versions[$browser]);
95
				
96
				// check if version is greater than latest version
97 91
				$major = \intval($version);
98 91
				$latest = \intval($data['browserlatest']);
99 91
				$first = \intval(\array_key_last($versions[$browser]));
100
101
				// version is way out of bounds (This happens sometimes, for example if the safari engine version is reported instead of the browser version)
102 91
				if ($latest + 3 < $major) {
103 25
					return [];
104
105
				// nightly build?
106 91
				} elseif ($latest + 3 === $major) {
107
					$data['browserstatus'] = 'nightly';
108
109
				// canary build
110 91
				} elseif ($latest + 2 === $major) {
111
					$data['browserstatus'] = 'canary';
112
113
				// beta release
114 91
				} elseif ($latest + 1 === $major) {
115
					$data['browserstatus'] = 'beta';
116
117
				// so old we don't have data for it
118 91
				} elseif ($major < $first) {
119 22
					$data['browserstatus'] = 'legacy';
120
121
				// find closes match for version
122
				} else {
123
124
					// get current version
125 90
					$data['browserreleased'] = self::released($versions[$browser], $version);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $data['browserreleased'] is correct as self::released($versions[$browser], $version) targeting hexydec\agentzero\versions::released() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
126
127
					// calculate status
128 90
					if (isset($data['browserreleased'])) {
129 90
						$current = \explode('.', $data['browserlatest'])[0] === \explode('.', $version)[0];
130 90
						$released = new \DateTime($data['browserreleased']);
131
132
						// legacy
133 90
						if ($released < \date_create('-5 years')) {
134 71
							$data['browserstatus'] = 'legacy';
135
136
						// outdated
137 65
						} elseif ($released < \date_create('-2 years')) {
138 55
							$data['browserstatus'] = 'outdated';
139
140
						// current
141 27
						} elseif ($current && ($released >= \date_create('-1 year') || $data['browserlatest'] === $version)) {
142 1
							$data['browserstatus'] = 'current';
143
144
						// previous
145
						} else {
146 26
							$data['browserstatus'] = 'previous';
147
						}
148
					}
149
				}
150
			}
151 96
			return $data;
152
		}
153
		return [];
154
	}
155
}