master
21 Commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
f8d1c66934 | Implement commands | |||
1ee5c1c992 | Add console | |||
59200be680 | Add doctrine and seperate out the renderer | |||
56e8caa26c | Add key based genericConfig | |||
18848e041f | Play around with the rendering | |||
24683e70a8 | Streamline view rendering | |||
45797ba20a | Add ViewHelper in view for injecting some basic classes in views | |||
de5ff3a2b9 | Add toUri function to router | |||
c80dcd2860 | Implement simple PHP based view renderer | |||
9b8985640c |
Add appConfig to container
diff --git a/public/index.php b/public/index.php index 78fef51..e15604b 100644 --- a/public/index.php +++ b/public/index.php @@ -8,8 +8,7 @@ error_reporting(E_ALL); use App\Kernel; -require_once dirname(__DIR__).'/vendor/autoload.php'; +require_once dirname(__DIR__) . '/vendor/autoload.php'; -$kernel = new Kernel(); - -$kernel(); \ No newline at end of file +$kernel = new Kernel(__DIR__ . '/../app'); +$kernel->run(); \ No newline at end of file diff --git a/src/AppConfig.php b/src/AppConfig.php new file mode 100644 index 0000000..bcf0ee6 --- /dev/null +++ b/src/AppConfig.php @@ -0,0 +1,17 @@ +<?php + +namespace Ardent\Undercurrent; + +class AppConfig +{ + public function __construct( + private readonly string $rootPath, + ) + { + } + + public function getRootPath(): string + { + return $this->rootPath; + } +} \ No newline at end of file diff --git a/src/Kernel/BaseKernel.php b/src/Kernel/BaseKernel.php index 60164d8..c27f49a 100644 --- a/src/Kernel/BaseKernel.php +++ b/src/Kernel/BaseKernel.php @@ -2,6 +2,7 @@ namespace Ardent\Undercurrent\Kernel; +use Ardent\Undercurrent\AppConfig; use Ardent\Undercurrent\Container\ContainerInterface; use Ardent\Undercurrent\Container\GenericContainer; use Ardent\Undercurrent\Http\GenericRequest; @@ -13,18 +14,26 @@ use Ardent\Undercurrent\Http\RouterInterface; use Ardent\Undercurrent\Http\StatusEnum; use Ardent\Undercurrent\Logger\LogContainer; use Ardent\Undercurrent\Logger\LoggerInterface; -use Exception; class BaseKernel { - public function __invoke(): void + public function __construct( + private readonly string $rootDirectory, + ) { + } + + public function run(): void + { + $appConfig = new AppConfig($this->rootDirectory); + $container = (new GenericContainer()); $container ->alias(RouterInterface::class, GenericRouter::class) ->alias(ContainerInterface::class, GenericContainer::class) ->alias(LoggerInterface::class, LogContainer::class) ->add(GenericContainer::class, fn($container) => $container) + ->add(AppConfig::class, fn() => $appConfig) ->add(GenericRouter::class) ->add(LogContainer::class); |
|||
1aded029fc |
Add logger
diff --git a/src/Http/GenericRouter.php b/src/Http/GenericRouter.php index 334ecac..5a2ac6f 100644 --- a/src/Http/GenericRouter.php +++ b/src/Http/GenericRouter.php @@ -4,6 +4,7 @@ namespace Ardent\Undercurrent\Http; use Ardent\Undercurrent\Container\ClassNotFoundException; use Ardent\Undercurrent\Container\ContainerInterface; +use Ardent\Undercurrent\Logger\LoggerInterface; use Exception; use ReflectionMethod; @@ -11,6 +12,7 @@ class GenericRouter implements RouterInterface { public function __construct( private readonly ContainerInterface $container, + private readonly LoggerInterface $logger, private readonly RouterConfig $config, ) { @@ -28,6 +30,8 @@ class GenericRouter implements RouterInterface continue; } + $this->logger->add(sprintf('Matched route %s', $route->getRoute()->path)); + return $this->container->call( $route->getController(), $route->getMethod(), @@ -44,9 +48,9 @@ class GenericRouter implements RouterInterface return []; } - $result = preg_match_all('/{(\w+)}/', $routeUri, $tokens); + $result = preg_match_all('/{\w+}/', $routeUri, $tokens); - if (!$result) { + if (!$result === null) { return null; } @@ -59,6 +63,7 @@ class GenericRouter implements RouterInterface ) . '$/'; $result = preg_match($matchingRegex, $requestUri, $matches); + if (!$result) { return null; } diff --git a/src/Kernel/BaseKernel.php b/src/Kernel/BaseKernel.php index 634cafc..60164d8 100644 --- a/src/Kernel/BaseKernel.php +++ b/src/Kernel/BaseKernel.php @@ -5,10 +5,15 @@ namespace Ardent\Undercurrent\Kernel; use Ardent\Undercurrent\Container\ContainerInterface; use Ardent\Undercurrent\Container\GenericContainer; use Ardent\Undercurrent\Http\GenericRequest; +use Ardent\Undercurrent\Http\GenericResponse; use Ardent\Undercurrent\Http\GenericRouter; use Ardent\Undercurrent\Http\MethodEnum; use Ardent\Undercurrent\Http\RouterConfig; use Ardent\Undercurrent\Http\RouterInterface; +use Ardent\Undercurrent\Http\StatusEnum; +use Ardent\Undercurrent\Logger\LogContainer; +use Ardent\Undercurrent\Logger\LoggerInterface; +use Exception; class BaseKernel { @@ -18,8 +23,10 @@ class BaseKernel $container ->alias(RouterInterface::class, GenericRouter::class) ->alias(ContainerInterface::class, GenericContainer::class) + ->alias(LoggerInterface::class, LogContainer::class) ->add(GenericContainer::class, fn($container) => $container) - ->add(GenericRouter::class); + ->add(GenericRouter::class) + ->add(LogContainer::class); $this->dependencies($container); @@ -34,7 +41,20 @@ class BaseKernel $_REQUEST, ); $router = $container->get(RouterInterface::class); - $response = $router->dispatch($request); + $log = $container->get(LogContainer::class); + try { + $response = $router->dispatch($request); + } catch (\Throwable $e) { + $response = new GenericResponse( + $e->getMessage(), + StatusEnum::NOT_FOUND + ); + //$response = $container->get(RouterConfig::class)->getExceptionRoute()->getController()::exception($e); + } + + foreach ($log->getLogs() as $log) { + echo sprintf('<p>%s</p>', $log); + } http_response_code($response->getStatus()->value); diff --git a/src/Logger/LogContainer.php b/src/Logger/LogContainer.php new file mode 100644 index 0000000..39f3855 --- /dev/null +++ b/src/Logger/LogContainer.php @@ -0,0 +1,18 @@ +<?php + +namespace Ardent\Undercurrent\Logger; + +class LogContainer implements LoggerInterface +{ + private array $logs = []; + + public function add(string $log): void + { + $this->logs[] = $log; + } + + public function getLogs(): array + { + return $this->logs; + } +} \ No newline at end of file diff --git a/src/Logger/LoggerInterface.php b/src/Logger/LoggerInterface.php new file mode 100644 index 0000000..1b2867a --- /dev/null +++ b/src/Logger/LoggerInterface.php @@ -0,0 +1,8 @@ +<?php + +namespace Ardent\Undercurrent\Logger; + +interface LoggerInterface +{ + public function add(string $log): void; +} \ No newline at end of file |
|||
42c590dfd6 |
Finalize routing with injection and parameters
diff --git a/app/Controller/HelloWorldController.php b/app/Controller/HelloWorldController.php index 7f2af8b..86c5b8e 100644 --- a/app/Controller/HelloWorldController.php +++ b/app/Controller/HelloWorldController.php @@ -28,13 +28,13 @@ class HelloWorldController return new GenericResponse('Hello World!'); } - #[Route('/routes')] - public function routes(RouterConfig $config): ResponseInterface + #[Route('/routes/{word}')] + public function routes(RouterConfig $config, string $word): ResponseInterface { $routes = implode('<br>', array_map( - fn($route) => sprintf('%s - %s->%s', $route->getRoute()->path, $route->getController(), $route->getMethod()), - $config->getRoutes() - )); + fn($route) => sprintf('%s - %s->%s', $route->getRoute()->path, $route->getController(), $route->getMethod()), + $config->getRoutes() + )) . "<br>$word"; return new GenericResponse($routes); } diff --git a/src/Container/ContainerInterface.php b/src/Container/ContainerInterface.php index 7b55a94..5119eb5 100644 --- a/src/Container/ContainerInterface.php +++ b/src/Container/ContainerInterface.php @@ -19,4 +19,6 @@ interface ContainerInterface * @throws ClassNotFoundException */ public function get(string $className): object; + + public function call(string $className, string $methodName, array $parameters = []): mixed; } \ No newline at end of file diff --git a/src/Container/GenericContainer.php b/src/Container/GenericContainer.php index 8fdb26e..0e467b6 100644 --- a/src/Container/GenericContainer.php +++ b/src/Container/GenericContainer.php @@ -2,8 +2,10 @@ namespace Ardent\Undercurrent\Container; +use Ardent\Undercurrent\Http\RouteConfig; use Exception; use ReflectionClass; +use ReflectionMethod; class GenericContainer implements ContainerInterface { @@ -61,23 +63,39 @@ class GenericContainer implements ContainerInterface return $instance; } + public function call(string $className, string $methodName, array $parameters = []): mixed + { + $params = $this->methodParams($className, $methodName, $parameters) + $parameters; + return $this->get($className)->$methodName(...$params); + } + private function autowire(string $className): ?object { $reflection = new ReflectionClass($className); - $constructor = $reflection->getConstructor(); - if (!$constructor) { + $reflectionMethod = $reflection->getConstructor(); + if (!$reflectionMethod) { return new $className(); } + return new $className(...$this->methodParams($className, $reflectionMethod->getName())); + } + + private function methodParams(string $className, string $methodName, array $exceptParams = []): array + { + $reflectionMethod = new ReflectionMethod($className, $methodName); + $params = []; - foreach ($constructor->getParameters() as $parameter) { + foreach ($reflectionMethod->getParameters() as $parameter) { + if (in_array($parameter->getName(), array_keys($exceptParams))) { + continue; + } $type = $parameter->getType(); if (!$type) { - throw new Exception("Parameter {$parameter->getName()} in $className has no type"); + throw new Exception('Cannot autowire parameter without type'); } $params[] = $this->get($type->getName()); } - return new $className(...$params); + return $params; } } \ No newline at end of file diff --git a/src/Http/GenericRouter.php b/src/Http/GenericRouter.php index d5ffb95..334ecac 100644 --- a/src/Http/GenericRouter.php +++ b/src/Http/GenericRouter.php @@ -17,7 +17,7 @@ class GenericRouter implements RouterInterface } /** - * @throws RouteNotFoundException|ClassNotFoundException + * @throws RouteNotFoundException */ public function dispatch(RequestInterface $request): ResponseInterface { @@ -28,11 +28,11 @@ class GenericRouter implements RouterInterface continue; } - $controller = $this->container->get($route->getController()); - $method = $route->getMethod(); -// $params = $this->autowire($route) + $this->resolveParams($route->getRoute()->path, $request->getUri()); - $params = $this->resolveParams($route->getRoute()->path, $request->getUri()); - return $controller->$method(...$params); + return $this->container->call( + $route->getController(), + $route->getMethod(), + $params, + ); } throw new RouteNotFoundException($request); @@ -40,6 +40,10 @@ class GenericRouter implements RouterInterface private function resolveParams(string $routeUri, string $requestUri): ?array { + if ($routeUri === $requestUri) { + return []; + } + $result = preg_match_all('/{(\w+)}/', $routeUri, $tokens); if (!$result) { @@ -55,27 +59,11 @@ class GenericRouter implements RouterInterface ) . '$/'; $result = preg_match($matchingRegex, $requestUri, $matches); - if ($result === 0) { - return []; + if (!$result) { + return null; } $matches = array_slice($matches, 1); return array_combine(array_map(fn($token) => trim($token, '{}'), $tokens), $matches); } - - private function autowire(RouteConfig $route): array - { - $reflectionMethod = new ReflectionMethod($route->getController(), $route->getMethod()); - - $params = []; - foreach ($reflectionMethod->getParameters() as $parameter) { - $type = $parameter->getType(); - if (!$type) { - throw new Exception('Cannot autowire parameter without type'); - } - $params[] = $this->container->get($type->getName()); - } - - return $params; - } } \ No newline at end of file |
|||
2fd6e50b90 |
Start with controller parameter injection
diff --git a/src/Http/GenericRouter.php b/src/Http/GenericRouter.php index 23e9311..d5ffb95 100644 --- a/src/Http/GenericRouter.php +++ b/src/Http/GenericRouter.php @@ -22,16 +22,47 @@ class GenericRouter implements RouterInterface public function dispatch(RequestInterface $request): ResponseInterface { foreach ($this->config->getRoutes() as $route) { - if ($route->getRoute()->path === $request->getUri()) { - $controller = $this->container->get($route->getController()); - $method = $route->getMethod(); - return $controller->$method(...$this->autowire($route)); + $params = $this->resolveParams($route->getRoute()->path, $request->getUri()); + + if ($params === null) { + continue; } + + $controller = $this->container->get($route->getController()); + $method = $route->getMethod(); +// $params = $this->autowire($route) + $this->resolveParams($route->getRoute()->path, $request->getUri()); + $params = $this->resolveParams($route->getRoute()->path, $request->getUri()); + return $controller->$method(...$params); } throw new RouteNotFoundException($request); } + private function resolveParams(string $routeUri, string $requestUri): ?array + { + $result = preg_match_all('/{(\w+)}/', $routeUri, $tokens); + + if (!$result) { + return null; + } + + $tokens = $tokens[0]; + + $matchingRegex = '/^' . str_replace( + ['/', ...$tokens], + ['\/', ...array_fill(0, count($tokens), '([\w\s]+)')], + $routeUri + ) . '$/'; + + $result = preg_match($matchingRegex, $requestUri, $matches); + if ($result === 0) { + return []; + } + $matches = array_slice($matches, 1); + + return array_combine(array_map(fn($token) => trim($token, '{}'), $tokens), $matches); + } + private function autowire(RouteConfig $route): array { $reflectionMethod = new ReflectionMethod($route->getController(), $route->getMethod()); |
|||
64ff0c243d |
Add controller method autowiring
diff --git a/app/Controller/HelloWorldController.php b/app/Controller/HelloWorldController.php index 8361e9d..282a990 100644 --- a/app/Controller/HelloWorldController.php +++ b/app/Controller/HelloWorldController.php @@ -5,6 +5,7 @@ namespace App\Controller; use Ardent\Undercurrent\Attribute\Route; use Ardent\Undercurrent\Http\GenericResponse; use Ardent\Undercurrent\Http\ResponseInterface; +use Ardent\Undercurrent\Http\RouterConfig; use Ardent\Undercurrent\Http\StatusEnum; class HelloWorldController @@ -26,4 +27,21 @@ class HelloWorldController { return new GenericResponse('Hello World!'); } + + #[Route('/routes')] + public function routes(RouterConfig $config): ResponseInterface + { + $routes = implode('<br>', array_map( + fn($route) => $route->getRoute()->path, + $config->getRoutes() + )); + + return new GenericResponse($routes); + } + + #[Route('/world/{name}')] + public function world(string $name): ResponseInterface + { + return new GenericResponse("Hello $name!"); + } } \ No newline at end of file diff --git a/src/Http/GenericRouter.php b/src/Http/GenericRouter.php index b2d8e1d..23e9311 100644 --- a/src/Http/GenericRouter.php +++ b/src/Http/GenericRouter.php @@ -4,6 +4,8 @@ namespace Ardent\Undercurrent\Http; use Ardent\Undercurrent\Container\ClassNotFoundException; use Ardent\Undercurrent\Container\ContainerInterface; +use Exception; +use ReflectionMethod; class GenericRouter implements RouterInterface { @@ -23,10 +25,26 @@ class GenericRouter implements RouterInterface if ($route->getRoute()->path === $request->getUri()) { $controller = $this->container->get($route->getController()); $method = $route->getMethod(); - return $controller->$method(); + return $controller->$method(...$this->autowire($route)); } } throw new RouteNotFoundException($request); } + + private function autowire(RouteConfig $route): array + { + $reflectionMethod = new ReflectionMethod($route->getController(), $route->getMethod()); + + $params = []; + foreach ($reflectionMethod->getParameters() as $parameter) { + $type = $parameter->getType(); + if (!$type) { + throw new Exception('Cannot autowire parameter without type'); + } + $params[] = $this->container->get($type->getName()); + } + + return $params; + } } \ No newline at end of file |
|||
5d6ad29db8 |
Expand the response with headers and set status code
diff --git a/app/Controller/BaseController.php b/app/Controller/BaseController.php deleted file mode 100644 index 8e24148..0000000 --- a/app/Controller/BaseController.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -namespace App\Controller; - -use Ardent\Undercurrent\Attribute\Route; -use Ardent\Undercurrent\Http\GenericResponse; -use Ardent\Undercurrent\Http\ResponseInterface; - -class BaseController -{ - #[Route('/hello')] - public function helloWorld(): ResponseInterface - { - return new GenericResponse('Hello World!'); - } -} \ No newline at end of file diff --git a/app/Controller/HelloWorldController.php b/app/Controller/HelloWorldController.php new file mode 100644 index 0000000..8361e9d --- /dev/null +++ b/app/Controller/HelloWorldController.php @@ -0,0 +1,29 @@ +<?php + +namespace App\Controller; + +use Ardent\Undercurrent\Attribute\Route; +use Ardent\Undercurrent\Http\GenericResponse; +use Ardent\Undercurrent\Http\ResponseInterface; +use Ardent\Undercurrent\Http\StatusEnum; + +class HelloWorldController +{ + #[Route('/')] + public function index(): ResponseInterface + { + return new GenericResponse('Index, <a href="/hello">Hello</a>'); + } + + #[Route('/error')] + public function error(): ResponseInterface + { + return new GenericResponse('error', StatusEnum::NOT_FOUND); + } + + #[Route('/hello')] + public function hello(): ResponseInterface + { + return new GenericResponse('Hello World!'); + } +} \ No newline at end of file diff --git a/app/Kernel.php b/app/Kernel.php index a365d39..8b28577 100644 --- a/app/Kernel.php +++ b/app/Kernel.php @@ -2,7 +2,7 @@ namespace App; -use App\Controller\BaseController; +use App\Controller\HelloWorldController; use Ardent\Undercurrent\Container\ContainerInterface; use Ardent\Undercurrent\Kernel\BaseKernel; @@ -11,7 +11,7 @@ class Kernel extends BaseKernel protected function dependencies(ContainerInterface $container): void { $this->addControllers($container, [ - BaseController::class, + HelloWorldController::class, ]); } } \ No newline at end of file diff --git a/src/Container/ContainerInterface.php b/src/Container/ContainerInterface.php index bd50325..7b55a94 100644 --- a/src/Container/ContainerInterface.php +++ b/src/Container/ContainerInterface.php @@ -16,7 +16,7 @@ interface ContainerInterface * @template TClassName * @param class-string<TClassName> $className * @return TClassName - * @throws Exception + * @throws ClassNotFoundException */ public function get(string $className): object; } \ No newline at end of file diff --git a/src/Http/GenericResponse.php b/src/Http/GenericResponse.php index d80d350..18852ff 100644 --- a/src/Http/GenericResponse.php +++ b/src/Http/GenericResponse.php @@ -7,6 +7,7 @@ class GenericResponse implements ResponseInterface public function __construct( private readonly string $body, private readonly StatusEnum $status = StatusEnum::OK, + private readonly array $headers = [], ) { } @@ -20,4 +21,12 @@ class GenericResponse implements ResponseInterface { return $this->body; } + + /** + * @inheritDoc + */ + public function getHeaders(): array + { + return $this->headers; + } } \ No newline at end of file diff --git a/src/Http/GenericRouter.php b/src/Http/GenericRouter.php index 73ce8f1..b2d8e1d 100644 --- a/src/Http/GenericRouter.php +++ b/src/Http/GenericRouter.php @@ -2,9 +2,7 @@ namespace Ardent\Undercurrent\Http; -use App\Controller\BaseController; -use Ardent\Undercurrent\Attribute\Route; -use Ardent\Undercurrent\Collector\ClassAttributeCollector; +use Ardent\Undercurrent\Container\ClassNotFoundException; use Ardent\Undercurrent\Container\ContainerInterface; class GenericRouter implements RouterInterface @@ -16,6 +14,9 @@ class GenericRouter implements RouterInterface { } + /** + * @throws RouteNotFoundException|ClassNotFoundException + */ public function dispatch(RequestInterface $request): ResponseInterface { foreach ($this->config->getRoutes() as $route) { diff --git a/src/Http/ResponseInterface.php b/src/Http/ResponseInterface.php index abdc290..8047eb9 100644 --- a/src/Http/ResponseInterface.php +++ b/src/Http/ResponseInterface.php @@ -7,4 +7,9 @@ interface ResponseInterface public function getStatus(): StatusEnum; public function getBody(): string; + + /** + * @return array<string> + */ + public function getHeaders(): array; } \ No newline at end of file diff --git a/src/Kernel/BaseKernel.php b/src/Kernel/BaseKernel.php index 7122dcc..634cafc 100644 --- a/src/Kernel/BaseKernel.php +++ b/src/Kernel/BaseKernel.php @@ -33,9 +33,16 @@ class BaseKernel $_SERVER['REQUEST_URI'], $_REQUEST, ); - $router = $container->get(RouterInterface::class); - echo $router->dispatch($request)->getBody(); + $response = $router->dispatch($request); + + http_response_code($response->getStatus()->value); + + foreach ($response->getHeaders() as $header) { + header($header); + } + + echo $response->getBody(); } protected function addControllers(ContainerInterface $container, array $controllers): void |
|||
7c13318b9a | Introduce ClassNotFoundException for container | |||
a854480ff1 |
Implement basic version of route matching
Make RouteConfig more readable diff --git a/app/Kernel.php b/app/Kernel.php index 4425355..a365d39 100644 --- a/app/Kernel.php +++ b/app/Kernel.php @@ -10,7 +10,7 @@ class Kernel extends BaseKernel { protected function dependencies(ContainerInterface $container): void { - $this->addRoutes($container, [ + $this->addControllers($container, [ BaseController::class, ]); } diff --git a/src/Attribute/Route.php b/src/Attribute/Route.php index 6bbd272..7129654 100644 --- a/src/Attribute/Route.php +++ b/src/Attribute/Route.php @@ -2,13 +2,15 @@ namespace Ardent\Undercurrent\Attribute; +use Ardent\Undercurrent\Http\MethodEnum; use Attribute; #[Attribute] class Route { public function __construct( - public string $path, + public string $path, + public ?MethodEnum $method = null, ) { } diff --git a/src/Http/GenericRouter.php b/src/Http/GenericRouter.php index fa1bc6a..73ce8f1 100644 --- a/src/Http/GenericRouter.php +++ b/src/Http/GenericRouter.php @@ -11,15 +11,21 @@ class GenericRouter implements RouterInterface { public function __construct( private readonly ContainerInterface $container, - private readonly RouterConfig $config, + private readonly RouterConfig $config, ) { } public function dispatch(RequestInterface $request): ResponseInterface { - $controller = $this->container->get(BaseController::class); - $method = 'helloWorld'; - return $controller->$method(); + foreach ($this->config->getRoutes() as $route) { + if ($route->getRoute()->path === $request->getUri()) { + $controller = $this->container->get($route->getController()); + $method = $route->getMethod(); + return $controller->$method(); + } + } + + throw new RouteNotFoundException($request); } } \ No newline at end of file diff --git a/src/Http/RouteConfig.php b/src/Http/RouteConfig.php new file mode 100644 index 0000000..00c2cb0 --- /dev/null +++ b/src/Http/RouteConfig.php @@ -0,0 +1,31 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +use Ardent\Undercurrent\Attribute\Route; + +class RouteConfig +{ + public function __construct( + private readonly Route $route, + private readonly string $controller, + private readonly string $method + ) + { + } + + public function getRoute(): Route + { + return $this->route; + } + + public function getController(): string + { + return $this->controller; + } + + public function getMethod(): string + { + return $this->method; + } +} \ No newline at end of file diff --git a/src/Http/RouteNotFoundException.php b/src/Http/RouteNotFoundException.php new file mode 100644 index 0000000..081c625 --- /dev/null +++ b/src/Http/RouteNotFoundException.php @@ -0,0 +1,16 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +use Exception; + +class RouteNotFoundException extends Exception +{ + public function __construct(RequestInterface $request) + { + parent::__construct(sprintf( + 'No controller found for uri: %s', + $request->getUri() + )); + } +} \ No newline at end of file diff --git a/src/Http/RouterConfig.php b/src/Http/RouterConfig.php index 60e5af7..eec5cde 100644 --- a/src/Http/RouterConfig.php +++ b/src/Http/RouterConfig.php @@ -2,16 +2,45 @@ namespace Ardent\Undercurrent\Http; +use Ardent\Undercurrent\Attribute\Route; +use ReflectionAttribute; +use ReflectionClass; + class RouterConfig { - public function __construct( - private readonly array $controllers = [], - ) + /** + * @var array<RouteConfig> + */ + private array $routes = []; + + public function addController(string $controller): self { + $reflectionClass = new ReflectionClass($controller); + + foreach ($reflectionClass->getMethods() as $method) { + $attributes = $method->getAttributes(Route::class, ReflectionAttribute::IS_INSTANCEOF); + + if (count($attributes) === 0) { + continue; + } + + $route = $attributes[0]->newInstance(); + + $this->routes[] = new RouteConfig( + $route, + $controller, + $method->getName(), + ); + } + + return $this; } - public function getControllers(): array + /** + * @return array<RouteConfig> + */ + public function getRoutes(): array { - return $this->controllers; + return $this->routes; } } \ No newline at end of file diff --git a/src/Kernel/BaseKernel.php b/src/Kernel/BaseKernel.php index 149aa8b..7122dcc 100644 --- a/src/Kernel/BaseKernel.php +++ b/src/Kernel/BaseKernel.php @@ -38,13 +38,16 @@ class BaseKernel echo $router->dispatch($request)->getBody(); } - protected function addRoutes(ContainerInterface $container, array $routes): void + protected function addControllers(ContainerInterface $container, array $controllers): void { - foreach ($routes as $route) { - $container->add($route); + $config = new RouterConfig(); + + foreach ($controllers as $controller) { + $container->add($controller); + $config->addController($controller); } - $container->add(RouterConfig::class, fn() => new RouterConfig($routes)); + $container->add(RouterConfig::class, fn() => $config); } protected function dependencies(ContainerInterface $container): void |
|||
96e833fb4b |
Move route config to app
diff --git a/app/Kernel.php b/app/Kernel.php index 0e8e047..4425355 100644 --- a/app/Kernel.php +++ b/app/Kernel.php @@ -2,8 +2,16 @@ namespace App; +use App\Controller\BaseController; +use Ardent\Undercurrent\Container\ContainerInterface; use Ardent\Undercurrent\Kernel\BaseKernel; class Kernel extends BaseKernel { + protected function dependencies(ContainerInterface $container): void + { + $this->addRoutes($container, [ + BaseController::class, + ]); + } } \ No newline at end of file diff --git a/src/Http/RouterConfig.php b/src/Http/RouterConfig.php index ad856d6..60e5af7 100644 --- a/src/Http/RouterConfig.php +++ b/src/Http/RouterConfig.php @@ -4,7 +4,6 @@ namespace Ardent\Undercurrent\Http; class RouterConfig { - public function __construct( private readonly array $controllers = [], ) diff --git a/src/Kernel/BaseKernel.php b/src/Kernel/BaseKernel.php index a6732f4..149aa8b 100644 --- a/src/Kernel/BaseKernel.php +++ b/src/Kernel/BaseKernel.php @@ -2,7 +2,6 @@ namespace Ardent\Undercurrent\Kernel; -use App\Controller\BaseController; use Ardent\Undercurrent\Container\ContainerInterface; use Ardent\Undercurrent\Container\GenericContainer; use Ardent\Undercurrent\Http\GenericRequest; @@ -20,12 +19,9 @@ class BaseKernel ->alias(RouterInterface::class, GenericRouter::class) ->alias(ContainerInterface::class, GenericContainer::class) ->add(GenericContainer::class, fn($container) => $container) - ->add(GenericRouter::class) - ->add(BaseController::class); + ->add(GenericRouter::class); - $container->add(RouterConfig::class, fn() => new RouterConfig([ - BaseController::class, - ])); + $this->dependencies($container); $this->render($container); } @@ -41,4 +37,17 @@ class BaseKernel $router = $container->get(RouterInterface::class); echo $router->dispatch($request)->getBody(); } + + protected function addRoutes(ContainerInterface $container, array $routes): void + { + foreach ($routes as $route) { + $container->add($route); + } + + $container->add(RouterConfig::class, fn() => new RouterConfig($routes)); + } + + protected function dependencies(ContainerInterface $container): void + { + } } \ No newline at end of file |
|||
a55d1c3c2e |
Properly implement the router with config and interfaces
Expand the container with aliases and argument autowiring |
|||
e9a636554f |
Add response and request objects and interfaces
diff --git a/README.md b/README.md index 4b64da1..c860957 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ Todos: - [ ] Collect routes properly - [ ] Process routes correctly +- [ ] Add request and response objects diff --git a/app/Controller/BaseController.php b/app/Controller/BaseController.php index aa0a79b..7df9387 100644 --- a/app/Controller/BaseController.php +++ b/app/Controller/BaseController.php @@ -3,12 +3,14 @@ namespace App\Controller; use Ardent\Undercurrent\Attribute\Route; +use Ardent\Undercurrent\Http\GenericResponse; +use Ardent\Undercurrent\Http\ResponseInterface; class BaseController { #[Route('/hello')] - public function HelloWorld(): string + public function HelloWorld(): ResponseInterface { - return 'Hello, World!'; + return new GenericResponse('Hello World!'); } } \ No newline at end of file diff --git a/src/Http/GenericRequest.php b/src/Http/GenericRequest.php new file mode 100644 index 0000000..c758a40 --- /dev/null +++ b/src/Http/GenericRequest.php @@ -0,0 +1,30 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +class GenericRequest implements RequestInterface +{ + + public function __construct( + private readonly MethodEnum $method, + private readonly string $uri, + private readonly array $body, + ) + { + } + + public function getMethod(): MethodEnum + { + return $this->method; + } + + public function getUri(): string + { + return $this->uri; + } + + public function getBody(): array + { + return $this->body; + } +} \ No newline at end of file diff --git a/src/Http/GenericResponse.php b/src/Http/GenericResponse.php new file mode 100644 index 0000000..d80d350 --- /dev/null +++ b/src/Http/GenericResponse.php @@ -0,0 +1,23 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +class GenericResponse implements ResponseInterface +{ + public function __construct( + private readonly string $body, + private readonly StatusEnum $status = StatusEnum::OK, + ) + { + } + + public function getStatus(): StatusEnum + { + return $this->status; + } + + public function getBody(): string + { + return $this->body; + } +} \ No newline at end of file diff --git a/src/Controller/GenericRouter.php b/src/Http/GenericRouter.php similarity index 89% rename from src/Controller/GenericRouter.php rename to src/Http/GenericRouter.php index 28f75b1..0332ce5 100644 --- a/src/Controller/GenericRouter.php +++ b/src/Http/GenericRouter.php @@ -1,6 +1,6 @@ <?php -namespace Ardent\Undercurrent\Controller; +namespace Ardent\Undercurrent\Http; use App\Controller\BaseController; use Ardent\Undercurrent\Attribute\Route; diff --git a/src/Http/MethodEnum.php b/src/Http/MethodEnum.php new file mode 100644 index 0000000..76948c9 --- /dev/null +++ b/src/Http/MethodEnum.php @@ -0,0 +1,16 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +enum MethodEnum: string +{ + case GET = 'GET'; + case POST = 'POST'; +// case PUT = 'PUT'; +// case PATCH = 'PATCH'; +// case DELETE = 'DELETE'; +// case HEAD = 'HEAD'; +// case OPTIONS = 'OPTIONS'; +// case TRACE = 'TRACE'; +// case CONNECT = 'CONNECT'; +} diff --git a/src/Http/RequestInterface.php b/src/Http/RequestInterface.php new file mode 100644 index 0000000..0f564b8 --- /dev/null +++ b/src/Http/RequestInterface.php @@ -0,0 +1,12 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +interface RequestInterface +{ + public function getMethod(): MethodEnum; + + public function getUri(): string; + + public function getBody(): array; +} \ No newline at end of file diff --git a/src/Http/ResponseInterface.php b/src/Http/ResponseInterface.php new file mode 100644 index 0000000..abdc290 --- /dev/null +++ b/src/Http/ResponseInterface.php @@ -0,0 +1,10 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +interface ResponseInterface +{ + public function getStatus(): StatusEnum; + + public function getBody(): string; +} \ No newline at end of file diff --git a/src/Http/RouterInterface.php b/src/Http/RouterInterface.php new file mode 100644 index 0000000..186baac --- /dev/null +++ b/src/Http/RouterInterface.php @@ -0,0 +1,8 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +interface RouterInterface +{ + public function dispatch(RequestInterface $request): ResponseInterface; +} \ No newline at end of file diff --git a/src/Http/StatusEnum.php b/src/Http/StatusEnum.php new file mode 100644 index 0000000..6dce100 --- /dev/null +++ b/src/Http/StatusEnum.php @@ -0,0 +1,10 @@ +<?php + +namespace Ardent\Undercurrent\Http; + +enum StatusEnum: int +{ + case OK = 200; + case FORBIDDEN = 403; + case NOT_FOUND = 404; +} diff --git a/src/Kernel/BaseKernel.php b/src/Kernel/BaseKernel.php index 6bc8ed5..05ecf06 100644 --- a/src/Kernel/BaseKernel.php +++ b/src/Kernel/BaseKernel.php @@ -4,11 +4,12 @@ namespace Ardent\Undercurrent\Kernel; use App\Controller\BaseController; use Ardent\Undercurrent\Container\GenericContainer; -use Ardent\Undercurrent\Controller\GenericRouter; +use Ardent\Undercurrent\Http\GenericRouter; +use Ardent\Undercurrent\Http\ResponseInterface; class BaseKernel { - public function __invoke() + public function __invoke(): void { $container = new GenericContainer(); $container->add(GenericRouter::class); @@ -23,6 +24,6 @@ class BaseKernel $route = $router->getRoute($_SERVER['REQUEST_URI']); $controller = $container->get($route['controller']); $method = $route['method']; - echo $controller->$method(); + echo $controller->$method()->getBody(); } } \ No newline at end of file |
|||
503d8c524a | First working version with non working routes |