summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Light <sam@lightscale.co.uk>2026-06-10 19:00:32 +0100
committerSam Light <sam@lightscale.co.uk>2026-06-10 19:00:32 +0100
commit4c6c1b00e69ea06367dba96b3b024af632b729b6 (patch)
tree6f4d4700df5cd7d45a25082d0096ad70532438cd
parentb1b5696cf2fa0b2050d5b0387c4d819d2f41e4d4 (diff)
Refactor dispatch to use a seperate findRoute method
-rw-r--r--src/RouteMatch.php14
-rw-r--r--src/Router.php36
-rw-r--r--tests/Unit/RouteMatch.php5
-rw-r--r--tests/Unit/RouteMatchTest.php26
-rw-r--r--tests/Unit/RouterTest.php65
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);
-});