Completed
Branch master (9dcfc4)
by Daniel
24:32
created

EnvironmentCheckSuite::run()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
nop 0
1
<?php
2
3
namespace SilverStripe\EnvironmentCheck;
4
5
use Exception;
6
use InvalidArgumentException;
7
use SilverStripe\Core\Config\Configurable;
8
use SilverStripe\Core\Extensible;
9
use SilverStripe\Core\Injector\Injectable;
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
12
use SilverStripe\ORM\ArrayList;
13
use SilverStripe\View\ArrayData;
14
use SilverStripe\View\ViewableData;
15
16
/**
17
 * Represents a suite of environment checks.
18
 * Specific checks can be registered against a named instance of EnvironmentCheckSuite.
19
 *
20
 * Usage #1 - _config.php
21
 * EnvironmentCheckSuite::register('health', 'MyHealthCheck("my param")', 'Title of my health check');
22
 *
23
 * Usage #2 - config.yml
24
 * EnvironmentCheckSuite:
25
 *   registered_checks:
26
 *     mycheck:
27
 *       definition: 'MyHealthCheck("my param")'
28
 *       title: 'Title of my health check'
29
 *   registered_suites:
30
 *     health:
31
 *       - mycheck
32
 *
33
 * $result = EnvironmentCheckSuite::inst('health')->run();
34
 *
35
 * @package environmentcheck
36
 */
37
class EnvironmentCheckSuite
38
{
39
    use Configurable;
40
    use Injectable;
41
    use Extensible;
42
    /**
43
     * Name of this suite.
44
     *
45
     * @var string
46
     */
47
    protected $name;
48
49
    /**
50
     * @var array
51
     */
52
    protected $checks = [];
53
54
    /**
55
     * Associative array of named checks registered via the config system. Each check should specify:
56
     * - definition (e.g. 'MyHealthCheck("my param")')
57
     * - title (e.g. 'Is my feature working?')
58
     * - state (setting this to 'disabled' will cause suites to skip this check entirely.
59
     *
60
     * @var array
61
     */
62
    private static $registered_checks = [];
0 ignored issues
show
Unused Code introduced by
The property $registered_checks is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
63
64
    /**
65
     * Associative array of named suites registered via the config system. Each suite should enumerate
66
     * named checks that have been configured in 'registered_checks'.
67
     *
68
     * @var array
69
     */
70
    private static $registered_suites = [];
0 ignored issues
show
Unused Code introduced by
The property $registered_suites is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
71
72
    /**
73
     * Load checks for this suite from the configuration system. This is an alternative to the
74
     * EnvironmentCheckSuite::register - both can be used, checks will be appended to the suite.
75
     *
76
     * @param string $suiteName The name of this suite.
77
     */
78
    public function __construct($suiteName)
79
    {
80
        $this->constructExtensions();
81
        if (empty($this->config()->registered_suites[$suiteName])) {
82
            // Not registered via config system, but it still may be configured later via self::register.
83
            return;
84
        }
85
86
        foreach ($this->config()->registered_suites[$suiteName] as $checkName) {
87
            if (empty($this->config()->registered_checks[$checkName])) {
88
                throw new InvalidArgumentException(
89
                    "Bad EnvironmentCheck: '$checkName' - the named check has not been registered."
90
                );
91
            }
92
93
            $check = $this->config()->registered_checks[$checkName];
94
95
            // Existing named checks can be disabled by setting their 'state' to 'disabled'.
96
            // This is handy for disabling checks mandated by modules.
97
            if (!empty($check['state']) && $check['state'] === 'disabled') {
98
                continue;
99
            }
100
101
            // Add the check to this suite.
102
            $this->push($check['definition'], $check['title']);
103
        }
104
    }
105
106
    /**
107
     * Run this test suite and return the result code of the worst result.
108
     *
109
     * @return int
110
     */
111
    public function run()
112
    {
113
        $result = new EnvironmentCheckSuiteResult();
114
115
        foreach ($this->checkInstances() as $check) {
116
            list($checkClass, $checkTitle) = $check;
117
            try {
118
                list($status, $message) = $checkClass->check();
119
            // If the check fails, register that as an error
120
            } catch (Exception $e) {
121
                $status = EnvironmentCheck::ERROR;
122
                $message = $e->getMessage();
123
            }
124
            $result->addResult($status, $message, $checkTitle);
125
        }
126
127
        return $result;
128
    }
129
130
    /**
131
     * Get instances of all the environment checks.
132
     *
133
     * @return array
134
     * @throws InvalidArgumentException
135
     */
136
    protected function checkInstances()
137
    {
138
        $output = [];
139
        foreach ($this->checks as $check) {
140
            list($checkClass, $checkTitle) = $check;
141
            if (is_string($checkClass)) {
142
                $checkInst = Injector::inst()->create($checkClass);
143
                if ($checkInst instanceof EnvironmentCheck) {
144
                    $output[] = [$checkInst, $checkTitle];
145
                } else {
146
                    throw new InvalidArgumentException(
147
                        "Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck"
148
                    );
149
                }
150
            } elseif ($checkClass instanceof EnvironmentCheck) {
151
                $output[] = [$checkClass, $checkTitle];
152
            } else {
153
                throw new InvalidArgumentException("Bad EnvironmentCheck: " . var_export($check, true));
154
            }
155
        }
156
        return $output;
157
    }
158
159
    /**
160
     * Add a check to this suite.
161
     *
162
     * @param mixed $check
163
     * @param string $title
164
     */
165
    public function push($check, $title = null)
166
    {
167
        if (!$title) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $title of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
168
            $title = is_string($check) ? $check : get_class($check);
169
        }
170
        $this->checks[] = [$check, $title];
171
    }
172
173
    /////////////////////////////////////////////////////////////////////////////////////////////
174
175
    /**
176
     * @var array
177
     */
178
    protected static $instances = [];
179
180
    /**
181
     * Return a named instance of EnvironmentCheckSuite.
182
     *
183
     * @param string $name
184
     *
185
     * @return EnvironmentCheckSuite
186
     */
187
    public static function inst($name)
188
    {
189
        if (!isset(self::$instances[$name])) {
190
            self::$instances[$name] = new EnvironmentCheckSuite($name);
191
        }
192
        return self::$instances[$name];
193
    }
194
195
    /**
196
     * Register a check against the named check suite.
197
     *
198
     * @param string|array $names
199
     * @param EnvironmentCheck $check
200
     * @param string|array
201
     */
202
    public static function register($names, $check, $title = null)
203
    {
204
        if (!is_array($names)) {
205
            $names = [$names];
206
        }
207
208
        foreach ($names as $name) {
209
            self::inst($name)->push($check, $title);
210
        }
211
    }
212
213
    /**
214
     * Unregisters all checks.
215
     */
216
    public static function reset()
217
    {
218
        self::$instances = [];
219
    }
220
}
221