summaryrefslogtreecommitdiff
path: root/src
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
commit8c0efd0d9317ad92bd55cd6afcd41bdbab827bf8 (patch)
treec654456753e90ab38b7bcb89ece3381ad7a40f4a /src
parent5fe7c87967ff29c4a8f03a9186918d8359f4887e (diff)
Make basic routing work
Diffstat (limited to 'src')
-rw-r--r--src/BasicStrategy.php23
-rw-r--r--src/Contracts/Strategy.php15
-rw-r--r--src/Route.php11
-rw-r--r--src/RouteCall.php17
-rw-r--r--src/Router.php77
5 files changed, 130 insertions, 13 deletions
diff --git a/src/BasicStrategy.php b/src/BasicStrategy.php
new file mode 100644
index 0000000..62bc48e
--- /dev/null
+++ b/src/BasicStrategy.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Lightscale\Router;
+
+use Lightscale\Router\Contracts\Strategy;
+use Lightscale\Router\Exceptions\NotFoundException;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+class BasicStrategy implements Strategy
+{
+ public function runRoute(RouteCall $call): ResponseInterface
+ {
+ return ($call->route->getHandler())($call);
+ }
+
+ public function notFound(RequestInterface $request): ResponseInterface
+ {
+ throw new NotFoundException();
+ }
+}
diff --git a/src/Contracts/Strategy.php b/src/Contracts/Strategy.php
new file mode 100644
index 0000000..81d6ec3
--- /dev/null
+++ b/src/Contracts/Strategy.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Lightscale\Router\Contracts;
+
+use Lightscale\Router\RouteCall;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+interface Strategy
+{
+ public function runRoute(RouteCall $call): ResponseInterface;
+ public function notFound(RequestInterface $request): ResponseInterface;
+}
diff --git a/src/Route.php b/src/Route.php
index aeb3f66..af08ded 100644
--- a/src/Route.php
+++ b/src/Route.php
@@ -6,7 +6,6 @@ namespace Lightscale\Router;
use Closure;
use Lightscale\Router\Enums\HttpMethod;
-use Psr\Http\Message\RequestInterface;
class Route
{
@@ -26,11 +25,6 @@ class Route
}
}
- public function __invoke(RequestInterface $request): mixed
- {
- return ($this->handler)($request);
- }
-
public function getMethod(): HttpMethod
{
return $this->method;
@@ -50,4 +44,9 @@ class Route
{
return $this->segment->getPath();
}
+
+ public function getHandler(): Closure
+ {
+ return $this->handler;
+ }
}
diff --git a/src/RouteCall.php b/src/RouteCall.php
new file mode 100644
index 0000000..b76a780
--- /dev/null
+++ b/src/RouteCall.php
@@ -0,0 +1,17 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Lightscale\Router;
+
+use Psr\Http\Message\RequestInterface;
+
+class RouteCall
+{
+ /** @param array<string, string> $parameters */
+ public function __construct(
+ public RequestInterface $request,
+ public Route $route,
+ public array $parameters,
+ ) {}
+}
diff --git a/src/Router.php b/src/Router.php
index f666fe5..ddd3220 100644
--- a/src/Router.php
+++ b/src/Router.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Lightscale\Router;
+use Lightscale\Router\Contracts\Strategy;
use Lightscale\Router\Enums\HttpMethod;
use Lightscale\Router\Enums\PathSegmentType;
use Lightscale\Router\Exceptions\NotFoundException;
@@ -14,10 +15,22 @@ use Psr\Http\Message\ResponseInterface;
class Router
{
private PathSegment $root;
+ private Strategy $strategy;
public function __construct()
{
$this->root = new PathSegment(type: PathSegmentType::Root);
+ $this->strategy = new BasicStrategy;
+ }
+
+ public function getStrategy(): Strategy
+ {
+ return $this->strategy;
+ }
+
+ public function setStrategy(Strategy $strategy): void
+ {
+ $this->strategy = $strategy;
}
public function root(): PathSegment
@@ -60,21 +73,71 @@ class Router
$match = $this->findSegment($uri->getPath());
if (null === $match) {
- throw new NotFoundException();
+ return $this->strategy->notFound($request);
}
$segment = $match->segment;
$method = $request->getMethod();
- $method = (
- HttpMethod::tryFrom(strtolower($method)) ??
- throw new UnknownMethodException()
- );
+ $method = HttpMethod::tryFrom(strtolower($method));
+
+ if ($method === null) {
+ return $this->strategy->notFound($request);
+ }
+
$route = $segment->getRoute($method);
if (null === $route) {
- throw new NotFoundException();
+ return $this->strategy->notFound($request);
+ }
+
+ $call = new RouteCall(
+ $request,
+ $route,
+ $match->parameters,
+ );
+
+ return $this->strategy->runRoute($call);
+ }
+
+ public function route(HttpMethod $method, string $path, callable $handler): void
+ {
+ $pathSplit = $this->splitPath($path);
+
+ $seg = $this->root();
+ while(($v = array_shift($pathSplit)) !== null) {
+ $seg = $seg->child($v);
}
- return $route($request);
+ $seg->addRoute(new Route($method, $handler));
+ }
+
+ public function get(string $path, callable $handler): void
+ {
+ $this->route(HttpMethod::Get, $path, $handler);
+ }
+
+ public function post(string $path, callable $handler): void
+ {
+ $this->route(HttpMethod::Post, $path, $handler);
+ }
+
+ public function put(string $path, callable $handler): void
+ {
+ $this->route(HttpMethod::Put, $path, $handler);
+ }
+
+ public function patch(string $path, callable $handler): void
+ {
+ $this->route(HttpMethod::Patch, $path, $handler);
+ }
+
+ public function delete(string $path, callable $handler): void
+ {
+ $this->route(HttpMethod::Delete, $path, $handler);
+ }
+
+ public function any(string $path, callable $handler): void
+ {
+ $this->route(HttpMethod::Any, $path, $handler);
}
}