Passed
Push — master ( c4282d...8835f1 )
by Jean-Christophe
10:25
created

Router   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Test Coverage

Coverage 80.2%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 48
eloc 88
c 1
b 0
f 0
dl 0
loc 210
ccs 81
cts 101
cp 0.802
rs 8.5599

16 Methods

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

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