Skip to content

Commit 8ce0573

Browse files
committed
replaced controllers with handlers & unit tests
1 parent 14cbf0c commit 8ce0573

File tree

10 files changed

+130
-44
lines changed

10 files changed

+130
-44
lines changed

config/autoload/local.php.dist

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@ return [
1515
'application' => [
1616
'url' => $baseUrl,
1717
],
18+
'routes' => [
19+
'page' => [
20+
'about' => 'about',
21+
'who-we-are' => 'who-we-are',
22+
],
23+
],
1824
];

config/autoload/mezzio.global.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// generating responses.
1919
'error_handler' => [
2020
'template_404' => 'error::404',
21-
'template_error' => 'error::500',
21+
'template_error' => 'error::error',
2222
],
2323
],
2424
];

src/App/src/RoutesDelegator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function __invoke(ContainerInterface $container, string $serviceName, cal
1717
$app = $callback();
1818
assert($app instanceof Application);
1919

20-
$app->get('/', [IndexHandler::class], 'app.index');
20+
$app->get('/', [IndexHandler::class], 'app::index');
2121

2222
return $app;
2323
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{% extends '@layout/default.html.twig' %}
22

3-
{% block title %}500 Internal Server Error{% endblock %}
3+
{% block title %}{{ status }} {{ reason }}{% endblock %}
44
{% block canonical %}{% endblock %}
55

66
{% block content %}
77
<div class="page-intro home-intro error-messages">
88
<div class="container">
99
<h2>Oops!</h2>
1010
<h2>This is awkward.</h2>
11-
<h1>500</h1>
11+
<h1>{{ status }}</h1>
1212
<h2 class="message">{{ reason }}</h2>
1313
</div>
1414
</div>

src/App/templates/layout/default.html.twig

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@
66
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
77

88
<title>{% block title %}{% endblock %} | Dotkernel Light V1</title>
9-
{% block canonical %}
10-
{% if routeName is defined and routeName is not empty %}
11-
<link rel="canonical" href="{{ url(routeName) }}" />
12-
{% endif %}
13-
{% endblock %}
9+
{% block canonical %}<link rel="canonical" href="{{ url(routeName ?? null) }}" />{% endblock %}
1410

1511
<link rel="apple-touch-icon" sizes="180x180" href="{{ asset('images/app/favicon/apple-touch-icon.png') }}">
1612
<link rel="icon" type="image/png" sizes="32x32" href="{{ asset('images/app/favicon/favicon-32x32.png') }}">
@@ -48,16 +44,15 @@
4844
<li class="nav-item dropdown">
4945
<a class="nav-link dropdown-toggle" href="#" id="pageDropdown" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Pages</a>
5046
<div class="dropdown-menu" aria-labelledby="pageDropdown">
51-
<a class="dropdown-item" href="{{ url('app.index') }}">Home</a>
52-
<a class="dropdown-item" href="{{ url('page', {action: 'about-us'}) }}">About Us</a>
53-
<a class="dropdown-item" href="{{ url('page', {action: 'who-we-are'}) }}">Who We Are</a>
47+
<a class="dropdown-item" href="{{ url('page::about') }}">About Us</a>
48+
<a class="dropdown-item" href="{{ url('page::who-we-are') }}">Who We Are</a>
5449
</div>
5550
</li>
5651
<li class="nav-item">
5752
<a class="nav-link" href="https://github.com/dotkernel/light/" target="_blank">GitHub</a>
5853
</li>
5954
<li class="nav-item">
60-
<a class="nav-link disabled" href="{{ url('app.index') }}">Disabled</a>
55+
<a class="nav-link disabled" href="{{ url('app::index') }}">Disabled</a>
6156
</li>
6257
</ul>
6358
</div>

src/Page/src/Factory/PageHandlerFactory.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Light\Page\Factory;
66

77
use Light\Page\Handler\PageHandler;
8-
use Mezzio\Handler\NotFoundHandler;
98
use Mezzio\Template\TemplateRendererInterface;
109
use Psr\Container\ContainerExceptionInterface;
1110
use Psr\Container\ContainerInterface;
@@ -24,9 +23,6 @@ public function __invoke(ContainerInterface $container, string $requestedName):
2423
$template = $container->get(TemplateRendererInterface::class);
2524
assert($template instanceof TemplateRendererInterface);
2625

27-
$notFoundHandler = $container->get(NotFoundHandler::class);
28-
assert($notFoundHandler instanceof NotFoundHandler);
29-
30-
return new PageHandler($template, $notFoundHandler);
26+
return new PageHandler($template);
3127
}
3228
}

src/Page/src/Handler/PageHandler.php

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,25 @@
55
namespace Light\Page\Handler;
66

77
use Laminas\Diactoros\Response\HtmlResponse;
8-
use Mezzio\Handler\NotFoundHandler;
8+
use Mezzio\Router\RouteResult;
99
use Mezzio\Template\TemplateRendererInterface;
1010
use Psr\Http\Message\ResponseInterface;
1111
use Psr\Http\Message\ServerRequestInterface;
1212
use Psr\Http\Server\RequestHandlerInterface;
13-
use Twig\Error\LoaderError;
1413

1514
class PageHandler implements RequestHandlerInterface
1615
{
1716
public function __construct(
1817
protected TemplateRendererInterface $template,
19-
protected NotFoundHandler $notFoundHandler,
2018
) {
2119
}
2220

2321
public function handle(ServerRequestInterface $request): ResponseInterface
2422
{
25-
$actionTemplateMapping = [
26-
'about-us' => 'page::about',
27-
'who-we-are' => 'page::who-we-are',
28-
];
23+
$template = $request->getAttribute(RouteResult::class)->getMatchedRouteName();
2924

30-
$action = $request->getAttribute('action', 'index');
31-
32-
$template = $actionTemplateMapping[$action] ?? null;
33-
if (null === $template) {
34-
return $this->notFoundHandler->handle($request);
35-
}
36-
37-
try {
38-
return new HtmlResponse(
39-
$this->template->render($template)
40-
);
41-
} catch (LoaderError) {
42-
return $this->notFoundHandler->handle($request);
43-
}
25+
return new HtmlResponse(
26+
$this->template->render($template)
27+
);
4428
}
4529
}

src/Page/src/RoutesDelegator.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,34 @@
66

77
use Light\Page\Handler\PageHandler;
88
use Mezzio\Application;
9+
use Psr\Container\ContainerExceptionInterface;
910
use Psr\Container\ContainerInterface;
11+
use Psr\Container\NotFoundExceptionInterface;
1012

1113
use function assert;
14+
use function sprintf;
1215

1316
class RoutesDelegator
1417
{
18+
/**
19+
* @throws ContainerExceptionInterface
20+
* @throws NotFoundExceptionInterface
21+
*/
1522
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
1623
{
1724
$app = $callback();
1825
assert($app instanceof Application);
1926

20-
$app->get('/page[/{action}]', [PageHandler::class], 'page');
27+
$routes = $container->get('config')['routes'] ?? [];
28+
foreach ($routes as $moduleName => $moduleRoutes) {
29+
foreach ($moduleRoutes as $routeUri => $templateName) {
30+
$app->get(
31+
sprintf('/%s/%s', $moduleName, $routeUri),
32+
[PageHandler::class],
33+
sprintf('%s::%s', $moduleName, $templateName)
34+
);
35+
}
36+
}
2137

2238
return $app;
2339
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace LightTest\Unit\Page\Handler;
6+
7+
use Laminas\Diactoros\Response\HtmlResponse;
8+
use Light\Page\Handler\PageHandler;
9+
use Mezzio\Router\RouteResult;
10+
use Mezzio\Template\TemplateRendererInterface;
11+
use PHPUnit\Framework\MockObject\Exception;
12+
use PHPUnit\Framework\TestCase;
13+
use Psr\Http\Message\ServerRequestInterface;
14+
use Psr\Http\Server\RequestHandlerInterface;
15+
16+
class PageHandlerTest extends TestCase
17+
{
18+
/**
19+
* @throws Exception
20+
*/
21+
public function testWillInstantiate(): void
22+
{
23+
$handler = $this->createMock(PageHandler::class);
24+
25+
$this->assertContainsOnlyInstancesOf(RequestHandlerInterface::class, [$handler]);
26+
}
27+
28+
/**
29+
* @throws Exception
30+
*/
31+
public function testHandle(): void
32+
{
33+
$routeName = 'test_route_name';
34+
$request = $this->createMock(ServerRequestInterface::class);
35+
$template = $this->createMock(TemplateRendererInterface::class);
36+
$routeResult = $this->createMock(RouteResult::class);
37+
38+
$routeResult
39+
->method('getMatchedRouteName')
40+
->willReturn($routeName);
41+
42+
$request
43+
->method('getAttribute')
44+
->with(RouteResult::class)
45+
->willReturn($routeResult);
46+
47+
$template
48+
->method('render')
49+
->with($routeName)
50+
->willReturn('<p>' . $routeName . '</p>');
51+
52+
$handler = new PageHandler($template);
53+
54+
$response = $handler->handle($request);
55+
56+
$this->assertInstanceOf(HtmlResponse::class, $response);
57+
$this->assertSame('<p>' . $routeName . '</p>', $response->getBody()->getContents());
58+
}
59+
}

test/Unit/Page/RoutesDelegatorTest.php

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,54 @@
44

55
namespace LightTest\Unit\Page;
66

7+
use Light\Page\Handler\PageHandler;
78
use Light\Page\RoutesDelegator;
89
use Mezzio\Application;
10+
use Mezzio\Router\Route;
911
use PHPUnit\Framework\MockObject\Exception;
1012
use PHPUnit\Framework\TestCase;
1113
use Psr\Container\ContainerInterface;
1214

15+
use function sprintf;
16+
1317
class RoutesDelegatorTest extends TestCase
1418
{
1519
/**
1620
* @throws Exception
1721
*/
1822
public function testWillInvoke(): void
1923
{
20-
$application = (new RoutesDelegator())(
21-
$this->createMock(ContainerInterface::class),
24+
$moduleName = 'test';
25+
$routeName = 'test_route_name';
26+
$routeUri = sprintf('/%s/%s', $moduleName, $routeName);
27+
$templateName = sprintf('%s::%s', $moduleName, $routeName);
28+
29+
$container = $this->createMock(ContainerInterface::class);
30+
$app = $this->createMock(Application::class);
31+
32+
$app->method('get')->willReturn($this->createMock(Route::class));
33+
$app
34+
->expects($this->exactly(1))
35+
->method('get')
36+
->willReturnCallback(function (...$args) use ($routeUri, $templateName) {
37+
$this->assertSame($routeUri, $args[0]);
38+
$this->assertSame([[PageHandler::class]], [$args[1]]);
39+
$this->assertSame($templateName, $args[2]);
40+
});
41+
42+
$container->method('get')->with('config')->willReturn([
43+
'routes' => [
44+
$moduleName => [
45+
$routeName => $routeName,
46+
],
47+
],
48+
]);
49+
50+
$application = (new RoutesDelegator())(
51+
$container,
2252
'',
23-
function () {
24-
return $this->createMock(Application::class);
53+
$callback = function () use ($app) {
54+
return $app;
2555
}
2656
);
2757

0 commit comments

Comments
 (0)