From fec5a4d4051082d134c6c60776906dbeb0968197 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 07:24:00 -0400 Subject: [PATCH] Remove RouteInterface --- src/Routing/Route/PrefixRoute.php | 2 +- src/Routing/Route/RegexRoute.php | 2 +- src/Routing/Route/Route.php | 56 ++++++++++++- src/Routing/Route/RouteFactory.php | 2 +- src/Routing/Route/RouteFactoryInterface.php | 2 +- src/Routing/Route/RouteInterface.php | 80 ------------------- src/Routing/Route/StaticRoute.php | 2 +- src/Routing/Route/TemplateRoute.php | 2 +- src/Routing/Router.php | 24 +++--- .../unit/Routing/Route/PrefixRouteTest.php | 2 +- .../unit/Routing/Route/RegexRouteTest.php | 7 +- .../unit/Routing/Route/RouteFactoryTest.php | 12 ++- test/tests/unit/Routing/Route/RouteTest.php | 10 +-- .../unit/Routing/Route/StaticRouteTest.php | 7 +- .../unit/Routing/Route/TemplateRouteTest.php | 7 +- test/tests/unit/Routing/RouterTest.php | 61 +++++++------- 16 files changed, 119 insertions(+), 159 deletions(-) delete mode 100644 src/Routing/Route/RouteInterface.php diff --git a/src/Routing/Route/PrefixRoute.php b/src/Routing/Route/PrefixRoute.php index c958f8b..5aeb865 100644 --- a/src/Routing/Route/PrefixRoute.php +++ b/src/Routing/Route/PrefixRoute.php @@ -14,7 +14,7 @@ class PrefixRoute extends Route public function getType(): int { - return RouteInterface::TYPE_PREFIX; + return Route::TYPE_PREFIX; } /** diff --git a/src/Routing/Route/RegexRoute.php b/src/Routing/Route/RegexRoute.php index 536c3d6..de8d6b6 100644 --- a/src/Routing/Route/RegexRoute.php +++ b/src/Routing/Route/RegexRoute.php @@ -14,7 +14,7 @@ class RegexRoute extends Route public function getType(): int { - return RouteInterface::TYPE_PATTERN; + return Route::TYPE_PATTERN; } /** diff --git a/src/Routing/Route/Route.php b/src/Routing/Route/Route.php index c62b1b2..634c3e9 100644 --- a/src/Routing/Route/Route.php +++ b/src/Routing/Route/Route.php @@ -4,12 +4,21 @@ namespace WellRESTed\Routing\Route; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use RuntimeException; +use WellRESTed\MiddlewareInterface; /** * @internal */ -abstract class Route implements RouteInterface +abstract class Route implements MiddlewareInterface { + /** Matches when request path is an exact match to entire target */ + public const TYPE_STATIC = 0; + /** Matches when request path is an exact match to start of target */ + public const TYPE_PREFIX = 1; + /** Matches by request path by pattern and may extract matched varialbes */ + public const TYPE_PATTERN = 2; + /** @var string */ protected $target; /** @var MethodMap */ @@ -21,6 +30,45 @@ abstract class Route implements RouteInterface $this->methodMap = $methodMap; } + /** + * Return the Route::TYPE_ constants that identifies the type. + * + * TYPE_STATIC indicates the route MUST match only when the path is an + * exact match to the route's entire target. This route type SHOULD NOT + * provide path variables. + * + * TYPE_PREFIX indicates the route MUST match when the route's target + * appears in its entirety at the beginning of the path. + * + * TYPE_PATTERN indicates that matchesRequestTarget MUST be used + * to determine a match against a given path. This route type SHOULD + * provide path variables. + * + * @return int One of the Route::TYPE_ constants. + */ + abstract public function getType(): int; + + /** + * Return an array of variables extracted from the path most recently + * passed to matchesRequestTarget. + * + * If the path does not contain variables, or if matchesRequestTarget + * has not yet been called, this method MUST return an empty array. + * + * @return array + */ + abstract public function getPathVariables(): array; + + /** + * Examines a request target to see if it is a match for the route. + * + * @param string $requestTarget + * @return bool + * @throws RuntimeException Error occurred testing the target such as an + * invalid regular expression + */ + abstract public function matchesRequestTarget(string $requestTarget): bool; + /** * Path, partial path, or pattern to match request paths against. * @@ -50,6 +98,12 @@ abstract class Route implements RouteInterface $this->methodMap->register($method, $dispatchable); } + /** + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @param callable $next + * @return ResponseInterface + */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next) { $map = $this->methodMap; diff --git a/src/Routing/Route/RouteFactory.php b/src/Routing/Route/RouteFactory.php index 1e16e94..d0beb03 100644 --- a/src/Routing/Route/RouteFactory.php +++ b/src/Routing/Route/RouteFactory.php @@ -25,7 +25,7 @@ class RouteFactory implements RouteFactoryInterface * - Regular expressions will create RegexRoutes * * @param string $target Route target or target pattern - * @return RouteInterface + * @return Route */ public function create($target) { diff --git a/src/Routing/Route/RouteFactoryInterface.php b/src/Routing/Route/RouteFactoryInterface.php index c169682..65bd41e 100644 --- a/src/Routing/Route/RouteFactoryInterface.php +++ b/src/Routing/Route/RouteFactoryInterface.php @@ -16,7 +16,7 @@ interface RouteFactoryInterface * - Regular expressions will create RegexRoutes * * @param string $target Route target or target pattern - * @return RouteInterface + * @return Route */ public function create($target); } diff --git a/src/Routing/Route/RouteInterface.php b/src/Routing/Route/RouteInterface.php deleted file mode 100644 index 850a6c5..0000000 --- a/src/Routing/Route/RouteInterface.php +++ /dev/null @@ -1,80 +0,0 @@ -routes[$target])) { $route = $this->routes[$target]; @@ -218,26 +218,26 @@ class Router return $route; } - private function registerRouteForTarget(RouteInterface $route, string $target): void + private function registerRouteForTarget(Route $route, string $target): void { // Store the route to the hash indexed by original target. $this->routes[$target] = $route; // Store the route to the array of routes for its type. switch ($route->getType()) { - case RouteInterface::TYPE_STATIC: + case Route::TYPE_STATIC: $this->staticRoutes[$route->getTarget()] = $route; break; - case RouteInterface::TYPE_PREFIX: + case Route::TYPE_PREFIX: $this->prefixRoutes[rtrim($route->getTarget(), '*')] = $route; break; - case RouteInterface::TYPE_PATTERN: + case Route::TYPE_PATTERN: $this->patternRoutes[] = $route; break; } } - private function getStaticRoute(string $requestTarget): ?RouteInterface + private function getStaticRoute(string $requestTarget): ?Route { if (isset($this->staticRoutes[$requestTarget])) { return $this->staticRoutes[$requestTarget]; @@ -245,7 +245,7 @@ class Router return null; } - private function getPrefixRoute(string $requestTarget): ?RouteInterface + private function getPrefixRoute(string $requestTarget): ?Route { // Find all prefixes that match the start of this path. $prefixes = array_keys($this->prefixRoutes); diff --git a/test/tests/unit/Routing/Route/PrefixRouteTest.php b/test/tests/unit/Routing/Route/PrefixRouteTest.php index 2af3d19..b410b9b 100644 --- a/test/tests/unit/Routing/Route/PrefixRouteTest.php +++ b/test/tests/unit/Routing/Route/PrefixRouteTest.php @@ -20,7 +20,7 @@ class PrefixRouteTest extends TestCase { $methodMap = $this->prophesize(MethodMap::class); $route = new PrefixRoute('/*', $methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType()); + $this->assertSame(Route::TYPE_PREFIX, $route->getType()); } public function testReturnsEmptyArrayForPathVariables(): void diff --git a/test/tests/unit/Routing/Route/RegexRouteTest.php b/test/tests/unit/Routing/Route/RegexRouteTest.php index 887738d..ce10ee9 100644 --- a/test/tests/unit/Routing/Route/RegexRouteTest.php +++ b/test/tests/unit/Routing/Route/RegexRouteTest.php @@ -1,12 +1,9 @@ methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } /** @dataProvider matchingRouteProvider */ diff --git a/test/tests/unit/Routing/Route/RouteFactoryTest.php b/test/tests/unit/Routing/Route/RouteFactoryTest.php index 1ec246d..d818589 100644 --- a/test/tests/unit/Routing/Route/RouteFactoryTest.php +++ b/test/tests/unit/Routing/Route/RouteFactoryTest.php @@ -1,11 +1,9 @@ dispatcher->reveal()); $route = $factory->create('/cats/'); - $this->assertSame(RouteInterface::TYPE_STATIC, $route->getType()); + $this->assertSame(Route::TYPE_STATIC, $route->getType()); } public function testCreatesPrefixRoute() { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('/cats/*'); - $this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType()); + $this->assertSame(Route::TYPE_PREFIX, $route->getType()); } public function testCreatesRegexRoute() { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('~/cat/[0-9]+~'); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } public function testCreatesTemplateRoute() { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('/cat/{id}'); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } } diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index f57bed4..37d6b54 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -1,14 +1,12 @@ assertSame(self::TARGET, $this->route->getTarget()); } - public function testRegistersDispatchableWithMethodMap() + public function testRegistersDispatchableWithMethodMap(): void { $handler = $this->prophesize(RequestHandlerInterface::class)->reveal(); @@ -47,7 +45,7 @@ class RouteTest extends TestCase $this->methodMap->register('GET', $handler)->shouldHaveBeenCalled(); } - public function testDispatchesMethodMap() + public function testDispatchesMethodMap(): void { $request = new ServerRequest(); $response = new Response(); diff --git a/test/tests/unit/Routing/Route/StaticRouteTest.php b/test/tests/unit/Routing/Route/StaticRouteTest.php index 6ca6067..6b86f0c 100644 --- a/test/tests/unit/Routing/Route/StaticRouteTest.php +++ b/test/tests/unit/Routing/Route/StaticRouteTest.php @@ -1,11 +1,8 @@ prophesize(MethodMap::class); $route = new StaticRoute('/', $methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_STATIC, $route->getType()); + $this->assertSame(Route::TYPE_STATIC, $route->getType()); } public function testMatchesExactRequestTarget() diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index 8d87bce..bdf1d84 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -1,11 +1,8 @@ methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } // ------------------------------------------------------------------------- diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 58e5355..012e4c0 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -1,6 +1,6 @@ route = $this->prophesize(RouteInterface::class); + $this->route = $this->prophesize(Route::class); $this->route->__invoke(Argument::cetera())->willReturn(new Response()); $this->route->register(Argument::cetera()); - $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); + $this->route->getType()->willReturn(Route::TYPE_STATIC); $this->route->getTarget()->willReturn('/'); $this->route->getPathVariables()->willReturn([]); @@ -93,7 +92,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); + $this->route->getType()->willReturn(Route::TYPE_STATIC); $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); @@ -108,7 +107,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget('/animals/cats/molly'); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $this->route->getType()->willReturn(Route::TYPE_PREFIX); $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); @@ -123,7 +122,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->router->register('GET', $target, 'middleware'); @@ -135,16 +134,16 @@ class RouterTest extends TestCase public function testDispatchesStaticRouteBeforePrefixRoute() { - $staticRoute = $this->prophesize(RouteInterface::class); + $staticRoute = $this->prophesize(Route::class); $staticRoute->register(Argument::cetera()); $staticRoute->getTarget()->willReturn('/cats/'); - $staticRoute->getType()->willReturn(RouteInterface::TYPE_STATIC); + $staticRoute->getType()->willReturn(Route::TYPE_STATIC); $staticRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $prefixRoute = $this->prophesize(RouteInterface::class); + $prefixRoute = $this->prophesize(Route::class); $prefixRoute->register(Argument::cetera()); $prefixRoute->getTarget()->willReturn('/cats/*'); - $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $prefixRoute->getType()->willReturn(Route::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); $this->request = $this->request->withRequestTarget('/cats/'); @@ -164,16 +163,16 @@ class RouterTest extends TestCase { // Note: The longest route is also good for 2 points in Settlers of Catan. - $shortRoute = $this->prophesize(RouteInterface::class); + $shortRoute = $this->prophesize(Route::class); $shortRoute->register(Argument::cetera()); $shortRoute->getTarget()->willReturn('/animals/*'); - $shortRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $shortRoute->getType()->willReturn(Route::TYPE_PREFIX); $shortRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $longRoute = $this->prophesize(RouteInterface::class); + $longRoute = $this->prophesize(Route::class); $longRoute->register(Argument::cetera()); $longRoute->getTarget()->willReturn('/animals/cats/*'); - $longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $longRoute->getType()->willReturn(Route::TYPE_PREFIX); $longRoute->__invoke(Argument::cetera())->willReturn(new Response()); $this->request = $this->request @@ -192,16 +191,16 @@ class RouterTest extends TestCase public function testDispatchesPrefixRouteBeforePatternRoute() { - $prefixRoute = $this->prophesize(RouteInterface::class); + $prefixRoute = $this->prophesize(Route::class); $prefixRoute->register(Argument::cetera()); $prefixRoute->getTarget()->willReturn('/cats/*'); - $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $prefixRoute->getType()->willReturn(Route::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $patternRoute = $this->prophesize(RouteInterface::class); + $patternRoute = $this->prophesize(Route::class); $patternRoute->register(Argument::cetera()); $patternRoute->getTarget()->willReturn('/cats/{id}'); - $patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute->__invoke(Argument::cetera())->willReturn(new Response()); $this->request = $this->request->withRequestTarget('/cats/'); @@ -219,18 +218,18 @@ class RouterTest extends TestCase public function testDispatchesFirstMatchingPatternRoute() { - $patternRoute1 = $this->prophesize(RouteInterface::class); + $patternRoute1 = $this->prophesize(Route::class); $patternRoute1->register(Argument::cetera()); $patternRoute1->getTarget()->willReturn('/cats/{id}'); - $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute1->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); $patternRoute1->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute1->__invoke(Argument::cetera())->willReturn(new Response()); - $patternRoute2 = $this->prophesize(RouteInterface::class); + $patternRoute2 = $this->prophesize(Route::class); $patternRoute2->register(Argument::cetera()); $patternRoute2->getTarget()->willReturn('/cats/{name}'); - $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute2->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->__invoke(Argument::cetera())->willReturn(new Response()); @@ -250,18 +249,18 @@ class RouterTest extends TestCase public function testStopsTestingPatternsAfterFirstSuccessfulMatch() { - $patternRoute1 = $this->prophesize(RouteInterface::class); + $patternRoute1 = $this->prophesize(Route::class); $patternRoute1->register(Argument::cetera()); $patternRoute1->getTarget()->willReturn('/cats/{id}'); - $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute1->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); $patternRoute1->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute1->__invoke(Argument::cetera())->willReturn(new Response()); - $patternRoute2 = $this->prophesize(RouteInterface::class); + $patternRoute2 = $this->prophesize(Route::class); $patternRoute2->register(Argument::cetera()); $patternRoute2->getTarget()->willReturn('/cats/{name}'); - $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute2->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->__invoke(Argument::cetera())->willReturn(new Response()); @@ -286,7 +285,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->router->register('GET', $target, 'middleware'); @@ -310,7 +309,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->getPathVariables()->willReturn($variables); @@ -348,7 +347,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->getPathVariables()->willReturn($variables);