diff options
-rw-r--r-- | config/routes.php | 9 | ||||
-rw-r--r-- | includes/pages/guest_credits.php | 17 | ||||
-rw-r--r-- | src/Controllers/BaseController.php | 8 | ||||
-rw-r--r-- | src/Controllers/CreditsController.php | 24 | ||||
-rw-r--r-- | src/Middleware/LegacyMiddleware.php | 6 | ||||
-rw-r--r-- | src/Middleware/RequestHandler.php | 31 | ||||
-rw-r--r-- | templates/layouts/app.twig | 34 | ||||
-rw-r--r-- | templates/pages/credits.html | 36 | ||||
-rw-r--r-- | templates/pages/credits.twig | 42 | ||||
-rw-r--r-- | tests/Unit/Controllers/CreditsControllerTest.php | 28 | ||||
-rw-r--r-- | tests/Unit/Middleware/RequestHandlerTest.php | 77 |
11 files changed, 222 insertions, 90 deletions
diff --git a/config/routes.php b/config/routes.php index 5296dbc7..2267bc88 100644 --- a/config/routes.php +++ b/config/routes.php @@ -1,14 +1,7 @@ <?php use FastRoute\RouteCollector; -use Psr\Http\Message\ServerRequestInterface; /** @var RouteCollector $route */ -/** Demo route endpoint, TODO: Remove */ -$route->addRoute('GET', '/hello/{name}', function ($request) { - /** @var ServerRequestInterface $request */ - $name = $request->getAttribute('name'); - - return response(sprintf('Hello %s!', htmlspecialchars($name))); -}); +$route->get('/credits', 'CreditsController@index'); diff --git a/includes/pages/guest_credits.php b/includes/pages/guest_credits.php deleted file mode 100644 index 5f90c97c..00000000 --- a/includes/pages/guest_credits.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php - -/** - * @return string - */ -function credits_title() -{ - return __('Credits'); -} - -/** - * @return string - */ -function guest_credits() -{ - return view(__DIR__ . '/../../templates/pages/credits.html'); -} diff --git a/src/Controllers/BaseController.php b/src/Controllers/BaseController.php new file mode 100644 index 00000000..6a27a066 --- /dev/null +++ b/src/Controllers/BaseController.php @@ -0,0 +1,8 @@ +<?php + +namespace Engelsystem\Controllers; + +abstract class BaseController +{ + +} diff --git a/src/Controllers/CreditsController.php b/src/Controllers/CreditsController.php new file mode 100644 index 00000000..568811c7 --- /dev/null +++ b/src/Controllers/CreditsController.php @@ -0,0 +1,24 @@ +<?php + +namespace Engelsystem\Controllers; + +use Engelsystem\Http\Response; + +class CreditsController extends BaseController +{ + /** @var Response */ + protected $response; + + public function __construct(Response $response) + { + $this->response = $response; + } + + /** + * @return Response + */ + public function index() + { + return $this->response->withView('pages/credits.twig'); + } +} diff --git a/src/Middleware/LegacyMiddleware.php b/src/Middleware/LegacyMiddleware.php index f8c2a205..ebf456eb 100644 --- a/src/Middleware/LegacyMiddleware.php +++ b/src/Middleware/LegacyMiddleware.php @@ -18,7 +18,6 @@ class LegacyMiddleware implements MiddlewareInterface 'angeltypes', 'api', 'atom', - 'credits', 'ical', 'login', 'public_dashboard', @@ -249,11 +248,6 @@ class LegacyMiddleware implements MiddlewareInterface $title = admin_log_title(); $content = admin_log(); return [$title, $content]; - case 'credits': - require_once realpath(__DIR__ . '/../../includes/pages/guest_credits.php'); - $title = credits_title(); - $content = guest_credits(); - return [$title, $content]; } require_once realpath(__DIR__ . '/../../includes/pages/guest_start.php'); diff --git a/src/Middleware/RequestHandler.php b/src/Middleware/RequestHandler.php index e1381abf..ebe1ff9e 100644 --- a/src/Middleware/RequestHandler.php +++ b/src/Middleware/RequestHandler.php @@ -35,7 +35,7 @@ class RequestHandler implements MiddlewareInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $requestHandler = $request->getAttribute('route-request-handler'); - $requestHandler = $this->resolveMiddleware($requestHandler); + $requestHandler = $this->resolveRequestHandler($requestHandler); if ($requestHandler instanceof MiddlewareInterface) { return $requestHandler->process($request, $handler); @@ -47,4 +47,33 @@ class RequestHandler implements MiddlewareInterface throw new InvalidArgumentException('Unable to process request handler of type ' . gettype($requestHandler)); } + + /** + * @param string|callable|MiddlewareInterface|RequestHandlerInterface $handler + * @return MiddlewareInterface|RequestHandlerInterface + */ + protected function resolveRequestHandler($handler) + { + if (is_string($handler) && strpos($handler, '@') !== false) { + list($class, $method) = explode('@', $handler, 2); + if (!class_exists($class) && !$this->container->has($class)) { + $class = sprintf('Engelsystem\\Controllers\\%s', $class); + } + + $handler = [$class, $method]; + } + + if ( + is_array($handler) + && is_string($handler[0]) + && ( + class_exists($handler[0]) + || $this->container->has($handler[0]) + ) + ) { + $handler[0] = $this->container->make($handler[0]); + } + + return $this->resolveMiddleware($handler); + } } diff --git a/templates/layouts/app.twig b/templates/layouts/app.twig index 20ea853b..4868a714 100644 --- a/templates/layouts/app.twig +++ b/templates/layouts/app.twig @@ -28,8 +28,10 @@ {% endblock %} <div class="container-fluid"> - <div class="row"> - {% block content %}{{ content|raw }}{% endblock %} + <div class="row" id="content"> + {% block content %} + {{ content|raw }} + {% endblock %} </div> <div class="row" id="footer"> {% block footer %} @@ -38,19 +40,21 @@ </div> </div> - <script type="text/javascript" src="vendor/bootstrap/js/bootstrap.min.js"></script> - <script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/js/bootstrap-datepicker.min.js"></script> - <script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/locales/bootstrap-datepicker.de.min.js"></script> - <script type="text/javascript" src="vendor/Chart.min.js"></script> - <script type="text/javascript" src="js/forms.js"></script> - <script type="text/javascript" src="vendor/moment-with-locales.min.js"></script> - <script type="text/javascript"> - $(function () { - moment.locale("{{ session_get('locale')|escape('js') }}"); - }); - </script> - <script type="text/javascript" src="js/moment-countdown.js"></script> - <script type="text/javascript" src="js/sticky-headers.js"></script> + {% block scripts %} + <script type="text/javascript" src="vendor/bootstrap/js/bootstrap.min.js"></script> + <script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/js/bootstrap-datepicker.min.js"></script> + <script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/locales/bootstrap-datepicker.de.min.js"></script> + <script type="text/javascript" src="vendor/Chart.min.js"></script> + <script type="text/javascript" src="js/forms.js"></script> + <script type="text/javascript" src="vendor/moment-with-locales.min.js"></script> + <script type="text/javascript"> + $(function () { + moment.locale("{{ session_get('locale')|escape('js') }}"); + }); + </script> + <script type="text/javascript" src="js/moment-countdown.js"></script> + <script type="text/javascript" src="js/sticky-headers.js"></script> + {% endblock %} {% endblock %} </body> diff --git a/templates/pages/credits.html b/templates/pages/credits.html deleted file mode 100644 index 4e247113..00000000 --- a/templates/pages/credits.html +++ /dev/null @@ -1,36 +0,0 @@ -<div class="container"> - <h1>Credits</h1> - <div class="row"> - <div class="col-md-4"> - <h2>Source code</h2> - <p> - The original system was written by <a href="https://github.com/cookieBerlin/engelsystem">cookie</a>. - It was then completely rewritten and enhanced by - <a href="https://notrademark.de">msquare</a> (maintainer), - <a href="https://myigel.name">MyIgel</a>, - <a href="https://mortzu.de">mortzu</a>, - <a href="https://jplitza.de">jplitza</a> and - <a href="https://github.com/gnomus">gnomus</a>. - </p> - <p> - Please look at the <a href="https://github.com/engelsystem/engelsystem/graphs/contributors"> - contributor list on github</a> for a more complete version. - </p> - </div> - <div class="col-md-4"> - <h2>Hosting</h2> - <p> - Webspace, development platform and domain on <a href="https://engelsystem.de">engelsystem.de</a> - is currently provided by <a href="https://www.wybt.net/">would you buy this?</a> (ichdasich) - and adminstrated by <a href="https://mortzu.de">mortzu</a>, - <a href="http://derf.homelinux.org">derf</a> and ichdasich. - </p> - </div> - <div class="col-md-4"> - <h2>Translation</h2> - <p> - Many thanks for the german translation: <a href="http://e7p.de">e7p</a> - </p> - </div> - </div> -</div> diff --git a/templates/pages/credits.twig b/templates/pages/credits.twig new file mode 100644 index 00000000..ff2bf873 --- /dev/null +++ b/templates/pages/credits.twig @@ -0,0 +1,42 @@ +{% extends "layouts/app.twig" %} + +{% block title %}{{ __('Credits') }}{% endblock %} + +{% block content %} + <div class="container"> + <h1>Credits</h1> + <div class="row"> + <div class="col-md-4"> + <h2>Source code</h2> + <p> + The original system was written by <a href="https://github.com/cookieBerlin/engelsystem">cookie</a>. + It was then completely rewritten and enhanced by + <a href="https://notrademark.de">msquare</a> (maintainer), + <a href="https://myigel.name">MyIgel</a>, + <a href="https://mortzu.de">mortzu</a>, + <a href="https://jplitza.de">jplitza</a> and + <a href="https://github.com/gnomus">gnomus</a>. + </p> + <p> + Please look at the <a href="https://github.com/engelsystem/engelsystem/graphs/contributors"> + contributor list on github</a> for a more complete version. + </p> + </div> + <div class="col-md-4"> + <h2>Hosting</h2> + <p> + Webspace, development platform and domain on <a href="https://engelsystem.de">engelsystem.de</a> + is currently provided by <a href="https://www.wybt.net/">would you buy this?</a> (ichdasich) + and adminstrated by <a href="https://mortzu.de">mortzu</a>, + <a href="http://derf.homelinux.org">derf</a> and ichdasich. + </p> + </div> + <div class="col-md-4"> + <h2>Translation</h2> + <p> + Many thanks for the german translation: <a href="http://e7p.de">e7p</a> + </p> + </div> + </div> + </div> +{% endblock %} diff --git a/tests/Unit/Controllers/CreditsControllerTest.php b/tests/Unit/Controllers/CreditsControllerTest.php new file mode 100644 index 00000000..6f0200f2 --- /dev/null +++ b/tests/Unit/Controllers/CreditsControllerTest.php @@ -0,0 +1,28 @@ +<?php + +namespace Unit\Controllers; + +use Engelsystem\Controllers\CreditsController; +use Engelsystem\Http\Response; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CreditsControllerTest extends TestCase +{ + /** + * @covers \Engelsystem\Controllers\CreditsController::__construct + * @covers \Engelsystem\Controllers\CreditsController::index + */ + public function testIndex() + { + /** @var Response|MockObject $response */ + $response = $this->createMock(Response::class); + + $response->expects($this->once()) + ->method('withView') + ->with('pages/credits.twig'); + + $controller = new CreditsController($response); + $controller->index(); + } +} diff --git a/tests/Unit/Middleware/RequestHandlerTest.php b/tests/Unit/Middleware/RequestHandlerTest.php index 896b55c3..b1ffbd33 100644 --- a/tests/Unit/Middleware/RequestHandlerTest.php +++ b/tests/Unit/Middleware/RequestHandlerTest.php @@ -38,15 +38,12 @@ class RequestHandlerTest extends TestCase public function testProcess() { /** @var Application|MockObject $container */ - $container = $this->createMock(Application::class); /** @var ServerRequestInterface|MockObject $request */ - $request = $this->getMockForAbstractClass(ServerRequestInterface::class); /** @var RequestHandlerInterface|MockObject $handler */ - $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); /** @var ResponseInterface|MockObject $response */ - $response = $this->getMockForAbstractClass(ResponseInterface::class); + /** @var MiddlewareInterface|MockObject $middlewareInterface */ + list($container, $request, $handler, $response, $middlewareInterface) = $this->getMocks(); - $middlewareInterface = $this->getMockForAbstractClass(MiddlewareInterface::class); $requestHandlerInterface = $this->getMockForAbstractClass(RequestHandlerInterface::class); $request->expects($this->exactly(3)) @@ -57,10 +54,10 @@ class RequestHandlerTest extends TestCase /** @var RequestHandler|MockObject $middleware */ $middleware = $this->getMockBuilder(RequestHandler::class) ->setConstructorArgs([$container]) - ->setMethods(['resolveMiddleware']) + ->setMethods(['resolveRequestHandler']) ->getMock(); $middleware->expects($this->exactly(3)) - ->method('resolveMiddleware') + ->method('resolveRequestHandler') ->with('FooBarClass') ->willReturnOnConsecutiveCalls( $middlewareInterface, @@ -86,4 +83,70 @@ class RequestHandlerTest extends TestCase $this->expectException(InvalidArgumentException::class); $middleware->process($request, $handler); } + + /** + * @covers \Engelsystem\Middleware\RequestHandler::resolveRequestHandler + */ + public function testResolveRequestHandler() + { + /** @var Application|MockObject $container */ + /** @var ServerRequestInterface|MockObject $request */ + /** @var RequestHandlerInterface|MockObject $handler */ + /** @var ResponseInterface|MockObject $response */ + /** @var MiddlewareInterface|MockObject $middlewareInterface */ + list($container, $request, $handler, $response, $middlewareInterface) = $this->getMocks(); + + $className = 'Engelsystem\\Controllers\\FooBarTestController'; + + $request->expects($this->exactly(1)) + ->method('getAttribute') + ->with('route-request-handler') + ->willReturn('FooBarTestController@showStuff'); + + /** @var RequestHandler|MockObject $middleware */ + $middleware = $this->getMockBuilder(RequestHandler::class) + ->setConstructorArgs([$container]) + ->setMethods(['resolveMiddleware']) + ->getMock(); + $middleware->expects($this->once()) + ->method('resolveMiddleware') + ->with([$middlewareInterface, 'showStuff']) + ->willReturn($middlewareInterface); + + $middlewareInterface->expects($this->once()) + ->method('process') + ->with($request, $handler) + ->willReturn($response); + + $container->expects($this->exactly(2)) + ->method('has') + ->withConsecutive(['FooBarTestController'], [$className]) + ->willReturnOnConsecutiveCalls(false, true); + $container->expects($this->once()) + ->method('make') + ->with($className) + ->willReturn($middlewareInterface); + + $return = $middleware->process($request, $handler); + $this->assertEquals($return, $response); + } + + /** + * @return array + */ + protected function getMocks(): array + { + /** @var Application|MockObject $container */ + $container = $this->createMock(Application::class); + /** @var ServerRequestInterface|MockObject $request */ + $request = $this->getMockForAbstractClass(ServerRequestInterface::class); + /** @var RequestHandlerInterface|MockObject $handler */ + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + /** @var ResponseInterface|MockObject $response */ + $response = $this->getMockForAbstractClass(ResponseInterface::class); + /** @var MiddlewareInterface $middlewareInterface */ + $middlewareInterface = $this->getMockForAbstractClass(MiddlewareInterface::class); + + return array($container, $request, $handler, $response, $middlewareInterface); + } } |