Test Failed
Pull Request — master (#103)
by
unknown
14:56 queued 02:32
created

Router::getRoute()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 7.0671

Importance

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