Passed
Push — master ( d0407d...3b1a32 )
by Jean-Christophe
14:53
created

RouterCacheTrait::addRoute()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
dl 0
loc 4
ccs 4
cts 4
cp 1
rs 10
c 1
b 0
f 0
cc 2
nc 1
nop 8
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Ubiquity\cache\traits;
4
5
use Ubiquity\controllers\Startup;
6
use Ubiquity\controllers\Router;
7
use Ubiquity\cache\parser\ControllerParser;
8
use Ubiquity\cache\ClassUtils;
9
use Ubiquity\utils\base\UArray;
10
use Ubiquity\cache\CacheManager;
11
use Ubiquity\controllers\di\DiManager;
12
use Ubiquity\utils\base\UIntrospection;
13
use Ubiquity\controllers\Controller;
14
use Ubiquity\controllers\StartupAsync;
15
use Ubiquity\utils\http\UResponse;
16
17
/**
18
 *
19
 * Ubiquity\cache\traits$RouterCacheTrait
20
 * This class is part of Ubiquity
21
 *
22
 * @author jcheron <[email protected]>
23
 * @version 1.0.9
24
 * @property \Ubiquity\cache\system\AbstractDataCache $cache
25
 *
26
 */
27
trait RouterCacheTrait {
28
29
	abstract protected static function _getFiles(&$config, $type, $silent = false);
30
31
	private static function addControllerCache($classname) {
32
		$parser = new ControllerParser ();
33
		try {
34
			$parser->parse ( $classname );
35
			return $parser->asArray ();
36
		} catch ( \Exception $e ) {
37
			// Nothing to do
38
		}
39
		return [ ];
40
	}
41
42 16
	private static function parseControllerFiles(&$config, $silent = false) {
43 16
		$routes = [ 'rest' => [ ],'default' => [ ] ];
44 16
		$files = self::getControllersFiles ( $config, $silent );
45 16
		foreach ( $files as $file ) {
46 16
			if (is_file ( $file )) {
47 16
				$controller = ClassUtils::getClassFullNameFromFile ( $file );
48 16
				$parser = new ControllerParser ();
49
				try {
50 16
					$parser->parse ( $controller );
51 16
					$ret = $parser->asArray ();
52 16
					$key = ($parser->isRest ()) ? 'rest' : 'default';
53 16
					$routes [$key] = \array_merge ( $routes [$key], $ret );
54
				} catch ( \Exception $e ) {
55
					// Nothing to do
56
				}
57
			}
58
		}
59 16
		self::sortByPriority ( $routes ['default'] );
60 16
		self::sortByPriority ( $routes ['rest'] );
61 16
		return $routes;
62
	}
63
64 16
	protected static function sortByPriority(&$array) {
65
		\uasort ( $array, function ($item1, $item2) {
66 16
			return UArray::getRecursive ( $item2, 'priority', 0 ) <=> UArray::getRecursive ( $item1, 'priority', 0 );
67 16
		} );
68 16
		UArray::removeRecursive ( $array, 'priority' );
69 16
	}
70
71 8
	private static function initRouterCache(&$config, $silent = false) {
72 8
		$routes = self::parseControllerFiles ( $config, $silent );
73 8
		self::$cache->store ( 'controllers/routes.default', $routes ['default'], 'controllers' );
0 ignored issues
show
Bug introduced by
$routes['default'] of type array is incompatible with the type string expected by parameter $code of Ubiquity\cache\system\AbstractDataCache::store(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

73
		self::$cache->store ( 'controllers/routes.default', /** @scrutinizer ignore-type */ $routes ['default'], 'controllers' );
Loading history...
74 8
		self::$cache->store ( 'controllers/routes.rest', $routes ['rest'], 'controllers' );
75 8
		DiManager::init ( $config );
76 8
		if (! $silent) {
77 8
			echo "Router cache reset\n";
78
		}
79 8
	}
80
81 10
	public static function controllerCacheUpdated(&$config) {
82 10
		$result = false;
83 10
		$newRoutes = self::parseControllerFiles ( $config, true );
84 10
		$ctrls = self::getControllerCache ();
85 10
		if ($newRoutes ['default'] != $ctrls) {
86 2
			$result ['default'] = true;
87
		}
88 10
		$ctrls = self::getControllerCache ( true );
89 10
		if ($newRoutes ['rest'] != $ctrls) {
90
			$result ['rest'] = true;
91
		}
92 10
		return $result;
93
	}
94
95
	public static function storeDynamicRoutes($isRest = false) {
96
		$routes = Router::getRoutes ();
97
		$part = ($isRest) ? 'rest' : 'default';
98
		self::$cache->store ( 'controllers/routes.' . $part, $routes, 'controllers' );
0 ignored issues
show
Bug introduced by
It seems like $routes can also be of type array; however, parameter $code of Ubiquity\cache\system\AbstractDataCache::store() 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

98
		self::$cache->store ( 'controllers/routes.' . $part, /** @scrutinizer ignore-type */ $routes, 'controllers' );
Loading history...
99
	}
100
101
	private static function storeRouteResponse($key, $response) {
102
		$cache = [ 'content-type' => UResponse::$headers ['Content-Type'] ?? 'text/html','content' => $response ];
103
		self::$cache->store ( 'controllers/' . $key, $cache, 'controllers' );
0 ignored issues
show
Bug introduced by
$cache of type array<string,mixed|string> is incompatible with the type string expected by parameter $code of Ubiquity\cache\system\AbstractDataCache::store(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
		self::$cache->store ( 'controllers/' . $key, /** @scrutinizer ignore-type */ $cache, 'controllers' );
Loading history...
104
		return $response;
105
	}
106
107
	private static function getRouteKey($routePath) {
108
		if (\is_array ( $routePath )) {
109
			return 'path' . \md5 ( \implode ( '', $routePath ) );
110
		}
111
		return 'path' . \md5 ( Router::slashPath ( $routePath ) );
112
	}
113
114
	/**
115
	 *
116
	 * @param boolean $isRest
117
	 * @return array
118
	 */
119 55
	public static function getControllerCache($isRest = false) {
120 55
		$key = ($isRest) ? 'rest' : 'default';
121 55
		if (self::$cache->exists ( 'controllers/routes.' . $key ))
122 55
			return self::$cache->fetch ( 'controllers/routes.' . $key );
123
		return [ ];
124
	}
125
126
	public static function getRouteCache($routePath, $routeArray, $duration) {
127
		$key = self::getRouteKey ( $routePath );
128
129
		if (self::$cache->exists ( 'controllers/' . $key ) && ! self::expired ( $key, $duration )) {
130
			$response = self::$cache->fetch ( 'controllers/' . $key );
131
			if ($ct = $response ['content-type'] ?? false) {
132
				UResponse::setContentType ( $ct );
133
			}
134
			return $response ['content'] ?? '';
135
		} else {
136
			$response = Startup::runAsString ( $routeArray );
137
			return self::storeRouteResponse ( $key, $response );
138
		}
139
	}
140
141
	protected static function expired($key, $duration) {
142
		return self::$cache->expired ( "controllers/" . $key, $duration ) === true;
143
	}
144
145
	public static function isExpired($routePath, $duration) {
146
		return self::expired ( self::getRouteKey ( $routePath ), $duration );
147
	}
148
149
	public static function setExpired($routePath) {
150
		$key = self::getRouteKey ( $routePath );
151
		if (self::$cache->exists ( 'controllers/' . $key )) {
152
			self::$cache->remove ( 'controllers/' . $key );
153
		}
154
	}
155
156
	public static function setRouteCache($routePath) {
157
		$key = self::getRouteKey ( $routePath );
158
		$response = Startup::runAsString ( $routePath );
159
		return self::storeRouteResponse ( $key, $response );
160
	}
161
162
	public static function addAdminRoutes() {
163
		self::addControllerCache ( 'Ubiquity\controllers\Admin' );
164
	}
165
166 2
	public static function getRoutes() {
167 2
		$result = self::getControllerCache ();
168 2
		return $result;
169
	}
170
171 1
	public static function getControllerRoutes($controllerClass, $isRest = false) {
172 1
		$result = [ ];
173 1
		$ctrlCache = self::getControllerCache ( $isRest );
174 1
		foreach ( $ctrlCache as $path => $routeAttributes ) {
175 1
			if (isset ( $routeAttributes ['controller'] )) {
176 1
				if ($routeAttributes ['controller'] === $controllerClass) {
177 1
					$result [$path] = $routeAttributes;
178
				}
179
			} else {
180 1
				$firstValue = current ( $routeAttributes );
181 1
				if (isset ( $firstValue ) && isset ( $firstValue ['controller'] )) {
182 1
					if ($firstValue ['controller'] === $controllerClass) {
183 1
						$result [$path] = $routeAttributes;
184
					}
185
				}
186
			}
187
		}
188 1
		return $result;
189
	}
190
191 1
	public static function addRoute($path, $controller, $action = 'index', $methods = null, $name = '', $isRest = false, $priority = 0, $callback = null) {
192 1
		$controllerCache = self::getControllerCache ( $isRest );
193 1
		Router::addRouteToRoutes ( $controllerCache, $path, $controller, $action, $methods, $name, false, null, [ ], $priority, $callback );
194 1
		self::$cache->store ( 'controllers/routes.' . ($isRest ? 'rest' : 'default'), $controllerCache, 'controllers' );
195 1
	}
196
197
	public static function addRoutes($pathArray, $controller, $action = 'index', $methods = null, $name = '') {
198
		self::addRoutes_ ( $pathArray, $controller, $action, $methods, $name, false );
199
	}
200
201
	public static function addRestRoutes($pathArray, $controller, $action = 'index', $methods = null, $name = '') {
202
		self::addRoutes_ ( $pathArray, $controller, $action, $methods, $name, true );
203
	}
204
205
	private static function addRoutes_($pathArray, $controller, $action = 'index', $methods = null, $name = '', $isRest = false) {
206
		$controllerCache = self::getControllerCache ( $isRest );
207
		$postfix = 'default';
208
		if ($isRest) {
209
			$postfix = 'rest';
210
		}
211
		Router::addRoutesToRoutes ( $controllerCache, $pathArray, $controller, $action, $methods, $name );
212
		self::$cache->store ( 'controllers/routes.' . $postfix, $controllerCache, 'controllers' );
213
	}
214
215 16
	public static function getControllersFiles(&$config, $silent = false) {
216 16
		return self::_getFiles ( $config, 'controllers', $silent );
217
	}
218
219 10
	public static function getControllers($subClass = "\\Ubiquity\\controllers\\Controller", $backslash = false, $includeSubclass = false, $includeAbstract = false) {
220 10
		$result = [ ];
221 10
		if ($includeSubclass) {
222 1
			$result [] = $subClass;
223
		}
224 10
		$config = Startup::getConfig ();
225 10
		$files = self::getControllersFiles ( $config, true );
226
		try {
227 10
			$restCtrls = CacheManager::getRestCache ();
228
		} catch ( \Exception $e ) {
229
			$restCtrls = [ ];
230
		}
231 10
		foreach ( $files as $file ) {
232 10
			if (\is_file ( $file )) {
233 10
				$controllerClass = ClassUtils::getClassFullNameFromFile ( $file, $backslash );
234 10
				if (\class_exists ( $controllerClass ) && isset ( $restCtrls [$controllerClass] ) === false) {
235 10
					$r = new \ReflectionClass ( $controllerClass );
236 10
					if ($r->isSubclassOf ( $subClass ) && ($includeAbstract || ! $r->isAbstract ())) {
237 10
						$result [] = $controllerClass;
238
					}
239
				}
240
			}
241
		}
242 10
		return $result;
243
	}
244
245
	/**
246
	 * Preloads controllers.
247
	 * To use only with async servers (Swoole, Workerman)
248
	 *
249
	 * @param ?array $controllers
250
	 */
251
	public static function warmUpControllers($controllers = null) {
252
		$controllers = $controllers ?? self::getControllers ();
253
		foreach ( $controllers as $ctrl ) {
254
			$controller = StartupAsync::getControllerInstance ( $ctrl );
255
			$binary = UIntrospection::implementsMethod ( $controller, 'isValid', Controller::class ) ? 1 : 0;
256
			$binary += UIntrospection::implementsMethod ( $controller, 'initialize', Controller::class ) ? 2 : 0;
257
			$binary += UIntrospection::implementsMethod ( $controller, 'finalize', Controller::class ) ? 4 : 0;
258
			$controller->_binaryCalls = $binary;
259
		}
260
	}
261
}
262