Added routing through attributes.

This commit is contained in:
flash 2023-09-07 22:08:31 +00:00
parent 2b8b31289d
commit 32254bf398
4 changed files with 109 additions and 2 deletions

View file

@ -1 +1 @@
0.2309.61148
0.2309.72158

49
src/Routing/Route.php Normal file
View file

@ -0,0 +1,49 @@
<?php
// Route.php
// Created: 2023-09-07
// Updated: 2023-09-07
namespace Index\Routing;
use Attribute;
use ReflectionObject;
use UnexpectedValueException;
#[Attribute]
class Route {
public function __construct(
private string $method,
private string $path
) {}
public function getMethod(): string {
return $this->method;
}
public function getPath(): string {
return $this->path;
}
public static function handleAttributes(IRouter $router, IRouteHandler $handler): void {
$objectInfo = new ReflectionObject($handler);
$methodInfos = $objectInfo->getMethods();
foreach($methodInfos as $methodInfo) {
$attrInfos = $methodInfo->getAttributes(Route::class);
foreach($attrInfos as $attrInfo) {
if($attrInfo->isRepeated())
throw new UnexpectedValueException('Only one instance of the Route attribute should be used per method.');
$routeInfo = $attrInfo->newInstance();
$router->add(
$routeInfo->getMethod(),
$routeInfo->getPath(),
$methodInfo->getClosure(
$methodInfo->isStatic() ? null : $handler
)
);
}
}
}
}

View file

@ -0,0 +1,12 @@
<?php
// RouteHandlerTrait.php
// Created: 2023-09-07
// Updated: 2023-09-07
namespace Index\Routing;
trait RouteHandlerTrait {
public function registerRoutes(IRouter $router): void {
Route::handleAttributes($router, $this);
}
}

View file

@ -1,11 +1,14 @@
<?php
// RouterTest.php
// Created: 2022-01-20
// Updated: 2022-02-05
// Updated: 2023-09-07
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Index\Routing\IRouteHandler;
use Index\Routing\Route;
use Index\Routing\RouteHandlerTrait;
use Index\Routing\Router;
/**
@ -111,4 +114,47 @@ final class RouterTest extends TestCase {
$this->assertEquals('correct', $router3->resolve('GET', '/static/0')->run());
$this->assertEquals('correct', $router3->resolve('GET', '/variable/0')->run());
}
public function testAttribute(): void {
$router = new Router;
$handler = new class implements IRouteHandler {
use RouteHandlerTrait;
#[Route('GET', '/')]
public function getIndex() {
return 'index';
}
#[Route('POST', '/avatar')]
public function postAvatar() {
return 'avatar';
}
#[Route('PUT', '/static')]
public static function putStatic() {
return 'static';
}
public function hasNoAttr() {
return 'meow';
}
};
$router->register($handler);
$this->assertEquals('index', $router->resolve('GET', '/')->run());
$this->assertEquals('avatar', $router->resolve('POST', '/avatar')->run());
$this->assertEquals('static', $router->resolve('PUT', '/static')->run());
$badHandler = new class implements IRouteHandler {
use RouteHandlerTrait;
#[Route('GET', '/')]
#[Route('POST', '/meow')]
public function getPostBad() {
return 'this is bad';
}
};
$this->expectException(UnexpectedValueException::class);
$router->register($badHandler);
}
}