Startup   F
last analyzed

Complexity

Total Complexity 61

Size/Duplication

Total Lines 338
Duplicated Lines 0 %

Test Coverage

Coverage 82.98%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 61
eloc 139
dl 0
loc 338
ccs 117
cts 141
cp 0.8298
rs 3.52
c 1
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getTemplateEngineInstance() 0 7 2
A getApplicationName() 0 2 1
A injectDependencies() 0 17 6
A run() 0 3 1
A getControllerSimpleName() 0 2 1
A startDefaultTemplateEngine() 0 7 3
A getFrameworkDir() 0 2 1
A parseUrl() 0 5 2
A onError() 0 14 3
A getController() 0 2 1
A runAsString() 0 4 1
A logError() 0 7 3
A startTemplateEngine() 0 10 3
B runAction() 0 44 11
A getViewNameFileExtension() 0 2 1
A getAction() 0 2 1
A runCallable() 0 10 3
A init() 0 9 3
A _getControllerInstance() 0 10 4
A setMainParams() 0 6 3
A forward() 0 15 5
A getApplicationDir() 0 2 1
A getActionParams() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like Startup often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Startup, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Ubiquity\controllers;
4
5
use Ubiquity\controllers\di\DiManager;
6
use Ubiquity\controllers\traits\StartupConfigTrait;
7
use Ubiquity\log\Logger;
8
use Ubiquity\utils\http\USession;
9
use Ubiquity\views\engine\TemplateEngine;
10
11
/**
12
 * Starts the framework.
13
 * This class is part of Ubiquity
14
 *
15
 * @author jcheron <[email protected]>
16
 * @version 1.2.0
17
 *
18
 */
19
class Startup {
20
	use StartupConfigTrait;
21
22
	public static $urlParts;
23
	public static $templateEngine;
24
	protected static $controller;
25
	protected static $action;
26
	protected static $actionParams;
27
28 70
	protected static function parseUrl(&$url): array {
29 70
		if (!$url) {
30 4
			return self::$urlParts = [$url = '_default'];
31
		}
32 69
		return self::$urlParts = \explode('/', \rtrim($url, '/'));
33
	}
34
35 69
	protected static function _getControllerInstance(string $controllerName): ?object {
36 69
		if (\class_exists($controllerName, true)) {
37 68
			$controller = new $controllerName ();
38
			// Dependency injection
39 68
			if (isset (self::$config ['di']) && \is_array(self::$config ['di'])) {
40 68
				self::injectDependencies($controller);
41
			}
42 68
			return $controller;
43
		}
44 17
		return null;
45
	}
46
47 68
	protected static function startTemplateEngine(array &$config): void {
48
		try {
49 68
			$templateEngine = $config ['templateEngine'];
50 68
			$engineOptions = $config ['templateEngineOptions'] ?? ['cache' => false];
51 68
			$engine = new $templateEngine ($engineOptions);
52 68
			if ($engine instanceof TemplateEngine) {
53 68
				self::$templateEngine = $engine;
54
			}
55
		} catch (\Exception $e) {
56
			echo $e->getTraceAsString();
57
		}
58
	}
59
60 2
	protected static function setMainParams($controller, $mainParams) {
61 2
		foreach ($mainParams as $k => $v) {
62 2
			if (\method_exists($controller, $k)) {
63
				$controller->$k($v);
64
			} else {
65 2
				$controller->$k = $v;
66
			}
67
		}
68
	}
69
70
	/**
71
	 * Handles the request
72
	 *
73
	 * @param array $config The loaded config array
74
	 */
75 68
	public static function run(array &$config): void {
76 68
		self::init($config);
77 68
		self::forward($_GET ['c']);
78
	}
79
80
	/**
81
	 * Initialize the app with $config array
82
	 *
83
	 * @param array $config
84
	 */
85 68
	public static function init(array &$config): void {
86 68
		self::$config = $config;
87 68
		if (isset ($config ['templateEngine'])) {
88 68
			self::startTemplateEngine($config);
89
		}
90 68
		if (isset ($config ['sessionName'])) {
91 68
			USession::start($config ['sessionName']);
92
		}
93 68
		self::$ctrlNS = self::getNS();
94
	}
95
96
	/**
97
	 * Forwards to url
98
	 *
99
	 * @param string $url The url to forward to
100
	 * @param boolean $initialize If true, the **initialize** method of the controller is called
101
	 * @param boolean $finalize If true, the **finalize** method of the controller is called
102
	 */
103 69
	public static function forward(string $url, bool $initialize = true, bool $finalize = true): void {
104 69
		$u = self::parseUrl($url);
105 69
		if (\is_array(Router::getRoutes()) && ($ru = Router::getRoute($url, true, self::$config ['debug'] ?? false)) !== false) {
106 34
			if (\is_array($ru)) {
107 34
				if (isset ($ru ['controller'])) {
108 33
					static::runAction($ru, $initialize, $finalize);
109
				} else {
110 34
					self::runCallable($ru);
111
				}
112
			} else {
113 34
				echo $ru; // Displays route response from cache
114
			}
115
		} else {
116 50
			$ru = ['controller' => self::$ctrlNS . $u [0], 'action' => $u [1] ?? 'index', 'params' => \array_slice($u, 2)];
117 50
			static::runAction($ru, $initialize, $finalize);
118
		}
119
	}
120
121
	/**
122
	 * Returns the template engine instance
123
	 *
124
	 * @return TemplateEngine
125
	 */
126 3
	public static function getTemplateEngineInstance(): ?TemplateEngine {
127 3
		$config = self::$config;
128 3
		if (isset ($config ['templateEngine'])) {
129 3
			$templateEngine = $config ['templateEngine'];
130 3
			return new $templateEngine ([]);
131
		}
132
		return null;
133
	}
134
135
	/**
136
	 * Starts the default Template engine (Twig for Webtools).
137
	 *
138
	 * @return TemplateEngine
139
	 */
140 17
	public static function startDefaultTemplateEngine(): TemplateEngine {
141 17
		if (self::$templateEngine === null || !self::$templateEngine instanceof \Ubiquity\views\engine\twig\Twig) {
142
			$config = self::$config;
143
			$config['templateEngine'] = \Ubiquity\views\engine\twig\Twig::class;
144
			self::startTemplateEngine($config);
145
		}
146 17
		return self::$templateEngine;
147
	}
148
149
	/**
150
	 * Runs an action on a controller
151
	 *
152
	 * @param array $u An array containing controller, action and parameters
153
	 * @param boolean $initialize If true, the **initialize** method of the controller is called
154
	 * @param boolean $finalize If true, the **finalize** method of the controller is called
155
	 */
156 69
	public static function runAction(array &$u, bool $initialize = true, bool $finalize = true): void {
157 69
		self::$controller = $ctrl = $u ['controller'];
158 69
		self::$action = $action = $u ['action'] ?? 'index';
159 69
		self::$actionParams = $u['params'] ?? [];
160
161
		try {
162 69
			if (null !== $controller = self::_getControllerInstance($ctrl)) {
163 68
				if ($mainParams = $u['mainParams'] ?? false) {
164 2
					static::setMainParams($controller, $mainParams);
165
				}
166 68
				if (!$controller->isValid($action)) {
167 7
					$controller->onInvalidControl();
168
				} else {
169 68
					if ($initialize) {
170 68
						$controller->initialize();
171
					}
172
					try {
173 68
						$controller->$action (...(self::$actionParams));
174 3
					} catch (\Error $e) {
175 1
						if (!\method_exists($controller, $action)) {
176 1
							static::onError(404, "This action does not exist on the controller " . $ctrl, $controller);
177
						} else {
178
							static::logError($e->getCode(), $e->getMessage());
179
							if (self::$config ['debug']) {
180
								throw $e;
181
							} else {
182
								static::onError(500, $e->getMessage(), $controller);
183
							}
184
						}
185
					}
186 68
					if ($finalize) {
187 68
						$controller->finalize();
188
					}
189
				}
190
			} else {
191 17
				Logger::warn('Startup', "The controller `$ctrl` doesn't exist! <br/>", 'runAction');
192 69
				static::onError(404, "The controller `$ctrl` doesn't exist! <br/>");
193
			}
194 3
		} catch (\Error $eC) {
195
			static::logError($eC->getCode(), $eC->getMessage());
196
			if (self::$config ['debug']) {
197
				throw $eC;
198
			} else {
199
				static::onError(500, $eC->getMessage());
200
			}
201
		}
202
	}
203
204
	/**
205
	 * Runs a callback
206
	 *
207
	 * @param array $u An array containing a callback, and some parameters
208
	 */
209 1
	public static function runCallable(array &$u): void {
210 1
		self::$actionParams = $u['params'] ?? [];
211 1
		if (isset (self::$config ['di'])) {
212 1
			$di = self::$config ['di'];
213 1
			if (\is_array($di)) {
214 1
				self::$actionParams += \array_values($di);
215
			}
216
		}
217 1
		$func = $u ['callback'];
218 1
		$func (...(self::$actionParams));
219
	}
220
221
	/**
222
	 * Injects the dependencies from the **di** config key in a controller
223
	 *
224
	 * @param Controller $controller The controller
225
	 */
226 72
	public static function injectDependencies($controller): void {
227 72
		$di = DiManager::fetch($controller);
228 72
		if ($di !== false) {
229 58
			foreach ($di as $k => $v) {
230 58
				$setter = 'set' . \ucfirst($k);
231 58
				if (\method_exists($controller, $setter)) {
232 8
					$controller->$setter ($v ($controller));
233
				} else {
234 58
					$controller->$k = $v ($controller);
235
				}
236
			}
237
		}
238
239 72
		$di = self::$config ['di'] ?? [];
240 72
		if (isset ($di ['@exec'])) {
241 68
			foreach ($di ['@exec'] as $k => $v) {
242 68
				$controller->$k = $v ($controller);
243
			}
244
		}
245
	}
246
247
	/**
248
	 * Runs an action on a controller and returns a string
249
	 *
250
	 * @param array $u
251
	 * @param boolean $initialize If true, the **initialize** method of the controller is called
252
	 * @param boolean $finalize If true, the **finalize** method of the controller is called
253
	 * @return string
254
	 */
255 1
	public static function runAsString(array &$u, bool $initialize = true, bool $finalize = true): string {
256 1
		\ob_start();
257 1
		self::runAction($u, $initialize, $finalize);
258 1
		return \ob_get_clean();
259
	}
260
261 18
	public static function onError(int $code, ?string $message = null, $controllerInstance = null) {
262 18
		$onError = self::$config ['onError'] ?? (function ($code, $message = null, $controllerInstance = null) {
263
			switch ($code) {
264 18
				case 404 :
265 18
					self::getHttpInstance()->header('HTTP/1.0 404 Not Found', '', true, 404);
266 18
					echo $message ?? "The page you are looking for doesn't exist!";
267 18
					break;
268
269
				case 500 :
270
					echo $message ?? "A server error occurred!";
271
					break;
272
			}
273 18
		});
274 18
		$onError ($code, $message, $controllerInstance);
275
	}
276
277
	public static function logError(int $code, string $message) {
278
		if ($code <= E_ERROR) {
279
			Logger::critical('Startup', $message, 'runAction');
280
		} elseif ($code <= E_WARNING) {
281
			Logger::error('Startup', $message, 'runAction');
282
		} else {
283
			Logger::warn('Startup', $message, 'runAction');
284
		}
285
	}
286
287
	/**
288
	 * Returns the active controller name
289
	 *
290
	 * @return ?string
291
	 */
292 18
	public static function getController(): ?string {
293 18
		return self::$controller;
294
	}
295
296
	/**
297
	 * Returns the class simple name of the active controller
298
	 *
299
	 * @return string
300
	 */
301 6
	public static function getControllerSimpleName(): string {
302 6
		return (new \ReflectionClass (self::$controller))->getShortName();
303
	}
304
305
	/**
306
	 * Returns the extension for view files
307
	 *
308
	 * @return string
309
	 */
310 5
	public static function getViewNameFileExtension(): string {
311 5
		return self::$config ['templateEngineOptions']['fileExt'] ?? 'html';
312
	}
313
314
	/**
315
	 * Returns tha active action
316
	 *
317
	 * @return string
318
	 */
319 29
	public static function getAction(): ?string {
320 29
		return self::$action;
321
	}
322
323
	/**
324
	 * Returns the active parameters
325
	 *
326
	 * @return array
327
	 */
328 7
	public static function getActionParams(): array {
329 7
		return self::$actionParams;
330
	}
331
332
	/**
333
	 * Returns the framework directory
334
	 *
335
	 * @return string
336
	 */
337 71
	public static function getFrameworkDir(): string {
338 71
		return \dirname(__FILE__);
339
	}
340
341
	/**
342
	 * Returns the application directory (app directory)
343
	 *
344
	 * @return string
345
	 */
346 3
	public static function getApplicationDir(): string {
347 3
		return \dirname(\ROOT);
348
	}
349
350
	/**
351
	 * Returns the application name
352
	 *
353
	 * @return string
354
	 */
355 1
	public static function getApplicationName(): string {
356 1
		return \basename(\dirname(\ROOT));
357
	}
358
}
359