Passed
Branch v1.0.0 (b6b195)
by Alex
03:12
created
src/Exceptions/NotFoundException.php 1 patch
Indentation   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -20,34 +20,34 @@
 block discarded – undo
20 20
 class NotFoundException extends \Exception
21 21
 {
22 22
 
23
-    /**
24
-     * The HTTP method from request.
25
-     *
26
-     * @var string
27
-     */
28
-    public $requested_method;
23
+	/**
24
+	 * The HTTP method from request.
25
+	 *
26
+	 * @var string
27
+	 */
28
+	public $requested_method;
29 29
 
30
-    /**
31
-     * The requested URi.
32
-     *
33
-     * @var string
34
-     */
35
-    public $requested_uri;
30
+	/**
31
+	 * The requested URi.
32
+	 *
33
+	 * @var string
34
+	 */
35
+	public $requested_uri;
36 36
     
37
-    /**
38
-     * Exception constructor.
39
-     *
40
-     * @param string  $requested_method The request HTTP method.
41
-     * @param string  $requested_uri    The request URi.
42
-     * @param string  $message          The exception error message.
43
-     * @param integer $code             The exception error code.
44
-     */
45
-    public function __construct($requested_method, $requested_uri, $message = null, $code = 405)
46
-    {
47
-        $this->requested_method = $requested_method;
48
-        $this->requested_uri    = $requested_uri;
37
+	/**
38
+	 * Exception constructor.
39
+	 *
40
+	 * @param string  $requested_method The request HTTP method.
41
+	 * @param string  $requested_uri    The request URi.
42
+	 * @param string  $message          The exception error message.
43
+	 * @param integer $code             The exception error code.
44
+	 */
45
+	public function __construct($requested_method, $requested_uri, $message = null, $code = 405)
46
+	{
47
+		$this->requested_method = $requested_method;
48
+		$this->requested_uri    = $requested_uri;
49 49
 
50
-        parent::__construct($message, $code);
51
-    }
50
+		parent::__construct($message, $code);
51
+	}
52 52
 	
53 53
 }
Please login to merge, or discard this patch.
src/Exceptions/BadRouteException.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -20,10 +20,10 @@
 block discarded – undo
20 20
 class BadRouteException extends \Exception
21 21
 {
22 22
 
23
-    const UNSUPPORTED_HTTP_METHOD = "";
24
-    const OPTIONAL_SEGMENTS_ON_MIDDLE = "Optional segments can only occur at the end of a route.";
25
-    const UNCLOSED_OPTIONAL_SEGMENTS = "Number of opening [ and closing ] does not match.";
26
-    const EMPTY_OPTIONAL_PARTS = "Empty optional part.";
27
-    const BAD_DISPATCH_STRATEGY = "The route specific dispatch strategy is wrong. Check the class name.";
23
+	const UNSUPPORTED_HTTP_METHOD = "";
24
+	const OPTIONAL_SEGMENTS_ON_MIDDLE = "Optional segments can only occur at the end of a route.";
25
+	const UNCLOSED_OPTIONAL_SEGMENTS = "Number of opening [ and closing ] does not match.";
26
+	const EMPTY_OPTIONAL_PARTS = "Empty optional part.";
27
+	const BAD_DISPATCH_STRATEGY = "The route specific dispatch strategy is wrong. Check the class name.";
28 28
 
29 29
 }
Please login to merge, or discard this patch.
src/Exceptions/MethodNotAllowedException.php 1 patch
Indentation   +55 added lines, -55 removed lines patch added patch discarded remove patch
@@ -20,66 +20,66 @@
 block discarded – undo
20 20
 class MethodNotAllowedException extends \Exception
21 21
 {
22 22
 
23
-    /**
24
-     * The HTTP method from request.
25
-     *
26
-     * @var string
27
-     */
28
-    public $requested_method;
23
+	/**
24
+	 * The HTTP method from request.
25
+	 *
26
+	 * @var string
27
+	 */
28
+	public $requested_method;
29 29
 
30
-    /**
31
-     * The requested URi.
32
-     *
33
-     * @var string
34
-     */
35
-    public $requested_uri;
30
+	/**
31
+	 * The requested URi.
32
+	 *
33
+	 * @var string
34
+	 */
35
+	public $requested_uri;
36 36
 
37
-    /**
38
-     * All the allowed HTTP methods and routes for the request.
39
-     *
40
-     * @var array
41
-     */
42
-    public $allowed_methods;
37
+	/**
38
+	 * All the allowed HTTP methods and routes for the request.
39
+	 *
40
+	 * @var array
41
+	 */
42
+	public $allowed_methods;
43 43
 	
44
-    /**
45
-     * Exception constructor.
46
-     *
47
-     * @param string  $requested_method The request HTTP method.
48
-     * @param string  $requested_uri    The request URi.
49
-     * @param array   $allowed_methods  All the allowed HTTP methods and routes for the request.
50
-     * @param string  $message          The exception error message.
51
-     * @param integer $code             The exception error code.
52
-     */
53
-    public function __construct($requested_method, $requested_uri, array $allowed_methods, $message = null, $code = 405)
54
-    {
55
-        $this->requested_method = $requested_method;
56
-        $this->requested_uri    = $requested_uri;
57
-        $this->allowed_methods  = $allowed_methods;
44
+	/**
45
+	 * Exception constructor.
46
+	 *
47
+	 * @param string  $requested_method The request HTTP method.
48
+	 * @param string  $requested_uri    The request URi.
49
+	 * @param array   $allowed_methods  All the allowed HTTP methods and routes for the request.
50
+	 * @param string  $message          The exception error message.
51
+	 * @param integer $code             The exception error code.
52
+	 */
53
+	public function __construct($requested_method, $requested_uri, array $allowed_methods, $message = null, $code = 405)
54
+	{
55
+		$this->requested_method = $requested_method;
56
+		$this->requested_uri    = $requested_uri;
57
+		$this->allowed_methods  = $allowed_methods;
58 58
 
59
-        parent::__construct($message, $code);
60
-    }
59
+		parent::__construct($message, $code);
60
+	}
61 61
 
62
-    /**
63
-     * Verify if the given HTTP method is allowed for the request.
64
-     *
65
-     * @param string An HTTP method
66
-     * @return bool
67
-     */
68
-    public function can($method)
69
-    {
70
-        return isset($this->allowed_methods[strtoupper($method)]);
71
-    }
62
+	/**
63
+	 * Verify if the given HTTP method is allowed for the request.
64
+	 *
65
+	 * @param string An HTTP method
66
+	 * @return bool
67
+	 */
68
+	public function can($method)
69
+	{
70
+		return isset($this->allowed_methods[strtoupper($method)]);
71
+	}
72 72
 
73
-    /**
74
-     * The HTTP specification requires that a 405 Method Not Allowed response include the 
75
-     * Allow: header to detail available methods for the requested resource.
76
-     *
77
-     * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html section 14.7
78
-     * @return string
79
-     */
80
-    public function allowed()
81
-    {
82
-        return implode(', ', array_keys($this->allowed_methods));
83
-    }
73
+	/**
74
+	 * The HTTP specification requires that a 405 Method Not Allowed response include the 
75
+	 * Allow: header to detail available methods for the requested resource.
76
+	 *
77
+	 * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html section 14.7
78
+	 * @return string
79
+	 */
80
+	public function allowed()
81
+	{
82
+		return implode(', ', array_keys($this->allowed_methods));
83
+	}
84 84
 
85 85
 }
Please login to merge, or discard this patch.
src/Dispatcher.php 2 patches
Indentation   +288 added lines, -288 removed lines patch added patch discarded remove patch
@@ -27,294 +27,294 @@
 block discarded – undo
27 27
 class Dispatcher
28 28
 {
29 29
 
30
-    /**
31
-     * The action dispatch strategy object.
32
-     *
33
-     * @var string
34
-     */
35
-
36
-    protected $strategy;
37
-
38
-    /**
39
-     * The route collection.
40
-     *
41
-     * @var Collection
42
-     */
43
-
44
-    protected $collection;
45
-
46
-    /**
47
-     * Define a basepath to all routes.
48
-     *
49
-     * @var string
50
-     */
51
-
52
-    protected $basepath;
53
-
54
-    /**
55
-     * Construct the route dispatcher.
56
-     *
57
-     * @param Collection $collection The collection to save routes.
58
-     * @param string     $basepath   Define a URI prefix that must be excluded on matches.
59
-     * @param string     $strategy   The strategy to dispatch matched route action.
60
-     */
61
-
62
-    public function __construct(Collection $collection, $basepath = '', $strategy = 'Codeburner\Router\Strategies\UriDispatcherStrategy')
63
-    {
64
-        $this->collection = $collection;
65
-        $this->basepath   = (string) $basepath;
66
-        $this->strategy   = $strategy;
67
-    }
68
-
69
-    /**
70
-     * Find and dispatch a route based on the request http method and uri.
71
-     *
72
-     * @param string $method The HTTP method of the request, that should be GET, POST, PUT, PATCH or DELETE.
73
-     * @param string $uri    The URi of request.
74
-     *
75
-     * @throws NotFoundException
76
-     * @throws MethodNotAllowedException
77
-     * @return mixed The request response
78
-     */
79
-
80
-    public function dispatch($method, $uri)
81
-    {
82
-        if ($route = $this->match($method, $uri)) {
83
-            $strategy = $this->getRouteStrategy($route['strategy']);
84
-            return $strategy->dispatch($route['action'], $route['params']);
85
-        }
86
-
87
-        $this->dispatchNotFoundRoute($method, $uri);
88
-    }
89
-
90
-    /**
91
-     * Find a route that matches the given arguments.
92
-     * 
93
-     * @param string $method The HTTP method of the request, that should be GET, POST, PUT, PATCH or DELETE.
94
-     * @param string $uri    The URi of request.
95
-     *
96
-     * @return array|false
97
-     */
98
-
99
-    public function match($method, $uri)
100
-    {
101
-        $method = $this->getHttpMethod($method);
102
-        $uri = $this->getUriPath($uri);
103
-
104
-        if ($route = $this->collection->getStaticRoute($method, $uri)) {
105
-            return $route;
106
-        }
107
-
108
-        return $this->matchDynamicRoute($this->collection->getDynamicRoutes($method, $uri), $uri);
109
-    }
110
-
111
-    /**
112
-     * Verify if the given http method is valid.
113
-     *
114
-     * @param  int|string $method
115
-     * @throws Exception
116
-     * @return int
117
-     */
118
-
119
-    protected function getHttpMethod($method)
120
-    {
121
-        $methods = Mapper::getMethods();
122
-
123
-        if (in_array($method, $methods)) {
124
-            return $method;
125
-        }
126
-
127
-        if (array_key_exists($method = strtolower($method), array_map('strtolower', $methods))) {
128
-            return $methods[$method];
129
-        }
130
-
131
-        throw new Exception('The HTTP method given to the route dispatcher is not supported or is incorrect.');
132
-    }
133
-
134
-    /**
135
-     * Get only the path of a given url or uri.
136
-     *
137
-     * @param string $uri The given URL
138
-     *
139
-     * @throws Exception
140
-     * @return string
141
-     */
142
-
143
-    protected function getUriPath($uri)
144
-    {
145
-        $path = parse_url(substr(strstr(';' . $uri, ';' . $this->basepath), strlen(';' . $this->basepath)), PHP_URL_PATH);
146
-
147
-        if ($path === false) {
148
-            throw new Exception('Seriously malformed URL passed to route dispatcher.');
149
-        }
150
-
151
-        return $path;
152
-    }
153
-
154
-    /**
155
-     * Find and return the request dynamic route based on the compiled data and uri.
156
-     *
157
-     * @param array  $routes All the compiled data from dynamic routes.
158
-     * @param string $uri    The URi of request.
159
-     *
160
-     * @return array|false If the request match an array with the action and parameters will be returned
161
-     *                     otherwise a false will.
162
-     */
163
-
164
-    protected function matchDynamicRoute($routes, $uri)
165
-    {
166
-        foreach ($routes as $route) {
167
-            if (!preg_match($route['regex'], $uri, $matches)) {
168
-                continue;
169
-            }
170
-
171
-            list($routeAction, $routeParams, $strategy) = $route['map'][count($matches)];
172
-
173
-            $params = [];
174
-            $i = 0;
175
-
176
-            foreach ($routeParams as $name) {
177
-                $params[$name] = $matches[++$i];
178
-            }
179
-
180
-            return ['action' => $this->resolveDynamicRouteAction($routeAction, $params), 'params' => $params, 'strategy' => $strategy];
181
-        }
182
-
183
-        return false;
184
-    }
185
-
186
-    /**
187
-     * Generate an HTTP error request with method not allowed or not found.
188
-     *
189
-     * @param string $method The HTTP method that must not be checked.
190
-     * @param string $uri    The URi of request.
191
-     *
192
-     * @throws NotFoundException
193
-     * @throws MethodNotAllowedException
194
-     */
195
-
196
-    protected function dispatchNotFoundRoute($method, $uri)
197
-    {
198
-        $dm = $dm = [];
199
-
200
-        if ($sm = ($this->checkStaticRouteInOtherMethods($method, $uri)) 
201
-                || $dm = ($this->checkDynamicRouteInOtherMethods($method, $uri))) {
202
-            throw new MethodNotAllowedException($method, $uri, array_merge((array) $sm, (array) $dm));
203
-        }
204
-
205
-        throw new NotFoundException($method, $uri);
206
-    }
207
-
208
-    /**
209
-     * Verify if a static route match in another method than the requested.
210
-     *
211
-     * @param string $jump_method The HTTP method that must not be checked
212
-     * @param string $uri         The URi that must be matched.
213
-     *
214
-     * @return array
215
-     */
216
-
217
-    protected function checkStaticRouteInOtherMethods($jump_method, $uri)
218
-    {
219
-        return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function ($method) use ($uri) {
220
-            return (bool) $this->collection->getStaticRoute($method, $uri);
221
-        });
222
-    }
223
-
224
-    /**
225
-     * Verify if a dynamic route match in another method than the requested.
226
-     *
227
-     * @param string $jump_method The HTTP method that must not be checked
228
-     * @param string $uri         The URi that must be matched.
229
-     *
230
-     * @return array
231
-     */
232
-
233
-    protected function checkDynamicRouteInOtherMethods($jump_method, $uri)
234
-    {
235
-        return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function ($method) use ($uri) {
236
-            return (bool) $this->matchDynamicRoute($this->collection->getDynamicRoutes($method, $uri), $uri);
237
-        });
238
-    }
239
-
240
-    /**
241
-     * Resolve dynamic action, inserting route parameters at requested points.
242
-     *
243
-     * @param string|array|\closure $action The route action.
244
-     * @param array                $params The dynamic routes parameters.
245
-     *
246
-     * @return string
247
-     */
248
-
249
-    protected function resolveDynamicRouteAction($action, $params)
250
-    {
251
-        if (is_array($action)) {
252
-            foreach ($action as $key => $value) {
253
-                if (is_string($value)) {
254
-                    $action[$key] = str_replace(['{', '}'], '', str_replace(array_keys($params), array_values($params), $value));
255
-                }
256
-            }
257
-        }
258
-
259
-        return $action;
260
-    }
261
-
262
-    /**
263
-     * @return Collection
264
-     */
265
-
266
-    public function getCollection()
267
-    {
268
-        return $this->collection;
269
-    }
270
-
271
-    /**
272
-     * @return StrategyInterface
273
-     */
274
-
275
-    public function getStrategy()
276
-    {
277
-        return $this->strategy;
278
-    }
279
-
280
-    /**
281
-     * @return string
282
-     */
283
-
284
-    public function getBasePath()
285
-    {
286
-        return $this->basepath;
287
-    }
288
-
289
-    /**
290
-     * Set a new basepath, this will be a prefix that must be excluded in every
291
-     * requested URi.
292
-     *
293
-     * @param string $basepath The new basepath
294
-     */
30
+	/**
31
+	 * The action dispatch strategy object.
32
+	 *
33
+	 * @var string
34
+	 */
35
+
36
+	protected $strategy;
37
+
38
+	/**
39
+	 * The route collection.
40
+	 *
41
+	 * @var Collection
42
+	 */
43
+
44
+	protected $collection;
45
+
46
+	/**
47
+	 * Define a basepath to all routes.
48
+	 *
49
+	 * @var string
50
+	 */
51
+
52
+	protected $basepath;
53
+
54
+	/**
55
+	 * Construct the route dispatcher.
56
+	 *
57
+	 * @param Collection $collection The collection to save routes.
58
+	 * @param string     $basepath   Define a URI prefix that must be excluded on matches.
59
+	 * @param string     $strategy   The strategy to dispatch matched route action.
60
+	 */
61
+
62
+	public function __construct(Collection $collection, $basepath = '', $strategy = 'Codeburner\Router\Strategies\UriDispatcherStrategy')
63
+	{
64
+		$this->collection = $collection;
65
+		$this->basepath   = (string) $basepath;
66
+		$this->strategy   = $strategy;
67
+	}
68
+
69
+	/**
70
+	 * Find and dispatch a route based on the request http method and uri.
71
+	 *
72
+	 * @param string $method The HTTP method of the request, that should be GET, POST, PUT, PATCH or DELETE.
73
+	 * @param string $uri    The URi of request.
74
+	 *
75
+	 * @throws NotFoundException
76
+	 * @throws MethodNotAllowedException
77
+	 * @return mixed The request response
78
+	 */
79
+
80
+	public function dispatch($method, $uri)
81
+	{
82
+		if ($route = $this->match($method, $uri)) {
83
+			$strategy = $this->getRouteStrategy($route['strategy']);
84
+			return $strategy->dispatch($route['action'], $route['params']);
85
+		}
86
+
87
+		$this->dispatchNotFoundRoute($method, $uri);
88
+	}
89
+
90
+	/**
91
+	 * Find a route that matches the given arguments.
92
+	 * 
93
+	 * @param string $method The HTTP method of the request, that should be GET, POST, PUT, PATCH or DELETE.
94
+	 * @param string $uri    The URi of request.
95
+	 *
96
+	 * @return array|false
97
+	 */
98
+
99
+	public function match($method, $uri)
100
+	{
101
+		$method = $this->getHttpMethod($method);
102
+		$uri = $this->getUriPath($uri);
103
+
104
+		if ($route = $this->collection->getStaticRoute($method, $uri)) {
105
+			return $route;
106
+		}
107
+
108
+		return $this->matchDynamicRoute($this->collection->getDynamicRoutes($method, $uri), $uri);
109
+	}
110
+
111
+	/**
112
+	 * Verify if the given http method is valid.
113
+	 *
114
+	 * @param  int|string $method
115
+	 * @throws Exception
116
+	 * @return int
117
+	 */
118
+
119
+	protected function getHttpMethod($method)
120
+	{
121
+		$methods = Mapper::getMethods();
122
+
123
+		if (in_array($method, $methods)) {
124
+			return $method;
125
+		}
126
+
127
+		if (array_key_exists($method = strtolower($method), array_map('strtolower', $methods))) {
128
+			return $methods[$method];
129
+		}
130
+
131
+		throw new Exception('The HTTP method given to the route dispatcher is not supported or is incorrect.');
132
+	}
133
+
134
+	/**
135
+	 * Get only the path of a given url or uri.
136
+	 *
137
+	 * @param string $uri The given URL
138
+	 *
139
+	 * @throws Exception
140
+	 * @return string
141
+	 */
142
+
143
+	protected function getUriPath($uri)
144
+	{
145
+		$path = parse_url(substr(strstr(';' . $uri, ';' . $this->basepath), strlen(';' . $this->basepath)), PHP_URL_PATH);
146
+
147
+		if ($path === false) {
148
+			throw new Exception('Seriously malformed URL passed to route dispatcher.');
149
+		}
150
+
151
+		return $path;
152
+	}
153
+
154
+	/**
155
+	 * Find and return the request dynamic route based on the compiled data and uri.
156
+	 *
157
+	 * @param array  $routes All the compiled data from dynamic routes.
158
+	 * @param string $uri    The URi of request.
159
+	 *
160
+	 * @return array|false If the request match an array with the action and parameters will be returned
161
+	 *                     otherwise a false will.
162
+	 */
163
+
164
+	protected function matchDynamicRoute($routes, $uri)
165
+	{
166
+		foreach ($routes as $route) {
167
+			if (!preg_match($route['regex'], $uri, $matches)) {
168
+				continue;
169
+			}
170
+
171
+			list($routeAction, $routeParams, $strategy) = $route['map'][count($matches)];
172
+
173
+			$params = [];
174
+			$i = 0;
175
+
176
+			foreach ($routeParams as $name) {
177
+				$params[$name] = $matches[++$i];
178
+			}
179
+
180
+			return ['action' => $this->resolveDynamicRouteAction($routeAction, $params), 'params' => $params, 'strategy' => $strategy];
181
+		}
182
+
183
+		return false;
184
+	}
185
+
186
+	/**
187
+	 * Generate an HTTP error request with method not allowed or not found.
188
+	 *
189
+	 * @param string $method The HTTP method that must not be checked.
190
+	 * @param string $uri    The URi of request.
191
+	 *
192
+	 * @throws NotFoundException
193
+	 * @throws MethodNotAllowedException
194
+	 */
195
+
196
+	protected function dispatchNotFoundRoute($method, $uri)
197
+	{
198
+		$dm = $dm = [];
199
+
200
+		if ($sm = ($this->checkStaticRouteInOtherMethods($method, $uri)) 
201
+				|| $dm = ($this->checkDynamicRouteInOtherMethods($method, $uri))) {
202
+			throw new MethodNotAllowedException($method, $uri, array_merge((array) $sm, (array) $dm));
203
+		}
204
+
205
+		throw new NotFoundException($method, $uri);
206
+	}
207
+
208
+	/**
209
+	 * Verify if a static route match in another method than the requested.
210
+	 *
211
+	 * @param string $jump_method The HTTP method that must not be checked
212
+	 * @param string $uri         The URi that must be matched.
213
+	 *
214
+	 * @return array
215
+	 */
216
+
217
+	protected function checkStaticRouteInOtherMethods($jump_method, $uri)
218
+	{
219
+		return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function ($method) use ($uri) {
220
+			return (bool) $this->collection->getStaticRoute($method, $uri);
221
+		});
222
+	}
223
+
224
+	/**
225
+	 * Verify if a dynamic route match in another method than the requested.
226
+	 *
227
+	 * @param string $jump_method The HTTP method that must not be checked
228
+	 * @param string $uri         The URi that must be matched.
229
+	 *
230
+	 * @return array
231
+	 */
232
+
233
+	protected function checkDynamicRouteInOtherMethods($jump_method, $uri)
234
+	{
235
+		return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function ($method) use ($uri) {
236
+			return (bool) $this->matchDynamicRoute($this->collection->getDynamicRoutes($method, $uri), $uri);
237
+		});
238
+	}
239
+
240
+	/**
241
+	 * Resolve dynamic action, inserting route parameters at requested points.
242
+	 *
243
+	 * @param string|array|\closure $action The route action.
244
+	 * @param array                $params The dynamic routes parameters.
245
+	 *
246
+	 * @return string
247
+	 */
248
+
249
+	protected function resolveDynamicRouteAction($action, $params)
250
+	{
251
+		if (is_array($action)) {
252
+			foreach ($action as $key => $value) {
253
+				if (is_string($value)) {
254
+					$action[$key] = str_replace(['{', '}'], '', str_replace(array_keys($params), array_values($params), $value));
255
+				}
256
+			}
257
+		}
258
+
259
+		return $action;
260
+	}
261
+
262
+	/**
263
+	 * @return Collection
264
+	 */
265
+
266
+	public function getCollection()
267
+	{
268
+		return $this->collection;
269
+	}
270
+
271
+	/**
272
+	 * @return StrategyInterface
273
+	 */
274
+
275
+	public function getStrategy()
276
+	{
277
+		return $this->strategy;
278
+	}
279
+
280
+	/**
281
+	 * @return string
282
+	 */
283
+
284
+	public function getBasePath()
285
+	{
286
+		return $this->basepath;
287
+	}
288
+
289
+	/**
290
+	 * Set a new basepath, this will be a prefix that must be excluded in every
291
+	 * requested URi.
292
+	 *
293
+	 * @param string $basepath The new basepath
294
+	 */
295 295
     
296
-    public function setBasePath($basepath)
297
-    {
298
-        $this->basepath = $basepath;
299
-    }
300
-
301
-    /**
302
-     * @param string $strategy
303
-     * @throws BadRouteException
304
-     * @return \Codeburner\Router\Strategies\DispatcherStrategyInterface
305
-     */
306
-
307
-    private function getRouteStrategy($strategy)
308
-    {
309
-        if ($strategy === null) {
310
-            return new $this->strategy;
311
-        }
312
-
313
-        if (class_exists($strategy)) {
314
-            return new $strategy;
315
-        }
316
-
317
-        throw new BadRouteException(BadRouteException::BAD_DISPATCH_STRATEGY);
318
-    }
296
+	public function setBasePath($basepath)
297
+	{
298
+		$this->basepath = $basepath;
299
+	}
300
+
301
+	/**
302
+	 * @param string $strategy
303
+	 * @throws BadRouteException
304
+	 * @return \Codeburner\Router\Strategies\DispatcherStrategyInterface
305
+	 */
306
+
307
+	private function getRouteStrategy($strategy)
308
+	{
309
+		if ($strategy === null) {
310
+			return new $this->strategy;
311
+		}
312
+
313
+		if (class_exists($strategy)) {
314
+			return new $strategy;
315
+		}
316
+
317
+		throw new BadRouteException(BadRouteException::BAD_DISPATCH_STRATEGY);
318
+	}
319 319
 
320 320
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 
217 217
     protected function checkStaticRouteInOtherMethods($jump_method, $uri)
218 218
     {
219
-        return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function ($method) use ($uri) {
219
+        return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function($method) use ($uri) {
220 220
             return (bool) $this->collection->getStaticRoute($method, $uri);
221 221
         });
222 222
     }
@@ -232,7 +232,7 @@  discard block
 block discarded – undo
232 232
 
233 233
     protected function checkDynamicRouteInOtherMethods($jump_method, $uri)
234 234
     {
235
-        return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function ($method) use ($uri) {
235
+        return array_filter(array_diff_key(Mapper::getMethods(), [$jump_method => true]), function($method) use ($uri) {
236 236
             return (bool) $this->matchDynamicRoute($this->collection->getDynamicRoutes($method, $uri), $uri);
237 237
         });
238 238
     }
Please login to merge, or discard this patch.
src/Mapper.php 2 patches
Indentation   +730 added lines, -730 removed lines patch added patch discarded remove patch
@@ -21,409 +21,409 @@  discard block
 block discarded – undo
21 21
 class Mapper
22 22
 {
23 23
 
24
-    /**
25
-     * Implement support to variations of the set method that abstract the
26
-     * HTTP method from the parameters.
27
-     */
24
+	/**
25
+	 * Implement support to variations of the set method that abstract the
26
+	 * HTTP method from the parameters.
27
+	 */
28 28
 
29
-    use HttpMethodMapper;
29
+	use HttpMethodMapper;
30 30
 
31
-    /**
32
-     * Insert support for mapping a resource.
33
-     *
34
-     * @see https://github.com/codeburnerframework/router/#resources
35
-     */
31
+	/**
32
+	 * Insert support for mapping a resource.
33
+	 *
34
+	 * @see https://github.com/codeburnerframework/router/#resources
35
+	 */
36 36
 
37
-    use ResourceMapper;
37
+	use ResourceMapper;
38 38
 
39
-    /**
40
-     * Add support to abstract a entire controller registration.
41
-     *
42
-     * @see https://github.com/codeburnerframework/router/#controllers
43
-     */
39
+	/**
40
+	 * Add support to abstract a entire controller registration.
41
+	 *
42
+	 * @see https://github.com/codeburnerframework/router/#controllers
43
+	 */
44 44
 
45
-    use ControllerMapper;
45
+	use ControllerMapper;
46 46
 
47
-    /**
48
-     * The regex used to parse all the routes patterns. For more information
49
-     * contact the author of this class.
50
-     *
51
-     * @var string
52
-     */
47
+	/**
48
+	 * The regex used to parse all the routes patterns. For more information
49
+	 * contact the author of this class.
50
+	 *
51
+	 * @var string
52
+	 */
53 53
 
54
-    const DYNAMIC_REGEX = '\{\s*([\w]*)\s*(?::\s*([^{}]*(?:\{(?-1)\}[^{}]*)*))?\s*\}';
54
+	const DYNAMIC_REGEX = '\{\s*([\w]*)\s*(?::\s*([^{}]*(?:\{(?-1)\}[^{}]*)*))?\s*\}';
55 55
     
56
-    /**
57
-     * The default pattern that will be used to match a dynamic segment of a route.
58
-     *
59
-     * @var string
60
-     */
61
-
62
-    const DEFAULT_PLACEHOLDER_REGEX = '([^/]+)';
63
-
64
-    /**
65
-     * All the supported http methods and they zones. An http method zone is the range
66
-     * of numeric indexes that routes separated by the number of slashes can be registered.
67
-     * By default the range begins on 10 and jumps 10 in every method, this give a zone
68
-     * of infinite routes ate 9 slashes or if you prefer, segments.
69
-     */
70
-
71
-    const METHOD_GET    = 100;
72
-    const METHOD_POST   = 200;
73
-    const METHOD_PUT    = 300;
74
-    const METHOD_PATCH  = 400;
75
-    const METHOD_DELETE = 500;
76
-
77
-    /**
78
-     * An mirror for the constants values in array form for easily iteration and validation.
79
-     * This will be deprecated soon, with the new support to array in constants of php 7 this static attribute and
80
-     * the static getter method will be refactored to a constant.
81
-     *
82
-     * @var array
83
-     */
84
-
85
-    protected static $methods = [
86
-        'get'    => self::METHOD_GET,
87
-        'post'   => self::METHOD_POST,
88
-        'put'    => self::METHOD_PUT,
89
-        'patch'  => self::METHOD_PATCH,
90
-        'delete' => self::METHOD_DELETE
91
-    ];
56
+	/**
57
+	 * The default pattern that will be used to match a dynamic segment of a route.
58
+	 *
59
+	 * @var string
60
+	 */
61
+
62
+	const DEFAULT_PLACEHOLDER_REGEX = '([^/]+)';
63
+
64
+	/**
65
+	 * All the supported http methods and they zones. An http method zone is the range
66
+	 * of numeric indexes that routes separated by the number of slashes can be registered.
67
+	 * By default the range begins on 10 and jumps 10 in every method, this give a zone
68
+	 * of infinite routes ate 9 slashes or if you prefer, segments.
69
+	 */
70
+
71
+	const METHOD_GET    = 100;
72
+	const METHOD_POST   = 200;
73
+	const METHOD_PUT    = 300;
74
+	const METHOD_PATCH  = 400;
75
+	const METHOD_DELETE = 500;
76
+
77
+	/**
78
+	 * An mirror for the constants values in array form for easily iteration and validation.
79
+	 * This will be deprecated soon, with the new support to array in constants of php 7 this static attribute and
80
+	 * the static getter method will be refactored to a constant.
81
+	 *
82
+	 * @var array
83
+	 */
84
+
85
+	protected static $methods = [
86
+		'get'    => self::METHOD_GET,
87
+		'post'   => self::METHOD_POST,
88
+		'put'    => self::METHOD_PUT,
89
+		'patch'  => self::METHOD_PATCH,
90
+		'delete' => self::METHOD_DELETE
91
+	];
92 92
     
93
-    /**
94
-     * A set of aliases to regex that can be used in patterns definitions.
95
-     *
96
-     * @var array
97
-     */
98
-
99
-    protected $patternWildcards = [
100
-        'int' => '\d{length}',
101
-        'integer' => '\d{length}',
102
-        'string' => '\w{length}',
103
-        'float' => '[-+]?(\d*[.])?\d{length}',
104
-        'bool' => '1|0|true|false|yes|no',
105
-        'boolean' => '1|0|true|false|yes|no'
106
-    ];
93
+	/**
94
+	 * A set of aliases to regex that can be used in patterns definitions.
95
+	 *
96
+	 * @var array
97
+	 */
98
+
99
+	protected $patternWildcards = [
100
+		'int' => '\d{length}',
101
+		'integer' => '\d{length}',
102
+		'string' => '\w{length}',
103
+		'float' => '[-+]?(\d*[.])?\d{length}',
104
+		'bool' => '1|0|true|false|yes|no',
105
+		'boolean' => '1|0|true|false|yes|no'
106
+	];
107 107
     
108
-    /**
109
-     * The delimiter in the controller/method action espefication.
110
-     *
111
-     * @var string
112
-     */
108
+	/**
109
+	 * The delimiter in the controller/method action espefication.
110
+	 *
111
+	 * @var string
112
+	 */
113 113
 
114
-    protected $actionDelimiter = '#';
114
+	protected $actionDelimiter = '#';
115 115
 
116
-    /**
117
-     * Hold all the routes without parameters.
118
-     *
119
-     * @var array [METHOD => [PATTERN => ROUTE]]
120
-     */
116
+	/**
117
+	 * Hold all the routes without parameters.
118
+	 *
119
+	 * @var array [METHOD => [PATTERN => ROUTE]]
120
+	 */
121 121
 
122
-    protected $statics;
122
+	protected $statics;
123 123
     
124
-    /**
125
-     * Routes with parameters to compute.
126
-     *
127
-     * @var array [PROCESSED_INDEX => [ROUTE]]
128
-     */
129
-
130
-    protected $dynamics;
131
-
132
-    /**
133
-     * Insert a route into the collection.
134
-     *
135
-     * @param int                   $method   The HTTP method zone of route. {GET, POST, PUT, PATCH, DELETE}
136
-     * @param string                $pattern  The URi that route should match.
137
-     * @param string|array|\closure $action   The callback for when route is matched.
138
-     * @param string                $strategy The route specific dispatch strategy.
139
-     */
140
-
141
-    public function set($method, $pattern, $action, $strategy = null)
142
-    {
143
-        $patterns = $this->parsePatternOptionals($pattern);
144
-        $action = $this->parseAction($action);
145
-
146
-        foreach ($patterns as $pattern) {
147
-            strpos($pattern, '{') === false ?
148
-                $this->setStatic($method, $pattern, $action, $strategy) : $this->setDynamic($method, $pattern, $action, $strategy);
149
-        }
150
-    }
151
-
152
-    /**
153
-     * Insert a static route into the collection.
154
-     *
155
-     * @param string                $method   The HTTP method of route. {GET, POST, PUT, PATCH, DELETE}
156
-     * @param string                $pattern  The URi that route should match.
157
-     * @param string|array|\closure $action   The callback for when route is matched.
158
-     * @param string                $strategy The route specific dispatch strategy.
159
-     */
160
-
161
-    protected function setStatic($method, $pattern, $action, $strategy)
162
-    {
163
-        $this->statics[$method][$pattern] = [
164
-            'action'   => $action,
165
-            'params'   => [],
166
-            'strategy' => $strategy
167
-        ];
168
-    }
169
-
170
-    /**
171
-     * Insert a dynamic route into the collection.
172
-     *
173
-     * @param string                $method   The HTTP method of route. {GET, POST, PUT, PATCH, DELETE}
174
-     * @param string                $pattern  The URi that route should match.
175
-     * @param string|array|\closure $action   The callback for when route is matched.
176
-     * @param string                $strategy The route specific dispatch strategy.
177
-     */
178
-
179
-    protected function setDynamic($method, $pattern, $action, $strategy)
180
-    {
181
-        $index = $this->getDynamicIndex($method, $pattern);
182
-
183
-        list($regex, $params) = $this->parsePatternPlaceholders($pattern);
184
-
185
-        $this->dynamics[$index][] = [
186
-            'action'   => $action,
187
-            'regex'    => $regex,
188
-            'params'   => $params,
189
-            'strategy' => $strategy
190
-        ];
191
-    }
192
-
193
-    /**
194
-     * Parses the given action to something that can be called.
195
-     *
196
-     * @param  string|array|\closure $action  The callback for when route is matched.
197
-     * @return string|array|\closure
198
-     */
199
-
200
-    protected function parseAction($action)
201
-    {
202
-        if (is_string($action)) {
203
-            return explode($this->actionDelimiter, $action);
204
-        }
205
-
206
-        return $action;
207
-    }
208
-
209
-    /**
210
-     * Separate routes pattern with optional parts into n new patterns.
211
-     *
212
-     * @param string $pattern The route pattern to parse.
213
-     * @return array
214
-     */
215
-
216
-    protected function parsePatternOptionals($pattern)
217
-    {
218
-        $patternWithoutClosingOptionals = rtrim($pattern, ']');
219
-        $patternOptionalsNumber = strlen($pattern) - strlen($patternWithoutClosingOptionals);
220
-
221
-        $segments = preg_split('~' . self::DYNAMIC_REGEX . '(*SKIP)(*F) | \[~x', $patternWithoutClosingOptionals);
222
-        $this->parseSegmentOptionals($segments, $patternOptionalsNumber, $patternWithoutClosingOptionals);
223
-
224
-        return $this->buildPatterns($segments);
225
-    }
226
-
227
-    /**
228
-     * Parse an route pattern seeking for parameters and making the route regex.
229
-     *
230
-     * @param string $pattern The route pattern to be parsed.
231
-     * @return array 0 => new route regex, 1 => map of parameters names.
232
-     */
233
-
234
-    protected function parsePatternPlaceholders($pattern)
235
-    {
236
-        $parameters = [];
237
-        preg_match_all('~' . self::DYNAMIC_REGEX . '~x', $pattern, $matches, PREG_SET_ORDER);
238
-
239
-        foreach ((array) $matches as $key => $match) {
240
-            $pattern = str_replace($match[0],
241
-                isset($match[2]) ? $this->getPlaceholderRegex($match[2]) : self::DEFAULT_PLACEHOLDER_REGEX, $pattern);
242
-            $parameters[$key] = $match[1];
243
-        }
244
-
245
-        return [$pattern, $parameters];
246
-    }
247
-
248
-    /**
249
-     * Find and replace wildcards in one pattern placeholder.
250
-     *
251
-     * @param string $placeholder
252
-     * @return string
253
-     */
254
-
255
-    protected function getPlaceholderRegex($placeholder)
256
-    {
257
-        $strippedPlaceholder = strstr($placeholder, '{', true) ?: $placeholder;
258
-
259
-        if (isset($this->patternWildcards[$strippedPlaceholder])) {
260
-            return '(' . str_replace('{length}', strstr($placeholder, '{') ?: '+', $this->patternWildcards[$strippedPlaceholder]) . ')';
261
-        }
262
-
263
-        return '(' . trim($placeholder) . ')';
264
-    }
265
-
266
-    /**
267
-     * Parse the pattern seeking for the error and show a more specific message.
268
-     *
269
-     * @param array $segments
270
-     * @param int $patternOptionalsNumber
271
-     * @param string $patternWithoutClosingOptionals
272
-     *
273
-     * @throws Exceptions\BadRouteException With a more specific error message.
274
-     */
275
-
276
-    protected function parseSegmentOptionals(array $segments, $patternOptionalsNumber, $patternWithoutClosingOptionals)
277
-    {
278
-        if ($patternOptionalsNumber !== count($segments) - 1) {
279
-            if (preg_match('~' . self::DYNAMIC_REGEX . '(*SKIP)(*F) | \]~x', $patternWithoutClosingOptionals)) {
280
-                   throw new Exceptions\BadRouteException(Exceptions\BadRouteException::OPTIONAL_SEGMENTS_ON_MIDDLE);
281
-            } else throw new Exceptions\BadRouteException(Exceptions\BadRouteException::UNCLOSED_OPTIONAL_SEGMENTS);
282
-        }
283
-    }
284
-
285
-    /**
286
-     * Build all the possibles patterns for a set of segments.
287
-     *
288
-     * @param array $segments
289
-     * @throws Exceptions\BadRouteException
290
-     * @return array
291
-     */
292
-
293
-    protected function buildPatterns(array $segments)
294
-    {
295
-        $pattern  = '';
296
-        $patterns = [];
297
-
298
-        foreach ($segments as $n => $segment) {
299
-            if ($segment === '' && $n !== 0) {
300
-                throw new Exceptions\BadRouteException(Exceptions\BadRouteException::EMPTY_OPTIONAL_PARTS);
301
-            }
302
-
303
-            $patterns[] = $pattern .= $segment;
304
-        }
305
-
306
-        return $patterns;
307
-    }
308
-
309
-    /**
310
-     * Group several routes into one unique regex.
311
-     *
312
-     * @param  array $routes All the routes that must be grouped
313
-     * @return array
314
-     */
315
-
316
-    protected function buildGroup($routes)
317
-    {
318
-        $map = []; 
319
-        $regex = [];
320
-        $groupCount = 0;
321
-
322
-        foreach ($routes as $route) {
323
-            $paramsCount      = count($route['params']);
324
-            $groupCount       = max($groupCount, $paramsCount) + 1;
325
-            $regex[]          = $route['regex'] . str_repeat('()', $groupCount - $paramsCount - 1);
326
-            $map[$groupCount] = [$route['action'], $route['params'], $route['strategy']];
327
-        }
328
-
329
-        return ['regex' => '~^(?|' . implode('|', $regex) . ')$~', 'map' => $map];
330
-    }
331
-
332
-    /**
333
-     * Generate an index that will hold an especific group of dynamic routes.
334
-     *
335
-     * @param int $method The http method index defined by the METHOD_* constants
336
-     * @param string $pattern
337
-     *
338
-     * @return int
339
-     */
340
-
341
-    protected function getDynamicIndex($method, $pattern)
342
-    {
343
-        return (int) $method + substr_count($pattern, '/') - 1;
344
-    }
345
-
346
-    /**
347
-     * Retrieve a specific static route or a false.
348
-     *
349
-     * @param int $method The http method index defined by the METHOD_* constants
350
-     * @param string $pattern
351
-     *
352
-     * @return array|false
353
-     */
354
-
355
-    public function getStaticRoute($method, $pattern)
356
-    {
357
-        if (isset($this->statics[$method]) && isset($this->statics[$method][$pattern])) {
358
-            return $this->statics[$method][$pattern];
359
-        }
360
-
361
-        return false;
362
-    }
363
-
364
-    /**
365
-     * Concat all dynamic routes regex for a given method, this speeds up the match.
366
-     *
367
-     * @param string $method The http method to search in.
368
-     * @param string $pattern
369
-     *
370
-     * @return array [['regex', 'map' => [0 => action, 1 => params]]]
371
-     */
372
-
373
-    public function getDynamicRoutes($method, $pattern)
374
-    {
375
-        $index = $this->getDynamicIndex($method, $pattern);
376
-
377
-        if (!isset($this->dynamics[$index])) {
378
-            return [];
379
-        }
380
-
381
-        $dynamics = $this->dynamics[$index];
382
-        return array_map([$this, 'buildGroup'], array_chunk($dynamics, round(1 + 3.3 * log(count($dynamics))), true));
383
-    }
384
-
385
-    /**
386
-     * @return array
387
-     */
388
-    public static function getMethods()
389
-    {
390
-        return self::$methods;
391
-    }
392
-
393
-    /**
394
-     * @return array
395
-     */
396
-    public function getPatternWildcards()
397
-    {
398
-        return $this->patternWildcards;
399
-    }
400
-
401
-    /**
402
-     * @param string $pattern
403
-     * @param string $wildcard
404
-     */
405
-    public function setPatternWildcard($pattern, $wildcard)
406
-    {
407
-        $this->patternWildcards[(string) $pattern] = (string) $wildcard;
408
-    }
409
-
410
-    /**
411
-     * @return string
412
-     */
413
-
414
-    public function getActionDelimiter()
415
-    {
416
-        return $this->actionDelimiter;
417
-    }
418
-
419
-    /**
420
-     * @param string $delimiter
421
-     */
422
-
423
-    public function setActionDelimiter($delimiter)
424
-    {
425
-        $this->actionDelimiter = (string) $delimiter;
426
-    }
124
+	/**
125
+	 * Routes with parameters to compute.
126
+	 *
127
+	 * @var array [PROCESSED_INDEX => [ROUTE]]
128
+	 */
129
+
130
+	protected $dynamics;
131
+
132
+	/**
133
+	 * Insert a route into the collection.
134
+	 *
135
+	 * @param int                   $method   The HTTP method zone of route. {GET, POST, PUT, PATCH, DELETE}
136
+	 * @param string                $pattern  The URi that route should match.
137
+	 * @param string|array|\closure $action   The callback for when route is matched.
138
+	 * @param string                $strategy The route specific dispatch strategy.
139
+	 */
140
+
141
+	public function set($method, $pattern, $action, $strategy = null)
142
+	{
143
+		$patterns = $this->parsePatternOptionals($pattern);
144
+		$action = $this->parseAction($action);
145
+
146
+		foreach ($patterns as $pattern) {
147
+			strpos($pattern, '{') === false ?
148
+				$this->setStatic($method, $pattern, $action, $strategy) : $this->setDynamic($method, $pattern, $action, $strategy);
149
+		}
150
+	}
151
+
152
+	/**
153
+	 * Insert a static route into the collection.
154
+	 *
155
+	 * @param string                $method   The HTTP method of route. {GET, POST, PUT, PATCH, DELETE}
156
+	 * @param string                $pattern  The URi that route should match.
157
+	 * @param string|array|\closure $action   The callback for when route is matched.
158
+	 * @param string                $strategy The route specific dispatch strategy.
159
+	 */
160
+
161
+	protected function setStatic($method, $pattern, $action, $strategy)
162
+	{
163
+		$this->statics[$method][$pattern] = [
164
+			'action'   => $action,
165
+			'params'   => [],
166
+			'strategy' => $strategy
167
+		];
168
+	}
169
+
170
+	/**
171
+	 * Insert a dynamic route into the collection.
172
+	 *
173
+	 * @param string                $method   The HTTP method of route. {GET, POST, PUT, PATCH, DELETE}
174
+	 * @param string                $pattern  The URi that route should match.
175
+	 * @param string|array|\closure $action   The callback for when route is matched.
176
+	 * @param string                $strategy The route specific dispatch strategy.
177
+	 */
178
+
179
+	protected function setDynamic($method, $pattern, $action, $strategy)
180
+	{
181
+		$index = $this->getDynamicIndex($method, $pattern);
182
+
183
+		list($regex, $params) = $this->parsePatternPlaceholders($pattern);
184
+
185
+		$this->dynamics[$index][] = [
186
+			'action'   => $action,
187
+			'regex'    => $regex,
188
+			'params'   => $params,
189
+			'strategy' => $strategy
190
+		];
191
+	}
192
+
193
+	/**
194
+	 * Parses the given action to something that can be called.
195
+	 *
196
+	 * @param  string|array|\closure $action  The callback for when route is matched.
197
+	 * @return string|array|\closure
198
+	 */
199
+
200
+	protected function parseAction($action)
201
+	{
202
+		if (is_string($action)) {
203
+			return explode($this->actionDelimiter, $action);
204
+		}
205
+
206
+		return $action;
207
+	}
208
+
209
+	/**
210
+	 * Separate routes pattern with optional parts into n new patterns.
211
+	 *
212
+	 * @param string $pattern The route pattern to parse.
213
+	 * @return array
214
+	 */
215
+
216
+	protected function parsePatternOptionals($pattern)
217
+	{
218
+		$patternWithoutClosingOptionals = rtrim($pattern, ']');
219
+		$patternOptionalsNumber = strlen($pattern) - strlen($patternWithoutClosingOptionals);
220
+
221
+		$segments = preg_split('~' . self::DYNAMIC_REGEX . '(*SKIP)(*F) | \[~x', $patternWithoutClosingOptionals);
222
+		$this->parseSegmentOptionals($segments, $patternOptionalsNumber, $patternWithoutClosingOptionals);
223
+
224
+		return $this->buildPatterns($segments);
225
+	}
226
+
227
+	/**
228
+	 * Parse an route pattern seeking for parameters and making the route regex.
229
+	 *
230
+	 * @param string $pattern The route pattern to be parsed.
231
+	 * @return array 0 => new route regex, 1 => map of parameters names.
232
+	 */
233
+
234
+	protected function parsePatternPlaceholders($pattern)
235
+	{
236
+		$parameters = [];
237
+		preg_match_all('~' . self::DYNAMIC_REGEX . '~x', $pattern, $matches, PREG_SET_ORDER);
238
+
239
+		foreach ((array) $matches as $key => $match) {
240
+			$pattern = str_replace($match[0],
241
+				isset($match[2]) ? $this->getPlaceholderRegex($match[2]) : self::DEFAULT_PLACEHOLDER_REGEX, $pattern);
242
+			$parameters[$key] = $match[1];
243
+		}
244
+
245
+		return [$pattern, $parameters];
246
+	}
247
+
248
+	/**
249
+	 * Find and replace wildcards in one pattern placeholder.
250
+	 *
251
+	 * @param string $placeholder
252
+	 * @return string
253
+	 */
254
+
255
+	protected function getPlaceholderRegex($placeholder)
256
+	{
257
+		$strippedPlaceholder = strstr($placeholder, '{', true) ?: $placeholder;
258
+
259
+		if (isset($this->patternWildcards[$strippedPlaceholder])) {
260
+			return '(' . str_replace('{length}', strstr($placeholder, '{') ?: '+', $this->patternWildcards[$strippedPlaceholder]) . ')';
261
+		}
262
+
263
+		return '(' . trim($placeholder) . ')';
264
+	}
265
+
266
+	/**
267
+	 * Parse the pattern seeking for the error and show a more specific message.
268
+	 *
269
+	 * @param array $segments
270
+	 * @param int $patternOptionalsNumber
271
+	 * @param string $patternWithoutClosingOptionals
272
+	 *
273
+	 * @throws Exceptions\BadRouteException With a more specific error message.
274
+	 */
275
+
276
+	protected function parseSegmentOptionals(array $segments, $patternOptionalsNumber, $patternWithoutClosingOptionals)
277
+	{
278
+		if ($patternOptionalsNumber !== count($segments) - 1) {
279
+			if (preg_match('~' . self::DYNAMIC_REGEX . '(*SKIP)(*F) | \]~x', $patternWithoutClosingOptionals)) {
280
+				   throw new Exceptions\BadRouteException(Exceptions\BadRouteException::OPTIONAL_SEGMENTS_ON_MIDDLE);
281
+			} else throw new Exceptions\BadRouteException(Exceptions\BadRouteException::UNCLOSED_OPTIONAL_SEGMENTS);
282
+		}
283
+	}
284
+
285
+	/**
286
+	 * Build all the possibles patterns for a set of segments.
287
+	 *
288
+	 * @param array $segments
289
+	 * @throws Exceptions\BadRouteException
290
+	 * @return array
291
+	 */
292
+
293
+	protected function buildPatterns(array $segments)
294
+	{
295
+		$pattern  = '';
296
+		$patterns = [];
297
+
298
+		foreach ($segments as $n => $segment) {
299
+			if ($segment === '' && $n !== 0) {
300
+				throw new Exceptions\BadRouteException(Exceptions\BadRouteException::EMPTY_OPTIONAL_PARTS);
301
+			}
302
+
303
+			$patterns[] = $pattern .= $segment;
304
+		}
305
+
306
+		return $patterns;
307
+	}
308
+
309
+	/**
310
+	 * Group several routes into one unique regex.
311
+	 *
312
+	 * @param  array $routes All the routes that must be grouped
313
+	 * @return array
314
+	 */
315
+
316
+	protected function buildGroup($routes)
317
+	{
318
+		$map = []; 
319
+		$regex = [];
320
+		$groupCount = 0;
321
+
322
+		foreach ($routes as $route) {
323
+			$paramsCount      = count($route['params']);
324
+			$groupCount       = max($groupCount, $paramsCount) + 1;
325
+			$regex[]          = $route['regex'] . str_repeat('()', $groupCount - $paramsCount - 1);
326
+			$map[$groupCount] = [$route['action'], $route['params'], $route['strategy']];
327
+		}
328
+
329
+		return ['regex' => '~^(?|' . implode('|', $regex) . ')$~', 'map' => $map];
330
+	}
331
+
332
+	/**
333
+	 * Generate an index that will hold an especific group of dynamic routes.
334
+	 *
335
+	 * @param int $method The http method index defined by the METHOD_* constants
336
+	 * @param string $pattern
337
+	 *
338
+	 * @return int
339
+	 */
340
+
341
+	protected function getDynamicIndex($method, $pattern)
342
+	{
343
+		return (int) $method + substr_count($pattern, '/') - 1;
344
+	}
345
+
346
+	/**
347
+	 * Retrieve a specific static route or a false.
348
+	 *
349
+	 * @param int $method The http method index defined by the METHOD_* constants
350
+	 * @param string $pattern
351
+	 *
352
+	 * @return array|false
353
+	 */
354
+
355
+	public function getStaticRoute($method, $pattern)
356
+	{
357
+		if (isset($this->statics[$method]) && isset($this->statics[$method][$pattern])) {
358
+			return $this->statics[$method][$pattern];
359
+		}
360
+
361
+		return false;
362
+	}
363
+
364
+	/**
365
+	 * Concat all dynamic routes regex for a given method, this speeds up the match.
366
+	 *
367
+	 * @param string $method The http method to search in.
368
+	 * @param string $pattern
369
+	 *
370
+	 * @return array [['regex', 'map' => [0 => action, 1 => params]]]
371
+	 */
372
+
373
+	public function getDynamicRoutes($method, $pattern)
374
+	{
375
+		$index = $this->getDynamicIndex($method, $pattern);
376
+
377
+		if (!isset($this->dynamics[$index])) {
378
+			return [];
379
+		}
380
+
381
+		$dynamics = $this->dynamics[$index];
382
+		return array_map([$this, 'buildGroup'], array_chunk($dynamics, round(1 + 3.3 * log(count($dynamics))), true));
383
+	}
384
+
385
+	/**
386
+	 * @return array
387
+	 */
388
+	public static function getMethods()
389
+	{
390
+		return self::$methods;
391
+	}
392
+
393
+	/**
394
+	 * @return array
395
+	 */
396
+	public function getPatternWildcards()
397
+	{
398
+		return $this->patternWildcards;
399
+	}
400
+
401
+	/**
402
+	 * @param string $pattern
403
+	 * @param string $wildcard
404
+	 */
405
+	public function setPatternWildcard($pattern, $wildcard)
406
+	{
407
+		$this->patternWildcards[(string) $pattern] = (string) $wildcard;
408
+	}
409
+
410
+	/**
411
+	 * @return string
412
+	 */
413
+
414
+	public function getActionDelimiter()
415
+	{
416
+		return $this->actionDelimiter;
417
+	}
418
+
419
+	/**
420
+	 * @param string $delimiter
421
+	 */
422
+
423
+	public function setActionDelimiter($delimiter)
424
+	{
425
+		$this->actionDelimiter = (string) $delimiter;
426
+	}
427 427
 
428 428
 }
429 429
 
@@ -438,84 +438,84 @@  discard block
 block discarded – undo
438 438
 trait HttpMethodMapper
439 439
 {
440 440
 
441
-    abstract public function set($method, $pattern, $action, $strategy = null);
442
-
443
-    /**
444
-     * Register a set of routes for they especific http methods.
445
-     *
446
-     * @param string                $pattern  The URi pattern that should be matched.
447
-     * @param string|array|\closure $action   The action that must be executed in case of match.
448
-     * @param string                $strategy The route specific dispatch strategy.
449
-     */
450
-
451
-    public function get($pattern, $action, $strategy = null)
452
-    {
453
-        $this->set(Mapper::METHOD_GET, $pattern, $action, $strategy);
454
-    }
455
-
456
-    public function post($pattern, $action, $strategy = null)
457
-    {
458
-        $this->set(Mapper::METHOD_POST, $pattern, $action, $strategy);
459
-    }
460
-
461
-    public function put($pattern, $action, $strategy = null)
462
-    {
463
-        $this->set(Mapper::METHOD_PUT, $pattern, $action, $strategy);
464
-    }
465
-
466
-    public function patch($pattern, $action, $strategy = null)
467
-    {
468
-        $this->set(Mapper::METHOD_PATCH, $pattern, $action, $strategy);
469
-    }
470
-
471
-    public function delete($pattern, $action, $strategy = null)
472
-    {
473
-        $this->set(Mapper::METHOD_DELETE, $pattern, $action, $strategy);
474
-    }
475
-
476
-    /**
477
-     * Register a route into all HTTP methods.
478
-     *
479
-     * @param string                $pattern  The URi pattern that should be matched.
480
-     * @param string|array|\closure $action   The action that must be executed in case of match.
481
-     * @param string                $strategy The route specific dispatch strategy.
482
-     */
483
-    public function any($pattern, $action, $strategy = null)
484
-    {
485
-        foreach (Mapper::getMethods() as $method) {
486
-            $this->set($method, $pattern, $action, $strategy);
487
-        }
488
-    }
489
-
490
-    /**
491
-     * Register a route into all HTTP methods except by $method.
492
-     *
493
-     * @param string                $methods  The method that must be excluded.
494
-     * @param string                $pattern  The URi pattern that should be matched.
495
-     * @param string|array|\closure $action   The action that must be executed in case of match.
496
-     * @param string                $strategy The route specific dispatch strategy.
497
-     */
498
-    public function except($methods, $pattern, $action, $strategy = null)
499
-    {
500
-        foreach (array_diff_key(Mapper::getMethods(), array_flip((array) $methods)) as $method) {
501
-            $this->set($method, $pattern, $action, $strategy);
502
-        }
503
-    }
504
-
505
-    /**
506
-     * Register a route into given HTTP method(s).
507
-     *
508
-     * @param string|array          $methods  The method that must be matched.
509
-     * @param string                $pattern  The URi pattern that should be matched.
510
-     * @param string|array|\closure $action   The action that must be executed in case of match.
511
-     * @param string                $strategy The route specific dispatch strategy.
512
-     */
513
-    public function match($methods, $pattern, $action, $strategy = null)
514
-    {
515
-        foreach (array_intersect_key(Mapper::getMethods(), array_flip((array) $methods)) as $method) {
516
-            $this->set($method, $pattern, $action, $strategy);
517
-        }
518
-    }
441
+	abstract public function set($method, $pattern, $action, $strategy = null);
442
+
443
+	/**
444
+	 * Register a set of routes for they especific http methods.
445
+	 *
446
+	 * @param string                $pattern  The URi pattern that should be matched.
447
+	 * @param string|array|\closure $action   The action that must be executed in case of match.
448
+	 * @param string                $strategy The route specific dispatch strategy.
449
+	 */
450
+
451
+	public function get($pattern, $action, $strategy = null)
452
+	{
453
+		$this->set(Mapper::METHOD_GET, $pattern, $action, $strategy);
454
+	}
455
+
456
+	public function post($pattern, $action, $strategy = null)
457
+	{
458
+		$this->set(Mapper::METHOD_POST, $pattern, $action, $strategy);
459
+	}
460
+
461
+	public function put($pattern, $action, $strategy = null)
462
+	{
463
+		$this->set(Mapper::METHOD_PUT, $pattern, $action, $strategy);
464
+	}
465
+
466
+	public function patch($pattern, $action, $strategy = null)
467
+	{
468
+		$this->set(Mapper::METHOD_PATCH, $pattern, $action, $strategy);
469
+	}
470
+
471
+	public function delete($pattern, $action, $strategy = null)
472
+	{
473
+		$this->set(Mapper::METHOD_DELETE, $pattern, $action, $strategy);
474
+	}
475
+
476
+	/**
477
+	 * Register a route into all HTTP methods.
478
+	 *
479
+	 * @param string                $pattern  The URi pattern that should be matched.
480
+	 * @param string|array|\closure $action   The action that must be executed in case of match.
481
+	 * @param string                $strategy The route specific dispatch strategy.
482
+	 */
483
+	public function any($pattern, $action, $strategy = null)
484
+	{
485
+		foreach (Mapper::getMethods() as $method) {
486
+			$this->set($method, $pattern, $action, $strategy);
487
+		}
488
+	}
489
+
490
+	/**
491
+	 * Register a route into all HTTP methods except by $method.
492
+	 *
493
+	 * @param string                $methods  The method that must be excluded.
494
+	 * @param string                $pattern  The URi pattern that should be matched.
495
+	 * @param string|array|\closure $action   The action that must be executed in case of match.
496
+	 * @param string                $strategy The route specific dispatch strategy.
497
+	 */
498
+	public function except($methods, $pattern, $action, $strategy = null)
499
+	{
500
+		foreach (array_diff_key(Mapper::getMethods(), array_flip((array) $methods)) as $method) {
501
+			$this->set($method, $pattern, $action, $strategy);
502
+		}
503
+	}
504
+
505
+	/**
506
+	 * Register a route into given HTTP method(s).
507
+	 *
508
+	 * @param string|array          $methods  The method that must be matched.
509
+	 * @param string                $pattern  The URi pattern that should be matched.
510
+	 * @param string|array|\closure $action   The action that must be executed in case of match.
511
+	 * @param string                $strategy The route specific dispatch strategy.
512
+	 */
513
+	public function match($methods, $pattern, $action, $strategy = null)
514
+	{
515
+		foreach (array_intersect_key(Mapper::getMethods(), array_flip((array) $methods)) as $method) {
516
+			$this->set($method, $pattern, $action, $strategy);
517
+		}
518
+	}
519 519
 
520 520
 }
521 521
 
@@ -530,206 +530,206 @@  discard block
 block discarded – undo
530 530
 trait ControllerMapper
531 531
 {
532 532
 
533
-    abstract public function getActionDelimiter();
534
-    abstract public function getPatternWildcards();
535
-    abstract public function match($methods, $pattern, $action, $strategy = null);
536
-
537
-    /**
538
-     * Maps all the controller methods that begins with a HTTP method, and maps the rest of
539
-     * name as a uri. The uri will be the method name with slashes before every camelcased 
540
-     * word and without the HTTP method prefix. 
541
-     * e.g. getSomePage will generate a route to: GET some/page
542
-     *
543
-     * @param string|object $controller The controller name or representation.
544
-     * @param bool          $prefix     Dict if the controller name should prefix the path.
545
-     *
546
-     * @throws \BadMethodCallException
547
-     * @return Mapper
548
-     */
549
-
550
-    public function controller($controller, $prefix = true)
551
-    {
552
-        if (!$methods = get_class_methods($controller)) {
553
-            throw new \BadMethodCallException('The controller class could not be inspected.');
554
-        }
555
-
556
-        $methods = $this->getControllerMethods($methods);
557
-        $prefix = $this->getControllerPrefix($prefix, $controller);
558
-        $delimiter = $this->getActionDelimiter();
559
-
560
-        foreach ($methods as $route) {
561
-            $uri = preg_replace_callback('~(^|[a-z])([A-Z])~', [$this, 'getControllerAction'], $route[1]);
562
-
563
-            $methodName = $route[0] . $route[1];
564
-            $methodObj = new \ReflectionMethod($controller, $methodName);
565
-            $dynamic = $this->getMethodConstraints($methodObj);
566
-
567
-            $this->{$route[0]}($prefix . $uri . $dynamic, $controller . $delimiter . $methodName, $this->getMethodStrategy($methodObj));
568
-        }
569
-
570
-        return $this;
571
-    }
572
-
573
-    /**
574
-     * Give a prefix for the controller routes paths.
575
-     *
576
-     * @param bool $prefix Must prefix?
577
-     * @param string|object $controller The controller name or representation.
578
-     *
579
-     * @return string
580
-     */
581
-
582
-    protected function getControllerPrefix($prefix, $controller)
583
-    {
584
-        $path = '/';
585
-
586
-        if ($prefix === true) {
587
-            $path .= $this->getControllerName($controller);
588
-        }
589
-
590
-        return $path;
591
-    }
592
-
593
-    /**
594
-     * Transform camelcased strings into URIs.
595
-     *
596
-     * @param array $matches
597
-     *
598
-     * @return string
599
-     */
600
-
601
-    public function getControllerAction(array $matches)
602
-    {
603
-        return strtolower(strlen($matches[1]) ? $matches[1] . '/' . $matches[2] : $matches[2]);
604
-    }
605
-
606
-    /**
607
-     * Get the controller name without the suffix Controller.
608
-     *
609
-     * @param string|object $controller
610
-     * @param array $options
611
-     *
612
-     * @return string
613
-     */
614
-
615
-    public function getControllerName($controller, array $options = array())
616
-    {
617
-        if (isset($options['as'])) {
618
-            return $options['as'];
619
-        }
620
-
621
-        if (is_object($controller)) {
622
-            $controller = get_class($controller);
623
-        }
624
-
625
-        return strtolower(strstr(array_reverse(explode('\\', $controller))[0], 'Controller', true));
626
-    }
627
-
628
-    /**
629
-     * Maps the controller methods to HTTP methods.
630
-     *
631
-     * @param array $classMethods All the controller public methods
632
-     * @return array An array keyed by HTTP methods and their controller methods.
633
-     */
634
-
635
-    protected function getControllerMethods($classMethods)
636
-    {
637
-        $mapMethods = [];
638
-        $httpMethods = array_keys(Mapper::getMethods());
639
-
640
-        foreach ($classMethods as $classMethod) {
641
-            foreach ($httpMethods as $httpMethod) {
642
-                if (strpos($classMethod, $httpMethod) === 0) {
643
-                    $mapMethods[] = [$httpMethod, substr($classMethod, strlen($httpMethod))];
644
-                }
645
-            }
646
-        }
647
-
648
-        return $mapMethods;
649
-    }
650
-
651
-    /**
652
-     * Inspect a method seeking for parameters and make a dynamic pattern.
653
-     *
654
-     * @param \ReflectionMethod $method The method to be inspected name.
655
-     * @return string The resulting URi.
656
-     */
657
-
658
-    protected function getMethodConstraints(\ReflectionMethod $method)
659
-    {
660
-        $beginUri = '';
661
-        $endUri = '';
662
-
663
-        if ($parameters = $method->getParameters()) {
664
-            $types = $this->getParamsConstraint($method);
665
-
666
-            foreach ($parameters as $parameter) {
667
-                if ($parameter->isOptional()) {
668
-                    $beginUri .= '[';
669
-                    $endUri .= ']';
670
-                }
671
-
672
-                $beginUri .= $this->getUriConstraint($parameter, $types);
673
-            }
674
-        }
675
-
676
-        return $beginUri . $endUri;
677
-    }
678
-
679
-    /**
680
-     * Return a URi segment based on parameters constraints.
681
-     *
682
-     * @param \ReflectionParameter $parameter The parameter base to build the constraint.
683
-     * @param array $types All the parsed constraints.
684
-     *
685
-     * @return string
686
-     */
687
-
688
-    protected function getUriConstraint(\ReflectionParameter $parameter, $types)
689
-    {
690
-        $name = $parameter->name;
691
-        $uri  = '/{' . $name;
692
-
693
-        if (isset($types[$name])) {
694
-            return  $uri . ':' . $types[$name] . '}';
695
-        } else {
696
-            return $uri . '}';
697
-        }
698
-    }
699
-
700
-    /**
701
-     * Get all parameters with they constraint.
702
-     *
703
-     * @param \ReflectionMethod $method The method to be inspected name.
704
-     * @return array All the parameters with they constraint.
705
-     */
706
-
707
-    protected function getParamsConstraint(\ReflectionMethod $method)
708
-    {
709
-        $params = [];
710
-        preg_match_all('~\@param\s(' . implode('|', array_keys($this->getPatternWildcards())) . ')\s\$([a-zA-Z]+)\s(Match \((.+)\))?~',
711
-            $method->getDocComment(), $types, PREG_SET_ORDER);
712
-
713
-        foreach ((array) $types as $type) {
714
-            // if a pattern is defined on Match take it otherwise take the param type by PHPDoc.
715
-            $params[$type[2]] = isset($type[4]) ? $type[4] : $type[1];
716
-        }
717
-
718
-        return $params;
719
-    }
720
-
721
-    /**
722
-     * Get the strategy defined for a controller method by comment.
723
-     *
724
-     * @param \ReflectionMethod $method
725
-     * @return null|string
726
-     */
727
-
728
-    protected function getMethodStrategy(\ReflectionMethod $method)
729
-    {
730
-        preg_match('~\@strategy\s([a-zA-Z\\\_]+)~', $method->getDocComment(), $strategy);
731
-        return isset($strategy[1]) ? $strategy[1] : null;
732
-    }
533
+	abstract public function getActionDelimiter();
534
+	abstract public function getPatternWildcards();
535
+	abstract public function match($methods, $pattern, $action, $strategy = null);
536
+
537
+	/**
538
+	 * Maps all the controller methods that begins with a HTTP method, and maps the rest of
539
+	 * name as a uri. The uri will be the method name with slashes before every camelcased 
540
+	 * word and without the HTTP method prefix. 
541
+	 * e.g. getSomePage will generate a route to: GET some/page
542
+	 *
543
+	 * @param string|object $controller The controller name or representation.
544
+	 * @param bool          $prefix     Dict if the controller name should prefix the path.
545
+	 *
546
+	 * @throws \BadMethodCallException
547
+	 * @return Mapper
548
+	 */
549
+
550
+	public function controller($controller, $prefix = true)
551
+	{
552
+		if (!$methods = get_class_methods($controller)) {
553
+			throw new \BadMethodCallException('The controller class could not be inspected.');
554
+		}
555
+
556
+		$methods = $this->getControllerMethods($methods);
557
+		$prefix = $this->getControllerPrefix($prefix, $controller);
558
+		$delimiter = $this->getActionDelimiter();
559
+
560
+		foreach ($methods as $route) {
561
+			$uri = preg_replace_callback('~(^|[a-z])([A-Z])~', [$this, 'getControllerAction'], $route[1]);
562
+
563
+			$methodName = $route[0] . $route[1];
564
+			$methodObj = new \ReflectionMethod($controller, $methodName);
565
+			$dynamic = $this->getMethodConstraints($methodObj);
566
+
567
+			$this->{$route[0]}($prefix . $uri . $dynamic, $controller . $delimiter . $methodName, $this->getMethodStrategy($methodObj));
568
+		}
569
+
570
+		return $this;
571
+	}
572
+
573
+	/**
574
+	 * Give a prefix for the controller routes paths.
575
+	 *
576
+	 * @param bool $prefix Must prefix?
577
+	 * @param string|object $controller The controller name or representation.
578
+	 *
579
+	 * @return string
580
+	 */
581
+
582
+	protected function getControllerPrefix($prefix, $controller)
583
+	{
584
+		$path = '/';
585
+
586
+		if ($prefix === true) {
587
+			$path .= $this->getControllerName($controller);
588
+		}
589
+
590
+		return $path;
591
+	}
592
+
593
+	/**
594
+	 * Transform camelcased strings into URIs.
595
+	 *
596
+	 * @param array $matches
597
+	 *
598
+	 * @return string
599
+	 */
600
+
601
+	public function getControllerAction(array $matches)
602
+	{
603
+		return strtolower(strlen($matches[1]) ? $matches[1] . '/' . $matches[2] : $matches[2]);
604
+	}
605
+
606
+	/**
607
+	 * Get the controller name without the suffix Controller.
608
+	 *
609
+	 * @param string|object $controller
610
+	 * @param array $options
611
+	 *
612
+	 * @return string
613
+	 */
614
+
615
+	public function getControllerName($controller, array $options = array())
616
+	{
617
+		if (isset($options['as'])) {
618
+			return $options['as'];
619
+		}
620
+
621
+		if (is_object($controller)) {
622
+			$controller = get_class($controller);
623
+		}
624
+
625
+		return strtolower(strstr(array_reverse(explode('\\', $controller))[0], 'Controller', true));
626
+	}
627
+
628
+	/**
629
+	 * Maps the controller methods to HTTP methods.
630
+	 *
631
+	 * @param array $classMethods All the controller public methods
632
+	 * @return array An array keyed by HTTP methods and their controller methods.
633
+	 */
634
+
635
+	protected function getControllerMethods($classMethods)
636
+	{
637
+		$mapMethods = [];
638
+		$httpMethods = array_keys(Mapper::getMethods());
639
+
640
+		foreach ($classMethods as $classMethod) {
641
+			foreach ($httpMethods as $httpMethod) {
642
+				if (strpos($classMethod, $httpMethod) === 0) {
643
+					$mapMethods[] = [$httpMethod, substr($classMethod, strlen($httpMethod))];
644
+				}
645
+			}
646
+		}
647
+
648
+		return $mapMethods;
649
+	}
650
+
651
+	/**
652
+	 * Inspect a method seeking for parameters and make a dynamic pattern.
653
+	 *
654
+	 * @param \ReflectionMethod $method The method to be inspected name.
655
+	 * @return string The resulting URi.
656
+	 */
657
+
658
+	protected function getMethodConstraints(\ReflectionMethod $method)
659
+	{
660
+		$beginUri = '';
661
+		$endUri = '';
662
+
663
+		if ($parameters = $method->getParameters()) {
664
+			$types = $this->getParamsConstraint($method);
665
+
666
+			foreach ($parameters as $parameter) {
667
+				if ($parameter->isOptional()) {
668
+					$beginUri .= '[';
669
+					$endUri .= ']';
670
+				}
671
+
672
+				$beginUri .= $this->getUriConstraint($parameter, $types);
673
+			}
674
+		}
675
+
676
+		return $beginUri . $endUri;
677
+	}
678
+
679
+	/**
680
+	 * Return a URi segment based on parameters constraints.
681
+	 *
682
+	 * @param \ReflectionParameter $parameter The parameter base to build the constraint.
683
+	 * @param array $types All the parsed constraints.
684
+	 *
685
+	 * @return string
686
+	 */
687
+
688
+	protected function getUriConstraint(\ReflectionParameter $parameter, $types)
689
+	{
690
+		$name = $parameter->name;
691
+		$uri  = '/{' . $name;
692
+
693
+		if (isset($types[$name])) {
694
+			return  $uri . ':' . $types[$name] . '}';
695
+		} else {
696
+			return $uri . '}';
697
+		}
698
+	}
699
+
700
+	/**
701
+	 * Get all parameters with they constraint.
702
+	 *
703
+	 * @param \ReflectionMethod $method The method to be inspected name.
704
+	 * @return array All the parameters with they constraint.
705
+	 */
706
+
707
+	protected function getParamsConstraint(\ReflectionMethod $method)
708
+	{
709
+		$params = [];
710
+		preg_match_all('~\@param\s(' . implode('|', array_keys($this->getPatternWildcards())) . ')\s\$([a-zA-Z]+)\s(Match \((.+)\))?~',
711
+			$method->getDocComment(), $types, PREG_SET_ORDER);
712
+
713
+		foreach ((array) $types as $type) {
714
+			// if a pattern is defined on Match take it otherwise take the param type by PHPDoc.
715
+			$params[$type[2]] = isset($type[4]) ? $type[4] : $type[1];
716
+		}
717
+
718
+		return $params;
719
+	}
720
+
721
+	/**
722
+	 * Get the strategy defined for a controller method by comment.
723
+	 *
724
+	 * @param \ReflectionMethod $method
725
+	 * @return null|string
726
+	 */
727
+
728
+	protected function getMethodStrategy(\ReflectionMethod $method)
729
+	{
730
+		preg_match('~\@strategy\s([a-zA-Z\\\_]+)~', $method->getDocComment(), $strategy);
731
+		return isset($strategy[1]) ? $strategy[1] : null;
732
+	}
733 733
 
734 734
 }
735 735
 
@@ -743,68 +743,68 @@  discard block
 block discarded – undo
743 743
 trait ResourceMapper
744 744
 {
745 745
 
746
-    abstract public function set($methods, $pattern, $action, $strategy = null);
747
-    abstract public function getActionDelimiter();
748
-    abstract public function getControllerName($controller, array $options = array());
749
-
750
-    /**
751
-     * A map of all routes of resources.
752
-     *
753
-     * @var array
754
-     */
755
-
756
-    protected $map = [
757
-        'index' => [Mapper::METHOD_GET, '/:name'],
758
-        'make' => [Mapper::METHOD_GET, '/:name/make'],
759
-        'create' => [Mapper::METHOD_POST, '/:name'],
760
-        'show' => [Mapper::METHOD_GET, '/:name/{id}'],
761
-        'edit' => [Mapper::METHOD_GET, '/:name/{id}/edit'],
762
-        'update' => [Mapper::METHOD_PUT, '/:name/{id}'],
763
-        'delete' => [Mapper::METHOD_DELETE, '/:name/{id}'],
764
-    ];
765
-
766
-    /**
767
-     * Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. 
768
-     * Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, 
769
-     * a resourceful route declares them in a single line of code
770
-     *
771
-     * @param string|object $controller The controller name or representation.
772
-     * @param array         $options    Some options like, 'as' to name the route pattern, 'only' to
773
-     *                                  explicit say that only this routes will be registered, and
774
-     *                                  except that register all the routes except the indicates.
775
-     */
776
-
777
-    public function resource($controller, array $options = array())
778
-    {
779
-        $name  = isset($options['prefix']) ? $options['prefix'] : '';
780
-        $name .= $this->getControllerName($controller, $options);
781
-        $actions = $this->getResourceActions($options);
782
-        $delimiter = $this->getActionDelimiter();
783
-
784
-        foreach ($actions as $action => $map) {
785
-            $this->set($map[0], str_replace(':name', $name, $map[1]),
786
-                is_string($controller) ? $controller . $delimiter . $action : [$controller, $action]);
787
-        }
788
-    }
789
-
790
-    /**
791
-     * Parse the options to find out what actions will be registered.
792
-     *
793
-     * @param array $options
794
-     * @return array
795
-     */
796
-
797
-    protected function getResourceActions($options)
798
-    {
799
-        if (isset($options['only'])) {
800
-            return array_intersect_key($this->map, array_flip($options['only']));
801
-        }
802
-
803
-        if (isset($options['except'])) {
804
-            return array_diff_key($this->map, array_flip($options['except']));
805
-        }
806
-
807
-        return $this->map;
808
-    }
746
+	abstract public function set($methods, $pattern, $action, $strategy = null);
747
+	abstract public function getActionDelimiter();
748
+	abstract public function getControllerName($controller, array $options = array());
749
+
750
+	/**
751
+	 * A map of all routes of resources.
752
+	 *
753
+	 * @var array
754
+	 */
755
+
756
+	protected $map = [
757
+		'index' => [Mapper::METHOD_GET, '/:name'],
758
+		'make' => [Mapper::METHOD_GET, '/:name/make'],
759
+		'create' => [Mapper::METHOD_POST, '/:name'],
760
+		'show' => [Mapper::METHOD_GET, '/:name/{id}'],
761
+		'edit' => [Mapper::METHOD_GET, '/:name/{id}/edit'],
762
+		'update' => [Mapper::METHOD_PUT, '/:name/{id}'],
763
+		'delete' => [Mapper::METHOD_DELETE, '/:name/{id}'],
764
+	];
765
+
766
+	/**
767
+	 * Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. 
768
+	 * Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, 
769
+	 * a resourceful route declares them in a single line of code
770
+	 *
771
+	 * @param string|object $controller The controller name or representation.
772
+	 * @param array         $options    Some options like, 'as' to name the route pattern, 'only' to
773
+	 *                                  explicit say that only this routes will be registered, and
774
+	 *                                  except that register all the routes except the indicates.
775
+	 */
776
+
777
+	public function resource($controller, array $options = array())
778
+	{
779
+		$name  = isset($options['prefix']) ? $options['prefix'] : '';
780
+		$name .= $this->getControllerName($controller, $options);
781
+		$actions = $this->getResourceActions($options);
782
+		$delimiter = $this->getActionDelimiter();
783
+
784
+		foreach ($actions as $action => $map) {
785
+			$this->set($map[0], str_replace(':name', $name, $map[1]),
786
+				is_string($controller) ? $controller . $delimiter . $action : [$controller, $action]);
787
+		}
788
+	}
789
+
790
+	/**
791
+	 * Parse the options to find out what actions will be registered.
792
+	 *
793
+	 * @param array $options
794
+	 * @return array
795
+	 */
796
+
797
+	protected function getResourceActions($options)
798
+	{
799
+		if (isset($options['only'])) {
800
+			return array_intersect_key($this->map, array_flip($options['only']));
801
+		}
802
+
803
+		if (isset($options['except'])) {
804
+			return array_diff_key($this->map, array_flip($options['except']));
805
+		}
806
+
807
+		return $this->map;
808
+	}
809 809
 
810 810
 }
Please login to merge, or discard this patch.
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -278,7 +278,9 @@
 block discarded – undo
278 278
         if ($patternOptionalsNumber !== count($segments) - 1) {
279 279
             if (preg_match('~' . self::DYNAMIC_REGEX . '(*SKIP)(*F) | \]~x', $patternWithoutClosingOptionals)) {
280 280
                    throw new Exceptions\BadRouteException(Exceptions\BadRouteException::OPTIONAL_SEGMENTS_ON_MIDDLE);
281
-            } else throw new Exceptions\BadRouteException(Exceptions\BadRouteException::UNCLOSED_OPTIONAL_SEGMENTS);
281
+            } else {
282
+            	throw new Exceptions\BadRouteException(Exceptions\BadRouteException::UNCLOSED_OPTIONAL_SEGMENTS);
283
+            }
282 284
         }
283 285
     }
284 286
 
Please login to merge, or discard this patch.
src/Strategies/DispatcherStrategyInterface.php 1 patch
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -20,14 +20,14 @@
 block discarded – undo
20 20
 interface DispatcherStrategyInterface
21 21
 {
22 22
 
23
-    /**
24
-     * Dispatch the matched route action.
25
-     *
26
-     * @param string|array|closure $action The matched route action.
27
-     * @param array                $params The route parameters.
28
-     *
29
-     * @return mixed The response of request.
30
-     */
23
+	/**
24
+	 * Dispatch the matched route action.
25
+	 *
26
+	 * @param string|array|closure $action The matched route action.
27
+	 * @param array                $params The route parameters.
28
+	 *
29
+	 * @return mixed The response of request.
30
+	 */
31 31
 
32
-    public function dispatch($action, array $params);
32
+	public function dispatch($action, array $params);
33 33
 }
Please login to merge, or discard this patch.
src/Strategies/UriDispatcherStrategy.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -19,17 +19,17 @@
 block discarded – undo
19 19
 class UriDispatcherStrategy implements DispatcherStrategyInterface
20 20
 {
21 21
 
22
-    /**
23
-     * @inheritDoc
24
-     */
22
+	/**
23
+	 * @inheritDoc
24
+	 */
25 25
 
26
-    public function dispatch($action, array $params)
27
-    {
28
-        if (is_array($action)) {
29
-            return call_user_func_array([new $action[0], $action[1]], $params);
30
-        } else {
31
-            return call_user_func_array($action, $params);
32
-        }
33
-    }
26
+	public function dispatch($action, array $params)
27
+	{
28
+		if (is_array($action)) {
29
+			return call_user_func_array([new $action[0], $action[1]], $params);
30
+		} else {
31
+			return call_user_func_array($action, $params);
32
+		}
33
+	}
34 34
 
35 35
 }
Please login to merge, or discard this patch.