Passed
Push — main ( b74a3d...1ce707 )
by Will
12:35
created

versions   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Test Coverage

Coverage 91.8%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 64
c 1
b 0
f 0
dl 0
loc 133
ccs 56
cts 61
cp 0.918
rs 10
wmc 30

4 Methods

Rating   Name   Duplication   Size   Complexity  
B released() 0 25 7
B load() 0 29 9
C get() 0 61 12
A latest() 0 6 2
1
<?php
2
declare(strict_types = 1);
3
namespace hexydec\agentzero;
4
5
class versions {
6
7
	protected static ?array $versions = null;
8
9 95
	protected static function load(string $source, ?string $cache, int $life = 604800) : array|false {
10
11
		// cache for this session
12 95
		$data = self::$versions;
13 95
		if ($data === null) {
14
15
			// fetch from cache
16 95
			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 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...
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...
17
18
			// fetch from server
19 1
			} elseif (($json = \file_get_contents($source)) === false) {
20
				return false;
21
22
			// update cache
23 1
			} elseif ($cache !== null) {
24
25
				// create directory
26 1
				$dir = \dirname($cache);
27 1
				if (!\is_dir($dir) && \mkdir($dir, 0755)) {
28
29
					// cache file
30 1
					\file_put_contents($cache, $json);
31
				}
32
			}
33
34
			// decode JSON
35 95
			$data = \json_decode($json, true);
36
		}
37 95
		return $data ?? false;
38
	}
39
40 90
	protected static function latest(array $versions, ?\DateTime $now = null) : string {
41
42
		// no date restriction
43 90
		if ($now === null) {
44 90
			return \strval(\array_key_first($versions));
45
		} else {
46
47
		}
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
48
	}
49
50 90
	protected static function released(array $data, string $version) : ?string {
51 90
		$major = \intval($version);
52 90
		$len = 0;
53 90
		$i = 0;
54 90
		$vlen = \strlen($version);
55 90
		$released = null;
56 90
		foreach ($data AS $ver => $date) {
57 90
			if (\intval($ver) === $major) {
58 89
				$ver = \strval($ver); // cast as string to get letters, string keys cast to int when array keys
59 89
				$match = 0;
60 89
				for ($n = 0; $n < $vlen; $n++) {
61 89
					if ($version[$n] === ($ver[$n] ?? null)) {
62 89
						$match++;
63
					} else {
64 82
						break;
65
					}
66
				}
67 89
				if ($match > $len) {
68 89
					$len = $match;
69 89
					$released = $date;
70
				}
71
			}
72 90
			$i++;
73
		}
74 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...
75
	}
76
77 95
	public static function get(string $browser, string $version, array $config) : array {
78 95
		if (($versions = self::load($config['source'], $config['cache'])) !== false) {
79 95
			$data = [];
80 95
			if (isset($versions[$browser])) {
81
82
				// get latest version of the browser
83 90
				$data['browserlatest'] = self::latest($versions[$browser]);
84
				
85
				// check if version is greater than latest version
86 90
				$major = \intval($version);
87 90
				$latest = \intval($data['browserlatest']);
88
89
				// version is way out of bounds (This happens sometimes, for example if the safari engine version is reported instead of the browser version)
90 90
				if ($latest + 3 < $major) {
91 25
					return [];
92
93
				// nightly build?
94 90
				} elseif ($latest + 3 === $major) {
95
					$data['browserstatus'] = 'nightly';
96
97
				// canary build
98 90
				} elseif ($latest + 2 === $major) {
99
					$data['browserstatus'] = 'canary';
100
101
				// beta release
102 90
				} elseif ($latest + 1 === $major) {
103
					$data['browserstatus'] = 'beta';
104
105
				// find closes match for version
106
				} else {
107
108
					// get current version
109 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...
110
111
					// calculate status
112 90
					if (isset($data['browserreleased'])) {
113 89
						$current = \explode('.', $data['browserlatest'])[0] === \explode('.', $version)[0];
114 89
						$released = new \DateTime($data['browserreleased']);
115
116
						// legacy
117 89
						if ($released < \date_create('-3 years')) {
118 77
							$data['browserstatus'] = 'legacy';
119
120
						// current
121 53
						} elseif ($current && ($released >= \date_create('-1 year') || $data['browserlatest'] === $version)) {
122 1
							$data['browserstatus'] = 'current';
123
124
						// previous
125
						} else {
126 89
							$data['browserstatus'] = 'previous';
127
						}
128
129
					// version wasn't listed - ancient
130
					} else {
131 25
						$data['browserstatus'] = 'legacy';
132
					}
133
				}
134
			}
135 95
			return $data;
136
		}
137
		return [];
138
	}
139
}