diff options
| author | Sam Light <sam@lightscale.co.uk> | 2026-06-10 19:00:32 +0100 |
|---|---|---|
| committer | Sam Light <sam@lightscale.co.uk> | 2026-06-10 19:00:32 +0100 |
| commit | 4c6c1b00e69ea06367dba96b3b024af632b729b6 (patch) | |
| tree | 6f4d4700df5cd7d45a25082d0096ad70532438cd | |
| parent | b1b5696cf2fa0b2050d5b0387c4d819d2f41e4d4 (diff) | |
Refactor dispatch to use a seperate findRoute method
| -rw-r--r-- | src/RouteMatch.php | 14 | ||||
| -rw-r--r-- | src/Router.php | 36 | ||||
| -rw-r--r-- | tests/Unit/RouteMatch.php | 5 | ||||
| -rw-r--r-- | tests/Unit/RouteMatchTest.php | 26 | ||||
| -rw-r--r-- | tests/Unit/RouterTest.php | 65 |
5 files changed, 110 insertions, 36 deletions
diff --git a/src/RouteMatch.php b/src/RouteMatch.php new file mode 100644 index 0000000..d43bf80 --- /dev/null +++ b/src/RouteMatch.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +namespace Lightscale\Router; + +readonly class RouteMatch +{ + public function __construct( + public PathSegmentMatch $segmentMatch, + public Route $route, + ) { + } +} diff --git a/src/Router.php b/src/Router.php index d8580bd..9632c69 100644 --- a/src/Router.php +++ b/src/Router.php @@ -65,34 +65,50 @@ class Router ); } - public function dispatch(RequestInterface $request): ResponseInterface + public function findRoute(HttpMethod|string $method, string $path): ?RouteMatch { - $uri = $request->getUri(); - $match = $this->findSegment($uri->getPath()); + $match = $this->findSegment($path); if (null === $match) { - return $this->strategy->notFound($request); + return null; } - $segment = $match->segment; - $method = $request->getMethod(); - $method = HttpMethod::tryFrom(strtolower($method)); + $method = ( + $method instanceof HttpMethod ? + $method : + HttpMethod::tryFrom(strtolower($method)) + ); if (null === $method) { - return $this->strategy->notFound($request); + return null; } + $segment = $match->segment; $route = $segment->getRoute($method); $route ??= $segment->getRoute(HttpMethod::Any); if (null === $route) { + return null; + } + + return new RouteMatch( + $match, + $route, + ); + } + + public function dispatch(RequestInterface $request): ResponseInterface + { + $uri = $request->getUri(); + $match = $this->findRoute($request->getMethod(), $uri->getPath()); + if (null === $match) { return $this->strategy->notFound($request); } $call = new RouteCall( $request, - $route, - $match->parameters, + $match->route, + $match->segmentMatch->parameters, ); return $this->strategy->runRoute($call); diff --git a/tests/Unit/RouteMatch.php b/tests/Unit/RouteMatch.php new file mode 100644 index 0000000..083ebbd --- /dev/null +++ b/tests/Unit/RouteMatch.php @@ -0,0 +1,5 @@ +<?php + +declare(strict_types=1); + +namespace Lightscale\Router\Test\Unit; diff --git a/tests/Unit/RouteMatchTest.php b/tests/Unit/RouteMatchTest.php new file mode 100644 index 0000000..e3b8bce --- /dev/null +++ b/tests/Unit/RouteMatchTest.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +use Lightscale\Router\Enums\HttpMethod; +use Lightscale\Router\PathSegment; +use Lightscale\Router\PathSegmentMatch; +use Lightscale\Router\Route; +use Lightscale\Router\RouteMatch; + +it('initializes with data', function () { + $v = new RouteMatch( + $segMatch = new PathSegmentMatch( + new PathSegment('test'), + [] + ), + $route = new Route( + HttpMethod::Get, + fn () => null, + ), + ); + + expect($v) + ->segmentMatch->toBe($segMatch) + ->route->toBe($route); +}); diff --git a/tests/Unit/RouterTest.php b/tests/Unit/RouterTest.php index 2f8960a..dc78f56 100644 --- a/tests/Unit/RouterTest.php +++ b/tests/Unit/RouterTest.php @@ -9,6 +9,7 @@ use Lightscale\Router\Enums\PathSegmentType; use Lightscale\Router\PathSegment; use Lightscale\Router\Route; use Lightscale\Router\RouteCall; +use Lightscale\Router\RouteMatch; use Lightscale\Router\Router; use Nyholm\Psr7\Factory\Psr17Factory; @@ -107,6 +108,44 @@ it('return null when segment not found', function () { expect($router->findSegment('/testing/testing'))->toBeNull(); }); +it('returns null when finding route') + ->expect(fn () => (new Router())->findRoute(HttpMethod::Get, '/')) + ->toBeNull(); + +it('finds a route', function () { + $router = new Router(); + $seg = $router->root()->child('testing'); + $route = new Route(HttpMethod::Get, fn () => null); + $seg->addRoute($route); + + $result = $router->findRoute(HttpMethod::Get, '/testing'); + expect($result) + ->toBeInstanceOf(RouteMatch::class) + ->segmentMatch->segment->toBe($seg) + ->route->toBe($route); +}); + +it('finds any method route', function () { + $router = new Router(); + $router->root()->child('testing')->addRoute(new Route( + HttpMethod::Any, + fn () => null + )); + + $result = $router->findRoute(HttpMethod::Get, '/testing'); + expect($result)->toBeInstanceOf(RouteMatch::class); +}); + +it('finds route method case insenitively', function () { + $router = new Router(); + $router->root()->child('testing')->addRoute(new Route( + HttpMethod::Get, + fn () => null + )); + $result = $router->findRoute('gET', '/testing'); + expect($result)->toBeInstanceOf(RouteMatch::class); +}); + it('calls strategy notFound with dispatch', function () { $router = new Router(); $factory = new Psr17Factory(); @@ -144,29 +183,3 @@ it('calls strategy runRoute with dispatch on match', function () { $result = $router->dispatch($request); expect($result)->toBe($response); }); - -it('matches an any method route', function() { - $router = new Router(); - $factory = new Psr17Factory(); - $response = $factory->createResponse(); - $router->root()->child('testing')->addRoute(new Route( - HttpMethod::Any, - fn() => $response - )); - - $result = $router->dispatch($factory->createServerRequest(HttpMethod::Get->value, '/testing')); - expect($result)->toBe($response); -}); - -it('matches route method case insenitively', function() { - $router = new Router(); - $factory = new Psr17Factory(); - $response = $factory->createResponse(); - $router->root()->child('testing')->addRoute(new Route( - HttpMethod::Get, - fn() => $response - )); - - $result = $router->dispatch($factory->createServerRequest('GeT', '/testing')); - expect($result)->toBe($response); -}); |
