Completed
Push — master ( 3845e2...5afe3b )
by Jean-Christophe
02:10
created

Router   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 228
Duplicated Lines 10.96 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 58
lcom 1
cbo 4
dl 25
loc 228
rs 4.5599
c 1
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A slashPath() 0 7 3
A start() 0 3 1
A startRest() 0 3 1
A getRoute() 0 15 5
A getRouteInfoByControllerAction() 9 12 5
A filterRoutes() 0 10 3
A getRouteInfo() 0 12 5
A getAnnotations() 7 11 5
A getRouteByName() 0 13 5
A path() 0 3 1
A url() 0 3 1
A _getURL() 0 9 2
A checkRouteName() 0 9 6
B getRouteUrlParts() 9 30 8
A cleanParam() 0 5 2
A setExpired() 0 3 1
A addRoute() 0 3 1
A addRouteToRoutes() 0 10 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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\utils\http\URequest;
7
use Ubiquity\cache\parser\ControllerParser;
8
use Ubiquity\utils\base\UString;
9
use Ubiquity\log\Logger;
10
11
/**
12
 * Router
13
 *
14
 * @author jc
15
 * @version 1.0.0.2
16
 */
17
class Router {
18
	private static $routes;
19
20
	public static function slashPath($path) {
21
		if (UString::startswith ( $path, "/" ) === false)
22
			$path = "/" . $path;
23
		if (! UString::endswith ( $path, "/" ))
24
			$path = $path . "/";
25
		return $path;
26
	}
27
28
	public static function start() {
29
		self::$routes = CacheManager::getControllerCache ();
30
	}
31
32
	public static function startRest() {
33
		self::$routes = CacheManager::getControllerCache ( true );
34
	}
35
36
	public static function getRoute($path, $cachedResponse = true) {
37
		$path = self::slashPath ( $path );
38
		foreach ( self::$routes as $routePath => $routeDetails ) {
39
			if (preg_match ( "@^" . $routePath . "$@s", $path, $matches )) {
40
				if (! isset ( $routeDetails ["controller"] )) {
41
					$method = URequest::getMethod ();
42
					if (isset ( $routeDetails [$method] ))
43
						return self::getRouteUrlParts ( [ "path" => $routePath,"details" => $routeDetails [$method] ], $matches, $routeDetails [$method] ["cache"], $routeDetails [$method] ["duration"], $cachedResponse );
44
				} else
45
					return self::getRouteUrlParts ( [ "path" => $routePath,"details" => $routeDetails ], $matches, $routeDetails ["cache"], $routeDetails ["duration"], $cachedResponse );
46
			}
47
		}
48
		Logger::warn("Router", "No route found for {$path}","getRoute");
49
		return false;
50
	}
51
52
	public static function getRouteInfoByControllerAction($controller, $action) {
53 View Code Duplication
		foreach ( self::$routes as $routePath => $routeDetails ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
54
			if (! isset ( $routeDetails ["controller"] )) {
55
				$routeDetails = \reset ( $routeDetails );
56
			}
57
			if ($controller === $routeDetails ["controller"] && $action === $routeDetails ["action"]) {
58
				$routeDetails ["path"] = $routePath;
59
				return $routeDetails;
60
			}
61
		}
62
		return false;
63
	}
64
65
	public static function filterRoutes($path) {
66
		$path = self::slashPath ( $path );
67
		$result = [ ];
68
		foreach ( self::$routes as $routePath => $routeDetails ) {
69
			if (preg_match ( "@^" . $routePath . ".*?$@s", $path, $matches )) {
70
				$result [$routePath] = $routeDetails;
71
			}
72
		}
73
		return $result;
74
	}
75
76
	public static function getRouteInfo($path) {
77
		$path = self::slashPath ( $path );
78
		foreach ( self::$routes as $routePath => $routeDetails ) {
79
			if (preg_match ( "@^" . $routePath . "$@s", $path, $matches ) || \stripslashes ( $routePath ) == $path) {
80
				if (! isset ( $routeDetails ["controller"] )) {
81
					return \reset ( $routeDetails );
82
				} else
83
					return $routeDetails;
84
			}
85
		}
86
		return false;
87
	}
88
89
	public static function getAnnotations($controllerName, $actionName) {
90
		$result = [ ];
91 View Code Duplication
		foreach ( self::$routes as $routePath => $routeDetails ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
92
			if (! isset ( $routeDetails ["controller"] )) {
93
				$routeDetails = \reset ( $routeDetails );
94
			}
95
			if ($routeDetails ["controller"] === $controllerName && $routeDetails ["action"] === $actionName)
96
				$result [$routePath] = $routeDetails;
97
		}
98
		return $result;
99
	}
100
101
	/**
102
	 * Returns the generated path from a route
103
	 *
104
	 * @param string $name
105
	 *        	name of the route
106
	 * @param array $parameters
107
	 *        	array of the route parameters. default : []
108
	 * @param boolean $absolute
109
	 */
110
	public static function getRouteByName($name, $parameters = [], $absolute = true) {
111
		foreach ( self::$routes as $routePath => $routeDetails ) {
112
			if (self::checkRouteName ( $routeDetails, $name )) {
113
				if (\sizeof ( $parameters ) > 0)
114
					$routePath = self::_getURL ( $routePath, $parameters );
115
				if (! $absolute)
116
					return \ltrim ( $routePath, '/' );
117
				else
118
					return $routePath;
119
			}
120
		}
121
		return false;
122
	}
123
124
	/**
125
	 * Returns the generated path from a route
126
	 *
127
	 * @param string $name
128
	 *        	the route name
129
	 * @param array $parameters
130
	 *        	default: []
131
	 * @param boolean $absolute
132
	 *        	true if the path is absolute (/ at first)
133
	 * @return boolean|string|array|mixed the generated path (/path/to/route)
134
	 */
135
	public static function path($name, $parameters = [], $absolute = false) {
136
		return self::getRouteByName ( $name, $parameters, $absolute );
137
	}
138
139
	/**
140
	 * Returns the generated url from a route
141
	 *
142
	 * @param string $name
143
	 *        	the route name
144
	 * @param array $parameters
145
	 *        	default: []
146
	 * @return string the generated url (http://myApp/path/to/route)
147
	 */
148
	public static function url($name, $parameters = []) {
149
		return URequest::getUrl ( self::getRouteByName ( $name, $parameters, false ) );
150
	}
151
152
	protected static function _getURL($routePath, $params) {
153
		$result = \preg_replace_callback ( '~\((.*?)\)~', function () use (&$params) {
154
			return array_shift ( $params );
155
		}, $routePath );
156
		if (\sizeof ( $params ) > 0) {
157
			$result = \rtrim ( $result, '/' ) . '/' . \implode ( '/', $params );
158
		}
159
		return $result;
160
	}
161
162
	protected static function checkRouteName($routeDetails, $name) {
163
		if (! isset ( $routeDetails ["name"] )) {
164
			foreach ( $routeDetails as $methodRouteDetail ) {
165
				if (isset ( $methodRouteDetail ["name"] ) && $methodRouteDetail == $name)
166
					return true;
167
			}
168
		}
169
		return isset ( $routeDetails ["name"] ) && $routeDetails ["name"] == $name;
170
	}
171
172
	public static function getRouteUrlParts($routeArray, $params, $cached = false, $duration = NULL, $cachedResponse = true) {
173
		$params = \array_slice ( $params, 1 );
174
		$ctrl = str_replace ( "\\\\", "\\", $routeArray ["details"] ["controller"] );
175
		$result = [ $ctrl,$routeArray ["details"] ["action"] ];
176
		$paramsOrder = $routeArray ["details"] ["parameters"];
177
		$index = 0;
178
		foreach ( $paramsOrder as $order ) {
179 View Code Duplication
			if ($order === "*") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
				if (isset ( $params [$index] ))
181
					$result = \array_merge ( $result, \array_diff ( \explode ( "/", $params [$index] ), [ "" ] ) );
182
				break;
183
			}
184
			if (\substr ( $order, 0, 1 ) === "~") {
185
				$order = \intval ( \substr ( $order, 1, 1 ) );
186 View Code Duplication
				if (isset ( $params [$order] )) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
					$result = \array_merge ( $result, \array_diff ( \explode ( "/", $params [$order] ), [ "" ] ) );
188
					break;
189
				}
190
			}
191
			$result [] = self::cleanParam ( $params [$order] );
192
			unset ( $params [$order] );
193
			$index ++;
194
		}
195
		if ($cached === true && $cachedResponse === true) {
196
			Logger::info("Router", "Route found for {$routeArray["path"]} (from cache) : ".implode("/", $result),"getRouteUrlParts");
197
			return CacheManager::getRouteCache ( $result, $duration );
198
		}
199
		Logger::info("Router", "Route found for {$routeArray["path"]} : ".implode("/", $result),"getRouteUrlParts");
200
		return $result;
201
	}
202
203
	private static function cleanParam($param) {
204
		if (UString::endswith ( $param, "/" ))
205
			return \substr ( $param, 0, - 1 );
206
		return $param;
207
	}
208
209
	/**
210
	 * Déclare une route comme étant expirée ou non
211
	 *
212
	 * @param string $routePath
213
	 * @param boolean $expired
214
	 */
215
	public static function setExpired($routePath, $expired = true) {
216
		CacheManager::setExpired ( $routePath, $expired );
217
	}
218
219
	/**
220
	 *
221
	 * @param string $path
222
	 * @param string $controller
223
	 * @param string $action
224
	 * @param array|null $methods
225
	 * @param string $name
226
	 * @param boolean $cache
227
	 * @param int $duration
228
	 * @param array $requirements
229
	 */
230
	public static function addRoute($path, $controller, $action = "index", $methods = null, $name = "", $cache = false, $duration = null, $requirements = []) {
231
		self::addRouteToRoutes ( self::$routes, $path, $controller, $action, $methods, $name, $cache, $duration, $requirements );
232
	}
233
234
	public static function addRouteToRoutes(&$routesArray, $path, $controller, $action = "index", $methods = null, $name = "", $cache = false, $duration = null, $requirements = []) {
235
		$result = [ ];
236
		if (\class_exists ( $controller )) {
237
			$method = new \ReflectionMethod ( $controller, $action );
238
			ControllerParser::parseRouteArray ( $result, $controller, [ "path" => $path,"methods" => $methods,"name" => $name,"cache" => $cache,"duration" => $duration,"requirements" => $requirements ], $method, $action );
239
			foreach ( $result as $k => $v ) {
240
				$routesArray [$k] = $v;
241
			}
242
		}
243
	}
244
}
245