Test Failed
Push — master ( a842fc...2492ae )
by Jean-Christophe
24:05
created

Router   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Test Coverage

Coverage 94.34%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 53
eloc 91
c 4
b 0
f 0
dl 0
loc 225
ccs 100
cts 106
cp 0.9434
rs 6.96

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getRoute_() 0 11 3
A cleanParam() 0 5 2
A checkRouteName() 0 9 6
A startAll() 0 2 1
A start() 0 2 1
A startRest() 0 2 1
A _getURL() 0 8 2
A getRoute() 0 13 6
A setParamsInOrder() 0 19 6
A getRouteInfoByName() 0 7 3
A getRoutes() 0 2 1
B getRouteUrlParts() 0 26 8
A setExpired() 0 2 1
A path() 0 2 1
B getRouteByName() 0 14 7
A slashPath() 0 8 3
A url() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like Router 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 Router, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Ubiquity\controllers;
4
5
use Ubiquity\cache\CacheManager;
6
use Ubiquity\controllers\traits\RouterAdminTrait;
7
use Ubiquity\controllers\traits\RouterModifierTrait;
8
use Ubiquity\controllers\traits\RouterTestTrait;
9
use Ubiquity\log\Logger;
10
use Ubiquity\utils\http\URequest;
11
12
/**
13
 * Router manager.
14
 * Ubiquity\controllers$Router
15
 * This class is part of Ubiquity
16
 *
17
 * @author jcheron <[email protected]>
18
 * @version 1.0.14
19
 *
20
 */
21
class Router {
22
	use RouterModifierTrait,RouterAdminTrait,RouterTestTrait;
23
	protected static $routes;
24
25 13
	private static function cleanParam(string $param): string {
26 13
		if (\substr ( $param, - 1 ) === '/') {
27
			return \substr ( $param, 0, - 1 );
28
		}
29 13
		return $param;
30
	}
31
32 32
	private static function getRoute_(&$routeDetails, $routePath, $matches, $cachedResponse) {
33 32
		if (! isset ( $routeDetails ['controller'] )) {
34 12
			$method = \strtolower ( $_SERVER ['REQUEST_METHOD'] );
35 12
			if (isset ( $routeDetails [$method] )) {
36 12
				$routeDetailsMethod = $routeDetails [$method];
37 12
				return self::getRouteUrlParts ( [ 'path' => $routePath,'details' => $routeDetailsMethod ], $matches, $routeDetailsMethod ['cache'] ?? false, $routeDetailsMethod ['duration'] ?? null, $cachedResponse );
38
			}
39
		} else {
40 21
			return self::getRouteUrlParts ( [ 'path' => $routePath,'details' => $routeDetails ], $matches, $routeDetails ['cache'] ?? false, $routeDetails ['duration'] ?? null, $cachedResponse );
41
		}
42 11
		return false;
43
	}
44
45 2
	protected static function _getURL($routePath, $params) {
46
		$result = \preg_replace_callback ( '~\((.*?)\)~', function () use (&$params) {
47 2
			return \array_shift ( $params );
48 2
		}, $routePath );
49 2
		if (\count ( $params ) > 0) {
50
			$result = \rtrim ( $result, '/' ) . '/' . \implode ( '/', $params );
51
		}
52 2
		return $result;
53
	}
54
55 5
	protected static function checkRouteName($routeDetails, $name) {
56 5
		if (! isset ( $routeDetails ['name'] )) {
57 4
			foreach ( $routeDetails as $methodRouteDetail ) {
58 4
				if (isset ( $methodRouteDetail ['name'] ) && $methodRouteDetail ['name'] == $name) {
59
					return true;
60
				}
61
			}
62
		}
63 5
		return isset ( $routeDetails ['name'] ) && $routeDetails ['name'] == $name;
64
	}
65
66 16
	protected static function setParamsInOrder(&$routeUrlParts, $paramsOrder, $params) {
67 16
		$index = 0;
68 16
		foreach ( $paramsOrder as $order ) {
69 16
			if ($order === '*') {
70 1
				if (isset ( $params [$index] )) {
71 1
					$routeUrlParts = \array_merge ( $routeUrlParts, \array_diff ( \explode ( '/', $params [$index] ), [ '' ] ) );
72
				}
73 1
				break;
74
			}
75 15
			if (($order [0] ?? '') === '~') {
76 8
				$order = \intval ( \substr ( $order, 1, 1 ) );
77 8
				if (isset ( $params [$order] )) {
78 8
					$routeUrlParts = \array_merge ( $routeUrlParts, \array_diff ( \explode ( '/', $params [$order] ), [ '' ] ) );
79 8
					break;
80
				}
81
			}
82 13
			$routeUrlParts [] = self::cleanParam ( $params [$order] );
83 13
			unset ( $params [$order] );
84 13
			$index ++;
85
		}
86 16
	}
87
88
	/**
89
	 * Starts the router by loading normal routes (not rest)
90
	 */
91 43
	public static function start(): void {
92 43
		self::$routes = CacheManager::getControllerCache ();
93 43
	}
94
95
	/**
96
	 * Starts the router by loading rest routes (not normal routes)
97
	 */
98 5
	public static function startRest(): void {
99 5
		self::$routes = CacheManager::getControllerCache ( true );
100 5
	}
101
102
	/**
103
	 * Starts the router by loading all routes (normal + rest routes)
104
	 */
105 54
	public static function startAll(): void {
106 54
		self::$routes = \array_merge ( CacheManager::getControllerCache (), CacheManager::getControllerCache ( true ) );
107 54
	}
108
109
	/**
110
	 * Returns the route corresponding to a path
111
	 *
112
	 * @param string $path The route path
113
	 * @param boolean $cachedResponse
114
	 * @return boolean|mixed[]|string
115
	 */
116 67
	public static function getRoute($path, $cachedResponse = true, $debug = false) {
117 67
		$path = self::slashPath ( $path );
118 67
		if (isset ( self::$routes [$path] ) && ! $debug) { // No direct access to route in debug mode (for maintenance mode activation)
119 5
			return self::getRoute_ ( self::$routes [$path], $path, [ $path ], $cachedResponse );
120
		}
121 66
		foreach ( self::$routes as $routePath => $routeDetails ) {
122 66
			if (\preg_match ( "@^{$routePath}\$@s", $path, $matches )) {
123 29
				if (($r = self::getRoute_ ( $routeDetails, $routePath, $matches, $cachedResponse )) !== false) {
124 29
					return $r;
125
				}
126
			}
127
		}
128 45
		return false;
129
	}
130
131
	/**
132
	 * Returns the generated path from a route
133
	 *
134
	 * @param string $name name of the route
135
	 * @param array $parameters array of the route parameters. default : []
136
	 * @param boolean $absolute
137
	 */
138 3
	public static function getRouteByName($name, $parameters = [], $absolute = true) {
139 3
		foreach ( self::$routes as $routePath => $routeDetails ) {
140 3
			if (self::checkRouteName ( $routeDetails, $name )) {
141 3
				if (\trim ( $routePath, '/' ) == '_default') {
142 2
					return ($absolute)?'/':'';
143
				}
144 3
				if (\count ( $parameters ) > 0) {
145
					$routePath = self::_getURL ( $routePath, $parameters );
146
				}
147 3
				$routePath = \preg_replace('~\((.*?)\)~', '', $routePath);
148 2
				return ($absolute)?$routePath:\ltrim ( $routePath, '/' );
149
			}
150 2
		}
151
		return false;
152
	}
153
154 3
	public static function getRouteInfoByName($name) {
155
		foreach ( self::$routes as $routeDetails ) {
156
			if (self::checkRouteName ( $routeDetails, $name )) {
157 2
				return $routeDetails;
158 2
			}
159 2
		}
160 2
		return false;
161
	}
162
163 1
	/**
164
	 * Returns the generated path from a route
165
	 *
166
	 * @param string $name The route name
167
	 * @param array $parameters default: []
168
	 * @param boolean $absolute true if the path is absolute (/ at first)
169
	 * @return boolean|string|array|mixed the generated path (/path/to/route)
170
	 */
171
	public static function path($name, $parameters = [], $absolute = false) {
172
		return self::getRouteByName ( $name, $parameters, $absolute );
173
	}
174 1
175 1
	/**
176
	 * Returns the generated url from a route
177
	 *
178
	 * @param string $name the route name
179
	 * @param array $parameters default: []
180
	 * @return string the generated url (http://myApp/path/to/route)
181
	 */
182
	public static function url($name, $parameters = []): string {
183
		return URequest::getUrl ( self::getRouteByName ( $name, $parameters, false ) );
184
	}
185 1
186 1
	public static function getRouteUrlParts($routeArray, $params, $cached = false, $duration = NULL, $cachedResponse = true) {
187
		$realPath = \current ( $params );
188
		\array_shift ( $params );
189 32
		$routeDetails = $routeArray ['details'];
190 32
		if ($routeDetails ['controller'] instanceof \Closure) {
191 32
			$result = [ $routeDetails ['controller'] ];
192 32
			$resultStr = 'callable function';
193 32
		} else {
194 1
			$result = [ \str_replace ( "\\\\", "\\", $routeDetails ['controller'] ),$routeDetails ['action'] ];
195 1
			$resultStr = \implode ( '/', $result );
196
		}
197 31
		if (($paramsOrder = $routeDetails ['parameters']) && (\sizeof ( $paramsOrder ) > 0)) {
198 31
			self::setParamsInOrder ( $result, $paramsOrder, $params );
199
		}
200 32
		if (! $cached || ! $cachedResponse) {
201 16
			Logger::info ( 'Router', \sprintf ( 'Route found for %s : %s', $routeArray ['path'], $resultStr ), 'getRouteUrlParts' );
202
			if (isset ( $routeDetails ['callback'] )) {
203 32
				// Used for maintenance mode
204 32
				if ($routeDetails ['callback'] instanceof \Closure) {
205 32
					return $routeDetails ['callback'] ( $result );
206
				}
207 1
			}
208 1
			return $result;
209
		}
210
		Logger::info ( 'Router', sprintf ( 'Route found for %s (from cache) : %s', $realPath, $resultStr ), 'getRouteUrlParts' );
211 31
		return CacheManager::getRouteCache ( $realPath, $result, $duration );
212
	}
213
214
	/**
215
	 * Adds a slash before and after a path
216
	 *
217
	 * @param string $path The path to modify
218
	 * @return string The path with slashes
219
	 */
220
	public static function slashPath($path): string {
221
		if (\substr ( $path, 0, 1 ) !== '/') {
222
			$path = '/' . $path;
223 70
		}
224 70
		if (\substr ( $path, - 1 ) !== '/') {
225 68
			$path = $path . '/';
226
		}
227 70
		return $path;
228 59
	}
229
230 70
	/**
231
	 * Declare a route as expired
232
	 *
233
	 * @param string $routePath
234
	 */
235
	public static function setExpired($routePath): void {
236
		CacheManager::setExpired ( $routePath );
237
	}
238 1
239 1
	/**
240 1
	 * Returns the array of loaded routes
241
	 *
242
	 * @return array|mixed
243
	 */
244
	public static function getRoutes() {
245
		return self::$routes;
246
	}
247
}
248