aboutsummaryrefslogtreecommitdiff
path: root/src/Routing/RouteLoader.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/Routing/RouteLoader.php')
-rw-r--r--src/Routing/RouteLoader.php98
1 files changed, 98 insertions, 0 deletions
diff --git a/src/Routing/RouteLoader.php b/src/Routing/RouteLoader.php
new file mode 100644
index 0000000..596340f
--- /dev/null
+++ b/src/Routing/RouteLoader.php
@@ -0,0 +1,98 @@
+<?php
+
+declare(strict_types=1);
+
+namespace BrettParson\MiniRoute\Routing;
+
+use BrettParson\MiniRoute\Attribute\Middleware;
+use BrettParson\MiniRoute\Attribute\RouteAttribute;
+use ReflectionAttribute;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionMethod;
+
+final class RouteLoader
+{
+ /**
+ * Scan a controller class and compile the routes declared on its public
+ * methods.
+ *
+ * @param class-string $controllerClass
+ * @return list<RouteDef>
+ */
+ public function load(string $controllerClass): array
+ {
+ if (!class_exists($controllerClass)) {
+ throw new RouteRegistrationException("Controller class not found: {$controllerClass}");
+ }
+
+ try {
+ $reflector = new ReflectionClass($controllerClass);
+ } catch (ReflectionException $e) {
+ throw new RouteRegistrationException("Unable to reflect controller: {$controllerClass}", 0, $e);
+ }
+
+ $classMiddleware = $this->middlewareClasses($reflector->getAttributes(Middleware::class));
+
+ $routes = [];
+
+ foreach ($reflector->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
+ foreach ($this->loadMethod($controllerClass, $method, $classMiddleware) as $route) {
+ $routes[] = $route;
+ }
+ }
+
+ return $routes;
+ }
+
+ /**
+ * @param list<string> $classMiddleware
+ * @return list<RouteDef>
+ */
+ private function loadMethod(string $controllerClass, ReflectionMethod $method, array $classMiddleware): array
+ {
+ $routeAttributes = $method->getAttributes(RouteAttribute::class, ReflectionAttribute::IS_INSTANCEOF);
+
+ if ($routeAttributes === []) {
+ return [];
+ }
+
+ $methodMiddleware = $this->middlewareClasses($method->getAttributes(Middleware::class));
+
+ $middleware = array_merge($classMiddleware, $methodMiddleware);
+
+ $routes = [];
+
+ foreach ($routeAttributes as $attribute) {
+ /** @var RouteAttribute $route */
+ $route = $attribute->newInstance();
+
+ $routes[] = new RouteDef(
+ strtoupper($route->method()),
+ $route->path(),
+ $controllerClass,
+ $method->getName(),
+ $middleware,
+ );
+ }
+
+ return $routes;
+ }
+
+ /**
+ * @param list<ReflectionAttribute> $attributes
+ * @return list<string>
+ */
+ private function middlewareClasses(array $attributes): array
+ {
+ $classes = [];
+
+ foreach ($attributes as $attribute) {
+ /** @var Middleware $middleware */
+ $middleware = $attribute->newInstance();
+ $classes[] = $middleware->middlewareClass;
+ }
+
+ return $classes;
+ }
+}