Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.

Commit 21df1e6

Browse files
committed
Move duplication check logic in separate class
1 parent 7f55258 commit 21df1e6

File tree

2 files changed

+108
-87
lines changed

2 files changed

+108
-87
lines changed

src/DuplicateRouteDetector.php

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
5+
namespace Zend\Expressive\Router;
6+
7+
final class DuplicateRouteDetector
8+
{
9+
private const ROUTE_SEARCH_ANY = 'any';
10+
private const ROUTE_SEARCH_METHODS = 'methods';
11+
12+
/**
13+
* List of all routes indexed by name
14+
*
15+
* @var Route[]
16+
*/
17+
private $routeNames = [];
18+
19+
/**
20+
* Search structure for duplicate path-method detection
21+
* Indexed by path + method. Leaves are instances of Route
22+
* [
23+
* '/path/foo' => [
24+
* 'methods' => [
25+
* 'GET' => $route1,
26+
* 'POST' => $route2,
27+
* ],
28+
* ],
29+
* '/path/bar' => [ 'any' => $route3 ],
30+
* ]
31+
*
32+
* @var array
33+
*/
34+
private $routePaths = [];
35+
36+
/**
37+
* Determine if the route is duplicated in the current list.
38+
*
39+
* Checks if a route with the same name or path exists already in the list;
40+
* if so, and it responds to any of the $methods indicated, raises
41+
* a DuplicateRouteException indicating a duplicate route.
42+
*
43+
* @throws Exception\DuplicateRouteException on duplicate route detection.
44+
*/
45+
public function detectDuplicate(Route $route): void
46+
{
47+
$this->throwOnDuplicate($route);
48+
$this->remember($route);
49+
}
50+
51+
private function remember(Route $route): void
52+
{
53+
$this->routeNames[$route->getName()] = $route;
54+
if ($route->allowsAnyMethod()) {
55+
$this->routePaths[$route->getPath()][self::ROUTE_SEARCH_ANY] = $route;
56+
}
57+
58+
$allowedMethods = $route->getAllowedMethods() ?? [];
59+
foreach ($allowedMethods as $allowedMethod) {
60+
$this->routePaths[$route->getPath()][self::ROUTE_SEARCH_METHODS][$allowedMethod] = $route;
61+
}
62+
}
63+
64+
private function throwOnDuplicate(Route $route): void
65+
{
66+
if (isset($this->routeNames[$route->getName()])) {
67+
$this->duplicateRouteDetected($route);
68+
}
69+
70+
if (! isset($this->routePaths[$route->getPath()])) {
71+
return;
72+
}
73+
74+
if (isset($this->routePaths[$route->getPath()][self::ROUTE_SEARCH_ANY])) {
75+
$this->duplicateRouteDetected($route);
76+
}
77+
78+
if ($route->allowsAnyMethod() && isset($this->routePaths[$route->getPath()][self::ROUTE_SEARCH_METHODS])) {
79+
$this->duplicateRouteDetected($route);
80+
}
81+
82+
$allowedMethods = $route->getAllowedMethods() ?? [];
83+
foreach ($allowedMethods as $method) {
84+
if (isset($this->routePaths[$route->getPath()][self::ROUTE_SEARCH_METHODS][$method])) {
85+
$this->duplicateRouteDetected($route);
86+
}
87+
}
88+
}
89+
90+
private function duplicateRouteDetected(Route $duplicate): void
91+
{
92+
$allowedMethods = $duplicate->getAllowedMethods() ?: [ '(any)' ];
93+
$name = $duplicate->getName();
94+
throw new Exception\DuplicateRouteException(
95+
sprintf(
96+
'Duplicate route detected; path "%s" answering to methods [%s]%s',
97+
$duplicate->getPath(),
98+
implode(',', $allowedMethods),
99+
$name ? sprintf(', with name "%s"', $name) : ''
100+
)
101+
);
102+
}
103+
}

src/RouteCollector.php

Lines changed: 5 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@
3333
*/
3434
class RouteCollector
3535
{
36-
private const ROUTE_SEARCH_ANY = 'any';
37-
private const ROUTE_SEARCH_METHODS = 'methods';
38-
3936
/**
4037
* @var RouterInterface
4138
*/
@@ -49,32 +46,16 @@ class RouteCollector
4946
private $routes = [];
5047

5148
/**
52-
* List of all routes indexed by name
53-
*
54-
* @var Route[]
55-
*/
56-
private $routeNames = [];
57-
58-
/**
59-
* Search structure for duplicate path-method detection
60-
* Indexed by path + method. Leaves are instances of Route
61-
* [
62-
* '/path/foo' => [
63-
* 'methods' => [
64-
* 'GET' => $route1,
65-
* 'POST' => $route2,
66-
* ],
67-
* ],
68-
* '/path/bar' => [ 'any' => $route3 ],
69-
* ]
49+
* Checks for duplicate routes
7050
*
71-
* @var array
51+
* @var DuplicateRouteDetector
7252
*/
73-
private $routePaths = [];
53+
private $duplicateChecker;
7454

7555
public function __construct(RouterInterface $router)
7656
{
7757
$this->router = $router;
58+
$this->duplicateChecker = new DuplicateRouteDetector();
7859
}
7960

8061
/**
@@ -95,27 +76,13 @@ public function route(
9576

9677
$methods = $methods ?? Route::HTTP_METHOD_ANY;
9778
$route = new Route($path, $middleware, $methods, $name);
98-
$this->checkForDuplicateRoute($route);
99-
$this->fillRouteSearchStructure($route);
79+
$this->duplicateChecker->detectDuplicate($route);
10080
$this->routes[] = $route;
10181
$this->router->addRoute($route);
10282

10383
return $route;
10484
}
10585

106-
private function fillRouteSearchStructure(Route $route): void
107-
{
108-
$this->routeNames[$route->getName()] = $route;
109-
if ($route->allowsAnyMethod()) {
110-
$this->routePaths[$route->getPath()][self::ROUTE_SEARCH_ANY] = $route;
111-
}
112-
113-
$allowedMethods = $route->getAllowedMethods() ?? [];
114-
foreach ($allowedMethods as $allowedMethod) {
115-
$this->routePaths[$route->getPath()][self::ROUTE_SEARCH_METHODS][ $allowedMethod] = $route;
116-
}
117-
}
118-
11986
/**
12087
* @param null|string $name The name of the route.
12188
*/
@@ -173,53 +140,4 @@ public function getRoutes() : array
173140
{
174141
return $this->routes;
175142
}
176-
177-
/**
178-
* Determine if the route is duplicated in the current list.
179-
*
180-
* Checks if a route with the same name or path exists already in the list;
181-
* if so, and it responds to any of the $methods indicated, raises
182-
* a DuplicateRouteException indicating a duplicate route.
183-
*
184-
* @throws Exception\DuplicateRouteException on duplicate route detection.
185-
*/
186-
private function checkForDuplicateRoute(Route $route) : void
187-
{
188-
if (isset($this->routeNames[$route->getName()])) {
189-
$this->duplicateRouteDetected($route);
190-
}
191-
192-
if (! isset($this->routePaths[$route->getPath()])) {
193-
return;
194-
}
195-
196-
if (isset($this->routePaths[$route->getPath()][self::ROUTE_SEARCH_ANY])) {
197-
$this->duplicateRouteDetected($route);
198-
}
199-
200-
if ($route->allowsAnyMethod() && isset($this->routePaths[$route->getPath()][self::ROUTE_SEARCH_METHODS])) {
201-
$this->duplicateRouteDetected($route);
202-
}
203-
204-
$allowedMethods = $route->getAllowedMethods() ?? [];
205-
foreach ($allowedMethods as $method) {
206-
if (isset($this->routePaths[$route->getPath()][self::ROUTE_SEARCH_METHODS][ $method])) {
207-
$this->duplicateRouteDetected($route);
208-
}
209-
}
210-
}
211-
212-
private function duplicateRouteDetected(Route $duplicate):void
213-
{
214-
$allowedMethods = $duplicate->getAllowedMethods() ?: ['(any)'];
215-
$name = $duplicate->getName();
216-
throw new Exception\DuplicateRouteException(
217-
sprintf(
218-
'Duplicate route detected; path "%s" answering to methods [%s]%s',
219-
$duplicate->getPath(),
220-
implode(',', $allowedMethods),
221-
$name ? sprintf(', with name "%s"', $name) : ''
222-
)
223-
);
224-
}
225143
}

0 commit comments

Comments
 (0)