diff --git a/composer.json b/composer.json index 9a3617f..47f02dc 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ }, "require": { "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "dotkernel/dot-controller": "^4.0.1", "dotkernel/dot-errorhandler": "^4.1.1", "laminas/laminas-component-installer": "^3.5.0", "laminas/laminas-config-aggregator": "^1.17.0", diff --git a/config/autoload/local.php.dist b/config/autoload/local.php.dist index 5b50b90..7dba947 100644 --- a/config/autoload/local.php.dist +++ b/config/autoload/local.php.dist @@ -15,4 +15,10 @@ return [ 'application' => [ 'url' => $baseUrl, ], + 'routes' => [ + 'page' => [ + 'about' => 'about', + 'who-we-are' => 'who-we-are', + ], + ], ]; diff --git a/src/App/src/ConfigProvider.php b/src/App/src/ConfigProvider.php index 5c068ff..e9697a2 100644 --- a/src/App/src/ConfigProvider.php +++ b/src/App/src/ConfigProvider.php @@ -4,6 +4,10 @@ namespace Light\App; +use Light\App\Factory\IndexHandlerFactory; +use Light\App\Handler\IndexHandler; +use Mezzio\Application; + class ConfigProvider { public function __invoke(): array @@ -16,7 +20,16 @@ public function __invoke(): array public function getDependencies(): array { - return []; + return [ + 'delegators' => [ + Application::class => [ + RoutesDelegator::class, + ], + ], + 'factories' => [ + IndexHandler::class => IndexHandlerFactory::class, + ], + ]; } public function getTemplates(): array diff --git a/src/App/src/Factory/IndexHandlerFactory.php b/src/App/src/Factory/IndexHandlerFactory.php new file mode 100644 index 0000000..2bccc6a --- /dev/null +++ b/src/App/src/Factory/IndexHandlerFactory.php @@ -0,0 +1,29 @@ +get(TemplateRendererInterface::class); + assert($template instanceof TemplateRendererInterface); + + return new IndexHandler($template); + } +} diff --git a/src/App/src/Handler/IndexHandler.php b/src/App/src/Handler/IndexHandler.php new file mode 100644 index 0000000..8275400 --- /dev/null +++ b/src/App/src/Handler/IndexHandler.php @@ -0,0 +1,26 @@ +template->render('app::index') + ); + } +} diff --git a/src/App/src/RoutesDelegator.php b/src/App/src/RoutesDelegator.php new file mode 100644 index 0000000..1aa2ae2 --- /dev/null +++ b/src/App/src/RoutesDelegator.php @@ -0,0 +1,24 @@ +get('/', [IndexHandler::class], 'app::index'); + + return $app; + } +} diff --git a/src/App/templates/app/home.html.twig b/src/App/templates/app/index.html.twig similarity index 100% rename from src/App/templates/app/home.html.twig rename to src/App/templates/app/index.html.twig diff --git a/src/App/templates/error/403.html.twig b/src/App/templates/error/403.html.twig deleted file mode 100644 index 2e0324a..0000000 --- a/src/App/templates/error/403.html.twig +++ /dev/null @@ -1,17 +0,0 @@ -{% extends '@layout/default.html.twig' %} - -{% block title %}403 Forbidden{% endblock %} - -{% block content %} -
-
-

Oops!

-

This is awkward.

-

You don't have enough permissions to access the requested content!

-

- You are looking for something that doesn't exist or may have moved. Check out one of the links on this page - or head back to Home. -

-
-
-{% endblock %} diff --git a/src/App/templates/error/404.html.twig b/src/App/templates/error/404.html.twig index 4578393..c13e27b 100644 --- a/src/App/templates/error/404.html.twig +++ b/src/App/templates/error/404.html.twig @@ -9,9 +9,9 @@

Oops!

This is awkward.

404

-

+

You are looking for something that doesn't exist or may have moved. Check out one of the links on this page - or head back to Home. + or head back to Home.

diff --git a/src/App/templates/error/error.html.twig b/src/App/templates/error/error.html.twig index b42b77a..6b64993 100644 --- a/src/App/templates/error/error.html.twig +++ b/src/App/templates/error/error.html.twig @@ -1,6 +1,7 @@ {% extends '@layout/default.html.twig' %} {% block title %}{{ status }} {{ reason }}{% endblock %} +{% block canonical %}{% endblock %} {% block content %}
@@ -9,12 +10,6 @@

This is awkward.

{{ status }}

{{ reason }}

- {% if status == 404 %} -

- You are looking for something that doesn't exist or may have moved. Check out one of the links on this page - or head back to Home. -

- {% endif %}
{% endblock %} diff --git a/src/App/templates/layout/default.html.twig b/src/App/templates/layout/default.html.twig index 22e499f..6574cb3 100644 --- a/src/App/templates/layout/default.html.twig +++ b/src/App/templates/layout/default.html.twig @@ -6,9 +6,7 @@ {% block title %}{% endblock %} | Dotkernel Light V1 - {% block canonical %} - - {% endblock %} + {% block canonical %}{% endblock %} @@ -46,16 +44,15 @@ diff --git a/src/Page/src/ConfigProvider.php b/src/Page/src/ConfigProvider.php index c4b7455..ef99a6b 100644 --- a/src/Page/src/ConfigProvider.php +++ b/src/Page/src/ConfigProvider.php @@ -4,9 +4,10 @@ namespace Light\Page; -use Light\Page\Controller\PageController; -use Light\Page\Factory\PageControllerFactory; +use Light\Page\Factory\PageHandlerFactory; use Light\Page\Factory\PageServiceFactory; +use Light\Page\Handler\PageHandler; +use Light\Page\RoutesDelegator; use Light\Page\Service\PageService; use Light\Page\Service\PageServiceInterface; use Mezzio\Application; @@ -30,8 +31,8 @@ public function getDependencies(): array ], ], 'factories' => [ - PageController::class => PageControllerFactory::class, - PageService::class => PageServiceFactory::class, + PageHandler::class => PageHandlerFactory::class, + PageService::class => PageServiceFactory::class, ], 'aliases' => [ PageServiceInterface::class => PageService::class, diff --git a/src/Page/src/Controller/PageController.php b/src/Page/src/Controller/PageController.php deleted file mode 100644 index e0438cf..0000000 --- a/src/Page/src/Controller/PageController.php +++ /dev/null @@ -1,50 +0,0 @@ -template->render('app::home') - ); - } - - public function homeAction(): ResponseInterface - { - return new HtmlResponse( - $this->template->render('app::home', ['routeName' => 'home']) - ); - } - - public function aboutUsAction(): ResponseInterface - { - return new HtmlResponse( - $this->template->render('page::about') - ); - } - - public function whoWeAreAction(): ResponseInterface - { - return new HtmlResponse( - $this->template->render('page::who-we-are') - ); - } -} diff --git a/src/Page/src/Factory/PageControllerFactory.php b/src/Page/src/Factory/PageHandlerFactory.php similarity index 53% rename from src/Page/src/Factory/PageControllerFactory.php rename to src/Page/src/Factory/PageHandlerFactory.php index 740ae6c..e571d7f 100644 --- a/src/Page/src/Factory/PageControllerFactory.php +++ b/src/Page/src/Factory/PageHandlerFactory.php @@ -4,9 +4,7 @@ namespace Light\Page\Factory; -use Light\Page\Controller\PageController; -use Light\Page\Service\PageServiceInterface; -use Mezzio\Router\RouterInterface; +use Light\Page\Handler\PageHandler; use Mezzio\Template\TemplateRendererInterface; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; @@ -14,23 +12,18 @@ use function assert; -class PageControllerFactory +class PageHandlerFactory { /** + * @param class-string $requestedName * @throws NotFoundExceptionInterface * @throws ContainerExceptionInterface */ - public function __invoke(ContainerInterface $container, string $requestedName): PageController + public function __invoke(ContainerInterface $container, string $requestedName): PageHandler { - $pageService = $container->get(PageServiceInterface::class); - assert($pageService instanceof PageServiceInterface); - - $router = $container->get(RouterInterface::class); - assert($router instanceof RouterInterface); - $template = $container->get(TemplateRendererInterface::class); assert($template instanceof TemplateRendererInterface); - return new PageController($pageService, $router, $template); + return new PageHandler($template); } } diff --git a/src/Page/src/Factory/PageServiceFactory.php b/src/Page/src/Factory/PageServiceFactory.php index 92ca84b..61c26c4 100644 --- a/src/Page/src/Factory/PageServiceFactory.php +++ b/src/Page/src/Factory/PageServiceFactory.php @@ -10,6 +10,9 @@ class PageServiceFactory { + /** + * @param class-string $requestedName + */ public function __invoke(ContainerInterface $container, string $requestedName): PageServiceInterface { return new PageService(); diff --git a/src/Page/src/Handler/PageHandler.php b/src/Page/src/Handler/PageHandler.php new file mode 100644 index 0000000..6cb7b14 --- /dev/null +++ b/src/Page/src/Handler/PageHandler.php @@ -0,0 +1,29 @@ +getAttribute(RouteResult::class)->getMatchedRouteName(); + + return new HtmlResponse( + $this->template->render($template) + ); + } +} diff --git a/src/Page/src/RoutesDelegator.php b/src/Page/src/RoutesDelegator.php index 0bb5de5..40ebe63 100644 --- a/src/Page/src/RoutesDelegator.php +++ b/src/Page/src/RoutesDelegator.php @@ -4,22 +4,36 @@ namespace Light\Page; -use Light\Page\Controller\PageController; +use Light\Page\Handler\PageHandler; use Mezzio\Application; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use function assert; +use function sprintf; class RoutesDelegator { + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application { $app = $callback(); assert($app instanceof Application); - $app->get('/', [PageController::class], 'home'); - - $app->get('/page[/{action}]', [PageController::class], 'page'); + $routes = $container->get('config')['routes'] ?? []; + foreach ($routes as $moduleName => $moduleRoutes) { + foreach ($moduleRoutes as $routeUri => $templateName) { + $app->get( + sprintf('/%s/%s', $moduleName, $routeUri), + [PageHandler::class], + sprintf('%s::%s', $moduleName, $templateName) + ); + } + } return $app; } diff --git a/test/Unit/App/ConfigProviderTest.php b/test/Unit/App/ConfigProviderTest.php index f01fc1d..3b34e27 100644 --- a/test/Unit/App/ConfigProviderTest.php +++ b/test/Unit/App/ConfigProviderTest.php @@ -5,6 +5,7 @@ namespace LightTest\Unit\App; use Light\App\ConfigProvider; +use Light\App\Handler\IndexHandler; use PHPUnit\Framework\TestCase; class ConfigProviderTest extends TestCase @@ -23,6 +24,13 @@ public function testConfigHasDependencies(): void $this->assertArrayHasKey('dependencies', $this->config); } + public function testDependenciesHasFactories(): void + { + $this->assertArrayHasKey('factories', $this->config['dependencies']); + $this->assertIsArray($this->config['dependencies']['factories']); + $this->assertArrayHasKey(IndexHandler::class, $this->config['dependencies']['factories']); + } + public function testConfigHasTemplates(): void { $this->assertArrayHasKey('templates', $this->config); diff --git a/test/Unit/Page/ConfigProviderTest.php b/test/Unit/Page/ConfigProviderTest.php index 0b5d254..12f8aee 100644 --- a/test/Unit/Page/ConfigProviderTest.php +++ b/test/Unit/Page/ConfigProviderTest.php @@ -5,7 +5,6 @@ namespace LightTest\Unit\Page; use Light\Page\ConfigProvider; -use Light\Page\Controller\PageController; use Light\Page\RoutesDelegator; use Light\Page\Service\PageService; use Light\Page\Service\PageServiceInterface; @@ -49,7 +48,6 @@ public function testDependenciesHasFactories(): void { $this->assertArrayHasKey('factories', $this->config['dependencies']); $this->assertIsArray($this->config['dependencies']['factories']); - $this->assertArrayHasKey(PageController::class, $this->config['dependencies']['factories']); $this->assertArrayHasKey(PageService::class, $this->config['dependencies']['factories']); } diff --git a/test/Unit/Page/Handler/PageHandlerTest.php b/test/Unit/Page/Handler/PageHandlerTest.php new file mode 100644 index 0000000..272cba9 --- /dev/null +++ b/test/Unit/Page/Handler/PageHandlerTest.php @@ -0,0 +1,59 @@ +createMock(PageHandler::class); + + $this->assertContainsOnlyInstancesOf(RequestHandlerInterface::class, [$handler]); + } + + /** + * @throws Exception + */ + public function testHandle(): void + { + $routeName = 'test_route_name'; + $request = $this->createMock(ServerRequestInterface::class); + $template = $this->createMock(TemplateRendererInterface::class); + $routeResult = $this->createMock(RouteResult::class); + + $routeResult + ->method('getMatchedRouteName') + ->willReturn($routeName); + + $request + ->method('getAttribute') + ->with(RouteResult::class) + ->willReturn($routeResult); + + $template + ->method('render') + ->with($routeName) + ->willReturn('

' . $routeName . '

'); + + $handler = new PageHandler($template); + + $response = $handler->handle($request); + + $this->assertInstanceOf(HtmlResponse::class, $response); + $this->assertSame('

' . $routeName . '

', $response->getBody()->getContents()); + } +} diff --git a/test/Unit/Page/RoutesDelegatorTest.php b/test/Unit/Page/RoutesDelegatorTest.php index 89a14b7..9acf195 100644 --- a/test/Unit/Page/RoutesDelegatorTest.php +++ b/test/Unit/Page/RoutesDelegatorTest.php @@ -4,12 +4,16 @@ namespace LightTest\Unit\Page; +use Light\Page\Handler\PageHandler; use Light\Page\RoutesDelegator; use Mezzio\Application; +use Mezzio\Router\Route; use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use function sprintf; + class RoutesDelegatorTest extends TestCase { /** @@ -17,11 +21,37 @@ class RoutesDelegatorTest extends TestCase */ public function testWillInvoke(): void { - $application = (new RoutesDelegator())( - $this->createMock(ContainerInterface::class), + $moduleName = 'test'; + $routeName = 'test_route_name'; + $routeUri = sprintf('/%s/%s', $moduleName, $routeName); + $templateName = sprintf('%s::%s', $moduleName, $routeName); + + $container = $this->createMock(ContainerInterface::class); + $app = $this->createMock(Application::class); + + $app->method('get')->willReturn($this->createMock(Route::class)); + $app + ->expects($this->exactly(1)) + ->method('get') + ->willReturnCallback(function (...$args) use ($routeUri, $templateName) { + $this->assertSame($routeUri, $args[0]); + $this->assertSame([[PageHandler::class]], [$args[1]]); + $this->assertSame($templateName, $args[2]); + }); + + $container->method('get')->with('config')->willReturn([ + 'routes' => [ + $moduleName => [ + $routeName => $routeName, + ], + ], + ]); + + $application = (new RoutesDelegator())( + $container, '', - function () { - return $this->createMock(Application::class); + $callback = function () use ($app) { + return $app; } );