feat(cloud): path-param router + dispatch
This commit is contained in:
parent
f7a0a3740e
commit
430758c3b7
2 changed files with 49 additions and 0 deletions
24
cloud/src/Http/Router.php
Normal file
24
cloud/src/Http/Router.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace App\Http;
|
||||
|
||||
final class Router
|
||||
{
|
||||
private array $routes = [];
|
||||
|
||||
public function add(string $method, string $path, callable $handler): void {
|
||||
$regex = '#^' . preg_replace('#\{(\w+)\}#', '(?P<$1>[^/]+)', $path) . '$#';
|
||||
$this->routes[] = [strtoupper($method), $regex, $handler];
|
||||
}
|
||||
|
||||
public function dispatch(Request $req): Response {
|
||||
foreach ($this->routes as [$method, $regex, $handler]) {
|
||||
if ($req->method() !== $method) continue;
|
||||
if (preg_match($regex, $req->path(), $m)) {
|
||||
$params = array_filter($m, 'is_string', ARRAY_FILTER_USE_KEY);
|
||||
return $handler($req, $params);
|
||||
}
|
||||
}
|
||||
return Response::json(['error' => 'not_found'], 404);
|
||||
}
|
||||
}
|
||||
25
cloud/tests/RouterTest.php
Normal file
25
cloud/tests/RouterTest.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace App\Tests;
|
||||
use App\Http\{Router, Request, Response};
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class RouterTest extends TestCase
|
||||
{
|
||||
public function testMatchAndParams(): void {
|
||||
$r = new Router();
|
||||
$r->add('GET', '/events/{id}', fn(Request $req, array $p) => Response::json(['id' => $p['id']]));
|
||||
$res = $r->dispatch(new Request('GET', '/events/42', [], '', [], []));
|
||||
$this->assertSame(200, $res->status());
|
||||
$this->assertSame(['id' => '42'], json_decode($res->body(), true));
|
||||
}
|
||||
public function testUnmatchedIs404(): void {
|
||||
$r = new Router();
|
||||
$this->assertSame(404, $r->dispatch(new Request('GET', '/nope', [], '', [], []))->status());
|
||||
}
|
||||
public function testMethodMismatchIs404(): void {
|
||||
$r = new Router();
|
||||
$r->add('POST', '/x', fn() => Response::text('ok'));
|
||||
$this->assertSame(404, $r->dispatch(new Request('GET', '/x', [], '', [], []))->status());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue