Passed
Branch master (f3f2b9)
by Jean-Christophe
17:39
created

Router::getRouteInfoByName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 10
cc 3
nc 3
nop 1
crap 12
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.12
19
 *
20
 */
21
class Router {
22
	use RouterModifierTrait,RouterAdminTrait,RouterTestTrait;
23
	protected static $routes;
24
25 8
	private static function cleanParam(string $param): string {
26 8
		if (\substr ( $param, - 1 ) === '/')
27
			return \substr ( $param, 0, - 1 );
28 8
		return $param;
29
	}
30
31 19
	private static function getRoute_(&$routeDetails, $routePath, $matches, $cachedResponse) {
32 19
		if (! isset ( $routeDetails ['controller'] )) {
33 11
			$method = URequest::getMethod ();
34 11
			if (isset ( $routeDetails [$method] )) {
35 11
				$routeDetailsMethod = $routeDetails [$method];
36 11
				return self::getRouteUrlParts ( [ 'path' => $routePath,'details' => $routeDetailsMethod ], $matches, $routeDetailsMethod ['cache'] ?? false, $routeDetailsMethod ['duration'] ?? null, $cachedResponse );
37
			}
38
		} else {
39 9
			return self::getRouteUrlParts ( [ 'path' => $routePath,'details' => $routeDetails ], $matches, $routeDetails ['cache'] ?? false, $routeDetails ['duration'] ?? null, $cachedResponse );
40
		}
41 10
		return false;
42
	}
43
44
	protected static function _getURL($routePath, $params) {
45
		$result = \preg_replace_callback ( '~\((.*?)\)~', function () use (&$params) {
46
			return \array_shift ( $params );
47
		}, $routePath );
48
		if (\sizeof ( $params ) > 0) {
49
			$result = \rtrim ( $result, '/' ) . '/' . \implode ( '/', $params );
50
		}
51
		return $result;
52
	}
53
54 3
	protected static function checkRouteName($routeDetails, $name) {
55 3
		if (! isset ( $routeDetails ['name'] )) {
56 2
			foreach ( $routeDetails as $methodRouteDetail ) {
57 2
				if (isset ( $methodRouteDetail ['name'] ) && $methodRouteDetail ['name'] == $name)
58
					return true;
59
			}
60
		}
61 3
		return isset ( $routeDetails ['name'] ) && $routeDetails ['name'] == $name;
62
	}
63
64 8
	protected static function setParamsInOrder(&$routeUrlParts, $paramsOrder, $params) {
65 8
		$index = 0;
66 8
		foreach ( $paramsOrder as $order ) {
67 8
			if ($order === '*') {
68
				if (isset ( $params [$index] ))
69
					$routeUrlParts = \array_merge ( $routeUrlParts, \array_diff ( \explode ( '/', $params [$index] ), [ '' ] ) );
70
				break;
71
			}
72 8
			if (($order [0] ?? '') === '~') {
73 3
				$order = \intval ( \substr ( $order, 1, 1 ) );
74 3
				if (isset ( $params [$order] )) {
75 3
					$routeUrlParts = \array_merge ( $routeUrlParts, \array_diff ( \explode ( '/', $params [$order] ), [ '' ] ) );
76 3
					break;
77
				}
78
			}
79 8
			$routeUrlParts [] = self::cleanParam ( $params [$order] );
80 8
			unset ( $params [$order] );
81 8
			$index ++;
82
		}
83 8
	}
84
85
	/**
86
	 * Starts the router by loading normal routes (not rest)
87
	 */
88 18
	public static function start(): void {
89 18
		self::$routes = CacheManager::getControllerCache ();
90 18
	}
91
92
	/**
93
	 * Starts the router by loading rest routes (not normal routes)
94
	 */
95 2
	public static function startRest(): void {
96 2
		self::$routes = CacheManager::getControllerCache ( true );
97 2
	}
98
99
	/**
100
	 * Starts the router by loading all routes (normal + rest routes)
101
	 */
102 36
	public static function startAll(): void {
103 36
		self::$routes = \array_merge ( CacheManager::getControllerCache (), CacheManager::getControllerCache ( true ) );
104 36
	}
105
106
	/**
107
	 * Returns the route corresponding to a path
108
	 *
109
	 * @param string $path The route path
110
	 * @param boolean $cachedResponse
111
	 * @return boolean|mixed[]|string
112
	 */
113 46
	public static function getRoute($path, $cachedResponse = true, $debug = false) {
114 46
		$path = self::slashPath ( $path );
115 46
		if (isset ( self::$routes [$path] ) && ! $debug) { // No direct access to route in debug mode (for maintenance mode activation)
116
			return self::getRoute_ ( self::$routes [$path], $path, [ $path ], $cachedResponse );
117
		}
118 46
		foreach ( self::$routes as $routePath => $routeDetails ) {
119 46
			if (\preg_match ( "@^{$routePath}\$@s", $path, $matches )) {
120 19
				if (($r = self::getRoute_ ( $routeDetails, $routePath, $matches, $cachedResponse )) !== false) {
121 19
					return $r;
122
				}
123
			}
124
		}
125 34
		Logger::warn ( 'Router', "No route found for {$path}", 'getRoute' );
126 34
		return false;
127
	}
128
129
	/**
130
	 * Returns the generated path from a route
131
	 *
132
	 * @param string $name name of the route
133
	 * @param array $parameters array of the route parameters. default : []
134
	 * @param boolean $absolute
135
	 */
136 3
	public static function getRouteByName($name, $parameters = [ ], $absolute = true) {
137 3
		foreach ( self::$routes as $routePath => $routeDetails ) {
138 3
			if (self::checkRouteName ( $routeDetails, $name )) {
139 3
				if (\sizeof ( $parameters ) > 0) {
140
					$routePath = self::_getURL ( $routePath, $parameters );
141
				}
142 3
				if (trim ( $routePath, '/' ) == '_default') {
143 3
					$routePath = "/";
144
				}
145 3
				if (! $absolute)
146 3
					return \ltrim ( $routePath, '/' );
147
				else
148
					return $routePath;
149
			}
150
		}
151
		return false;
152
	}
153
154
	public static function getRouteInfoByName($name) {
155
		foreach ( self::$routes as $routeDetails ) {
156
			if (self::checkRouteName ( $routeDetails, $name )) {
157
				return $routeDetails;
158
			}
159
		}
160
		return false;
161
	}
162
163
	/**
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 3
	public static function path($name, $parameters = [ ], $absolute = false) {
172 3
		return self::getRouteByName ( $name, $parameters, $absolute );
173
	}
174
175
	/**
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
186 19
	public static function getRouteUrlParts($routeArray, $params, $cached = false, $duration = NULL, $cachedResponse = true) {
187 19
		$realPath = \current ( $params );
188 19
		\array_shift ( $params );
189 19
		$routeDetails = $routeArray ['details'];
190 19
		if ($routeDetails ['controller'] instanceof \Closure) {
191
			$result = [ $routeDetails ['controller'] ];
192
			$resultStr = 'callable function';
193
		} else {
194 19
			$result = [ \str_replace ( "\\\\", "\\", $routeDetails ['controller'] ),$routeDetails ['action'] ];
195 19
			$resultStr = \implode ( '/', $result );
196
		}
197 19
		if (($paramsOrder = $routeDetails ['parameters']) && (\sizeof ( $paramsOrder ) > 0)) {
198 8
			self::setParamsInOrder ( $result, $paramsOrder, $params );
199
		}
200 19
		if (! $cached || ! $cachedResponse) {
201 19
			Logger::info ( 'Router', \sprintf ( 'Route found for %s : %s', $routeArray ['path'], $resultStr ), 'getRouteUrlParts' );
202 19
			if (isset ( $routeDetails ['callback'] )) {
203
				// Used for maintenance mode
204 1
				if ($routeDetails ['callback'] instanceof \Closure) {
205 1
					return $routeDetails ['callback'] ( $result );
206
				}
207
			}
208 18
			return $result;
209
		}
210
		Logger::info ( 'Router', sprintf ( 'Route found for %s (from cache) : %s', $realPath, $resultStr ), 'getRouteUrlParts' );
211
		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 46
	public static function slashPath($path): string {
221 46
		if (\substr ( $path, 0, 1 ) !== '/') {
222 46
			$path = '/' . $path;
223
		}
224 46
		if (\substr ( $path, - 1 ) !== '/') {
225 38
			$path = $path . '/';
226
		}
227 46
		return $path;
228
	}
229
230
	/**
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
239
	/**
240
	 * Returns the array of loaded routes
241
	 *
242
	 * @return array|mixed
243
	 */
244 46
	public static function getRoutes() {
245 46
		return self::$routes;
246
	}
247
}
248