Test Failed
Push — develop ( 4e95f0...9cbbdf )
by Paul
08:00
created

Gatekeeper::pluginHeaders()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 13
rs 9.9666
ccs 0
cts 10
cp 0
cc 3
nc 3
nop 1
crap 12
1
<?php
2
3
namespace GeminiLabs\SiteReviews;
4
5
use GeminiLabs\SiteReviews\Defaults\DependencyDefaults;
6
7
class Gatekeeper
8
{
9
    public array $dependencies;
10
    public array $errors;
11
12
    public const ERROR_NOT_ACTIVATED = 'not_activated';
13
    public const ERROR_NOT_INSTALLED = 'not_installed';
14
    public const ERROR_NOT_SUPPORTED = 'not_supported';
15
    public const ERROR_NOT_TESTED = 'not_tested';
16
17
    public function __construct(array $dependencies)
18
    {
19
        $this->errors = [];
20
        $this->parseDependencies($dependencies);
21
    }
22
23
    /**
24
     * Checks if all dependencies meet activation criteria.
25
     *
26
     * @return bool true if all dependencies are satisfied, false otherwise
27
     */
28
    public function allows(): bool
29
    {
30
        foreach ($this->dependencies as $plugin => $data) {
31
            if (!$this->isPluginInstalled($plugin)) {
32
                continue;
33
            }
34
            if (!$this->isPluginVersionTested($plugin)) {
35
                continue;
36
            }
37
            if (!$this->isPluginVersionSupported($plugin)) {
38
                continue;
39
            }
40
            $this->isPluginActivated($plugin);
41
        }
42
        if ($this->hasErrors()) {
43
            set_transient(glsr()->prefix.'gatekeeper', $this->errors, 30);
44
            return false;
45
        }
46
        return true;
47
    }
48
49
    public function hasErrors(): bool
50
    {
51
        return !empty($this->errors);
52
    }
53
54
    public function isPluginActivated(string $plugin): bool
55
    {
56
        $isActive = is_plugin_active($plugin);
57
        return $this->catchError($plugin, $isActive, static::ERROR_NOT_ACTIVATED);
58
    }
59
60
    public function isPluginInstalled(string $plugin): bool
61
    {
62
        $isInstalled = $this->dependencies[$plugin]['is_installed'];
63
        return $this->catchError($plugin, $isInstalled, static::ERROR_NOT_INSTALLED);
64
    }
65
66
    public function isPluginVersionSupported(string $plugin): bool
67
    {
68
        $minimumVersion = $this->dependencies[$plugin]['minimum_version'];
69
        $installedVersion = $this->dependencies[$plugin]['installed_version'];
70
        $isVersionValid = version_compare($installedVersion, $minimumVersion, '>=');
71
        return $this->catchError($plugin, $isVersionValid, static::ERROR_NOT_SUPPORTED);
1 ignored issue
show
Bug introduced by
It seems like $isVersionValid can also be of type integer; however, parameter $isValid of GeminiLabs\SiteReviews\Gatekeeper::catchError() does only seem to accept boolean, 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

71
        return $this->catchError($plugin, /** @scrutinizer ignore-type */ $isVersionValid, static::ERROR_NOT_SUPPORTED);
Loading history...
72
    }
73
74
    public function isPluginVersionTested(string $plugin): bool
75
    {
76
        $untestedVersion = $this->dependencies[$plugin]['untested_version'];
77
        $installedVersion = $this->dependencies[$plugin]['installed_version'];
78
        $isVersionValid = version_compare($installedVersion, $untestedVersion, '<');
79
        return $this->catchError($plugin, $isVersionValid, static::ERROR_NOT_TESTED);
1 ignored issue
show
Bug introduced by
It seems like $isVersionValid can also be of type integer; however, parameter $isValid of GeminiLabs\SiteReviews\Gatekeeper::catchError() does only seem to accept boolean, 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

79
        return $this->catchError($plugin, /** @scrutinizer ignore-type */ $isVersionValid, static::ERROR_NOT_TESTED);
Loading history...
80
    }
81
82
    protected function catchError(string $plugin, bool $isValid, string $errorType): bool
83
    {
84
        if (!$isValid) {
85
            $this->errors[$plugin] = [
86
                'error' => $errorType,
87
                'name' => $this->dependencies[$plugin]['name'],
88
                'plugin_uri' => $this->dependencies[$plugin]['plugin_uri'],
89
                'textdomain' => $this->dependencies[$plugin]['textdomain'],
90
            ];
91
        }
92
        return $isValid;
93
    }
94
95
    protected function parseDependencies(array $dependencies): void
96
    {
97
        $results = [];
98
        foreach ($dependencies as $plugin => $data) {
99
            $data = glsr(DependencyDefaults::class)->restrict($data);
100
            if (count($data) !== count(array_filter($data))) {
101
                continue; // incomplete data
102
            }
103
            $results[$plugin] = wp_parse_args($data, [
104
                'installed_version' => '',
105
                'is_installed' => false,
106
                'textdomain' => '',
107
            ]);
108
            if ($headers = $this->pluginHeaders($plugin)) {
109
                $data = wp_parse_args($headers, $results[$plugin]); // header values take precedence
110
                $data['is_installed'] = true;
111
                $results[$plugin] = $data;
112
            }
113
        }
114
        $this->dependencies = $results;
115
    }
116
117
    protected function pluginHeaders(string $plugin): array
118
    {
119
        if (0 !== validate_file($plugin)) {
120
            return [];
121
        }
122
        if (!file_exists(\WP_PLUGIN_DIR.'/'.$plugin)) {
123
            return [];
124
        }
125
        return get_file_data(\WP_PLUGIN_DIR.'/'.$plugin, [
126
            'installed_version' => 'Version',
127
            'name' => 'Plugin Name',
128
            'plugin_uri' => 'Plugin URI',
129
            'textdomain' => 'Text Domain',
130
        ]);
131
    }
132
}
133