Completed
Push — master ( e090e4...18d79e )
by Damian
02:26
created

code/EnvironmentCheckSuite.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Represents a suite of environment checks.
5
 * Specific checks can be registered against a named instance of EnvironmentCheckSuite.
6
 *
7
 * Usage #1 - _config.php
8
 * EnvironmentCheckSuite::register('health', 'MyHealthCheck("my param")', 'Title of my health check');
9
 *
10
 * Usage #2 - config.yml
11
 * EnvironmentCheckSuite:
12
 *   registered_checks:
13
 *     mycheck:
14
 *       definition: 'MyHealthCheck("my param")'
15
 *       title: 'Title of my health check'
16
 *   registered_suites:
17
 *     health:
18
 *       - mycheck
19
 *
20
 * $result = EnvironmentCheckSuite::inst('health')->run();
21
 */
22
class EnvironmentCheckSuite extends Object {
23
	/**
24
	 * Name of this suite.
25
	 *
26
	 * @var string
27
	 */
28
	protected $name;
29
30
	/**
31
	 * @var array
32
	 */
33
	protected $checks = array();
34
35
	/**
36
	 * Associative array of named checks registered via the config system. Each check should specify:
37
	 * - definition (e.g. 'MyHealthCheck("my param")')
38
	 * - title (e.g. 'Is my feature working?')
39
	 * - state (setting this to 'disabled' will cause suites to skip this check entirely.
40
	 *
41
	 * @var array
42
	 */
43
	private static $registered_checks = array();
44
45
	/**
46
	 * Associative array of named suites registered via the config system. Each suite should enumerate
47
	 * named checks that have been configured in 'registered_checks'.
48
	 *
49
	 * @var array
50
	 */
51
	private static $registered_suites = array();
52
53
	/**
54
	 * Load checks for this suite from the configuration system. This is an alternative to the
55
	 * EnvironmentCheckSuite::register - both can be used, checks will be appended to the suite.
56
	 *
57
	 * @param string $suiteName The name of this suite.
58
	 */
59
	public function __construct($suiteName) {
60
		parent::__construct();
61
62
		if (empty($this->config()->registered_suites[$suiteName])) {
63
			// Not registered via config system, but it still may be configured later via self::register.
64
			return;
65
		}
66
67
		foreach ($this->config()->registered_suites[$suiteName] as $checkName) {
68
			if (empty($this->config()->registered_checks[$checkName])) {
69
				throw new InvalidArgumentException(
70
					"Bad EnvironmentCheck: '$checkName' - the named check has not been registered."
71
				);
72
			}
73
74
			$check = $this->config()->registered_checks[$checkName];
75
76
			// Existing named checks can be disabled by setting their 'state' to 'disabled'.
77
			// This is handy for disabling checks mandated by modules.
78
			if (!empty($check['state']) && $check['state']==='disabled') continue;
79
			
80
			// Add the check to this suite.
81
			$this->push($check['definition'], $check['title']);
82
		}
83
	}
84
85
	/**
86
	 * Run this test suite and return the result code of the worst result.
87
	 *
88
	 * @return int
89
	 */
90
	public function run() {
91
		$result = new EnvironmentCheckSuiteResult();
92
93
		foreach($this->checkInstances() as $check) {
94
			list($checkClass, $checkTitle) = $check;
95
			try {
96
				list($status, $message) = $checkClass->check();
97
			// If the check fails, register that as an error
98
			} catch(Exception $e) {
99
				$status = EnvironmentCheck::ERROR;
100
				$message = $e->getMessage();
101
			}
102
			$result->addResult($status, $message, $checkTitle);
103
		}
104
105
		return $result;
106
	}
107
108
	/**
109
	 * Get instances of all the environment checks.
110
	 *
111
	 * @return array
112
	 */
113
	protected function checkInstances() {
114
		$output = array();
115
		foreach($this->checks as $check) {
116
			list($checkClass, $checkTitle) = $check;
117
			if(is_string($checkClass)) {
118
				$checkInst = Object::create_from_string($checkClass);
119
				if($checkInst instanceof EnvironmentCheck) {
120
					$output[] = array($checkInst, $checkTitle);
121
				} else {
122
					throw new InvalidArgumentException("Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck");
123
				}
124
			} else if($checkClass instanceof EnvironmentCheck) {
125
				$output[] = array($checkClass, $checkTitle);
126
			} else {
127
				throw new InvalidArgumentException("Bad EnvironmentCheck: " . var_export($check, true));
128
			}
129
		}
130
		return $output;
131
	}
132
133
	/**
134
	 * Add a check to this suite.
135
	 *
136
	 * @param mixed $check
137
	 * @param string $title
138
	 */
139
	public function push($check, $title = null) {
140
		if(!$title) {
141
			$title = is_string($check) ? $check : get_class($check);
142
		}
143
		$this->checks[] = array($check, $title);
144
	}
145
146
	/////////////////////////////////////////////////////////////////////////////////////////////
147
148
	/**
149
	 * @var array
150
	 */
151
	protected static $instances = array();
152
153
	/**
154
	 * Return a named instance of EnvironmentCheckSuite.
155
	 *
156
	 * @param string $name
157
	 *
158
	 * @return EnvironmentCheckSuite
159
	 */
160
	static function inst($name) {
161
		if(!isset(self::$instances[$name])) self::$instances[$name] = new EnvironmentCheckSuite($name);
162
		return self::$instances[$name];
163
	}
164
165
	/**
166
	 * Register a check against the named check suite.
167
	 *
168
	 * @param string|array $names
169
	 * @param EnvironmentCheck $check
170
	 * @param string|array
171
	 */
172
	static function register($names, $check, $title = null) {
173
		if(!is_array($names)) $names = array($names);
174
		foreach($names as $name) self::inst($name)->push($check, $title);
175
	}
176
177
	/**
178
	 * Unregisters all checks.
179
	 */
180
	static function reset() {
181
		self::$instances = array();
182
	}
183
}
184
185
/**
186
 * A single set of results from running an EnvironmentCheckSuite
187
 */
188
class EnvironmentCheckSuiteResult extends ViewableData {
0 ignored issues
show
As per PSR2, the opening brace for this class should be on a new line.
Loading history...
189
	/**
190
	 * @var ArrayList
191
	 */
192
	protected $details;
193
194
	/**
195
	 * @var int
196
	 */
197
	protected $worst = 0;
198
199
	function __construct() {
200
		parent::__construct();
201
		$this->details = new ArrayList();
202
	}
203
204
	/**
205
	 * @param int $status
206
	 * @param string $message
207
	 * @param string $checkIdentifier
208
	 */
209
	function addResult($status, $message, $checkIdentifier) {
210
		$this->details->push(new ArrayData(array(
211
			'Check' => $checkIdentifier,
212
			'Status' => $this->statusText($status),
213
			'StatusCode' => $status,
214
			'Message' => $message,
215
		)));
216
217
		$this->worst = max($this->worst, $status);
218
	}
219
220
	/**
221
	 * Returns true if there are no errors.
222
	 *
223
	 * @return bool
224
	 */
225
	public function ShouldPass() {
226
		return $this->worst <= EnvironmentCheck::WARNING;
227
	}
228
229
	/**
230
	 * Returns overall (i.e. worst) status as a string.
231
	 *
232
	 * @return string
233
	 */
234
	function Status() {
235
		return $this->statusText($this->worst);
236
	}
237
238
	/**
239
	 * Returns detailed status information about each check.
240
	 *
241
	 * @return ArrayList
242
	 */
243
	function Details() {
244
		return $this->details;
245
	}
246
247
	/**
248
	 * Convert the final result status and details to JSON.
249
	 *
250
	 * @return string
251
	 */
252
	function toJSON() {
253
		$result = array(
254
			'Status' => $this->Status(),
255
			'ShouldPass' => $this->ShouldPass(),
256
			'Checks' => array()
257
		);
258
		foreach($this->details as $detail) {
259
			$result['Checks'][] = $detail->toMap();
260
		}
261
		return json_encode($result);
262
	}
263
264
	/**
265
	 * Return a text version of a status code.
266
	 *
267
	 * @return string
268
	 */
269
	protected function statusText($status) {
270
		switch($status) {
271
			case EnvironmentCheck::ERROR: return "ERROR";
272
			case EnvironmentCheck::WARNING: return "WARNING";
273
			case EnvironmentCheck::OK: return "OK";
274
			case 0: return "NO CHECKS";
275
			default: throw new InvalidArgumentException("Bad environment check status '$status'");
276
		}
277
	}
278
}
279