diff options
author | Igor Scheller <igor.scheller@igorshp.de> | 2018-08-25 21:16:20 +0200 |
---|---|---|
committer | Igor Scheller <igor.scheller@igorshp.de> | 2018-08-25 21:48:39 +0200 |
commit | a1bc763a16ee8be109de5c9053fbc5eded53824e (patch) | |
tree | 7253db0c8ea918e82253bef3926bcba461a7105d /src/Middleware | |
parent | 73c9d923e7cc77847cfcbff4b90ad4815699a4fa (diff) |
Added nikic/fast-route as routing dispatcher
Diffstat (limited to 'src/Middleware')
-rw-r--r-- | src/Middleware/CallableHandler.php | 77 | ||||
-rw-r--r-- | src/Middleware/Dispatcher.php | 26 | ||||
-rw-r--r-- | src/Middleware/LegacyMiddleware.php | 13 | ||||
-rw-r--r-- | src/Middleware/NotFoundResponse.php | 56 | ||||
-rw-r--r-- | src/Middleware/RequestHandler.php | 50 | ||||
-rw-r--r-- | src/Middleware/RequestHandlerServiceProvider.php | 17 | ||||
-rw-r--r-- | src/Middleware/ResolvesMiddlewareTrait.php | 56 | ||||
-rw-r--r-- | src/Middleware/RouteDispatcher.php | 75 | ||||
-rw-r--r-- | src/Middleware/RouteDispatcherServiceProvider.php | 41 |
9 files changed, 330 insertions, 81 deletions
diff --git a/src/Middleware/CallableHandler.php b/src/Middleware/CallableHandler.php new file mode 100644 index 00000000..eb493bf1 --- /dev/null +++ b/src/Middleware/CallableHandler.php @@ -0,0 +1,77 @@ +<?php + +namespace Engelsystem\Middleware; + +use Engelsystem\Container\Container; +use Engelsystem\Http\Response; +use InvalidArgumentException; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class CallableHandler implements MiddlewareInterface, RequestHandlerInterface +{ + /** @var callable */ + protected $callable; + + /** @var Container */ + protected $container; + + /** + * @param callable $callable The callable that should be wrapped + * @param Container $container + */ + public function __construct(callable $callable, Container $container = null) + { + $this->callable = $callable; + $this->container = $container; + } + + /** + * Process an incoming server request and return a response, optionally delegating + * response creation to a handler. + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + return $this->execute([$request, $handler]); + } + + /** + * Handle the request and return a response. + * + * @param ServerRequestInterface $request + * @return ResponseInterface + */ + public function handle(ServerRequestInterface $request): ResponseInterface + { + return $this->execute([$request]); + } + + /** + * Execute the callable and return a response + * + * @param array $arguments + * @return ResponseInterface + */ + protected function execute(array $arguments = []): ResponseInterface + { + $return = call_user_func_array($this->callable, $arguments); + + if ($return instanceof ResponseInterface) { + return $return; + } + + if (!$this->container instanceof Container) { + throw new InvalidArgumentException('Unable to resolve response'); + } + + /** @var Response $response */ + $response = $this->container->get('response'); + return $response->withContent($return); + } +} diff --git a/src/Middleware/Dispatcher.php b/src/Middleware/Dispatcher.php index f2a5b5d5..48eb0948 100644 --- a/src/Middleware/Dispatcher.php +++ b/src/Middleware/Dispatcher.php @@ -12,6 +12,8 @@ use Psr\Http\Server\RequestHandlerInterface; class Dispatcher implements MiddlewareInterface, RequestHandlerInterface { + use ResolvesMiddlewareTrait; + /** @var MiddlewareInterface[]|string[] */ protected $stack; @@ -70,10 +72,7 @@ class Dispatcher implements MiddlewareInterface, RequestHandlerInterface throw new LogicException('Middleware queue is empty'); } - if (is_string($middleware)) { - $middleware = $this->resolveMiddleware($middleware); - } - + $middleware = $this->resolveMiddleware($middleware); if (!$middleware instanceof MiddlewareInterface) { throw new InvalidArgumentException('Middleware is no instance of ' . MiddlewareInterface::class); } @@ -82,25 +81,6 @@ class Dispatcher implements MiddlewareInterface, RequestHandlerInterface } /** - * Resolve the middleware with the container - * - * @param string $middleware - * @return MiddlewareInterface - */ - protected function resolveMiddleware($middleware) - { - if (!$this->container instanceof Application) { - throw new InvalidArgumentException('Unable to resolve middleware ' . $middleware); - } - - if ($this->container->has($middleware)) { - return $this->container->get($middleware); - } - - return $this->container->make($middleware); - } - - /** * @param Application $container */ public function setContainer(Application $container) diff --git a/src/Middleware/LegacyMiddleware.php b/src/Middleware/LegacyMiddleware.php index 714141de..276fb3ee 100644 --- a/src/Middleware/LegacyMiddleware.php +++ b/src/Middleware/LegacyMiddleware.php @@ -83,7 +83,9 @@ class LegacyMiddleware implements MiddlewareInterface } if (empty($title) and empty($content)) { - return $handler->handle($request); + $page = '404'; + $title = _('Page not found'); + $content = _('This page could not be found or you don\'t have permission to view it. You probably have to sign in or register in order to gain access!'); } return $this->renderPage($page, $title, $content); @@ -270,10 +272,17 @@ class LegacyMiddleware implements MiddlewareInterface $parameters = [ 'key' => (isset($user) ? $user['api_key'] : ''), ]; + if ($page == 'user_meetings') { $parameters['meetings'] = 1; } + $status = 200; + if ($page == '404') { + $status = 404; + $content = info($content, true); + } + return response(view(__DIR__ . '/../../templates/layout.html', [ 'theme' => isset($user) ? $user['color'] : config('theme'), 'title' => $title, @@ -291,6 +300,6 @@ class LegacyMiddleware implements MiddlewareInterface 'contact_email' => config('contact_email'), 'locale' => locale(), 'event_info' => EventConfig_info($event_config) . ' <br />' - ])); + ]), $status); } } diff --git a/src/Middleware/NotFoundResponse.php b/src/Middleware/NotFoundResponse.php deleted file mode 100644 index f9431c1d..00000000 --- a/src/Middleware/NotFoundResponse.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php - -namespace Engelsystem\Middleware; - -use Engelsystem\Http\Response; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\MiddlewareInterface; -use Psr\Http\Server\RequestHandlerInterface; - -class NotFoundResponse implements MiddlewareInterface -{ - /** - * Returns a 404: Page not found response - * - * Should be the last middleware - * - * @param ServerRequestInterface $request - * @param RequestHandlerInterface $handler - * @return ResponseInterface - */ - public function process( - ServerRequestInterface $request, - RequestHandlerInterface $handler - ): ResponseInterface { - $info = _('This page could not be found or you don\'t have permission to view it. You probably have to sign in or register in order to gain access!'); - - return $this->renderPage($info); - } - - /** - * @param string $content - * @return Response - * @codeCoverageIgnore - */ - protected function renderPage($content) - { - global $user; - $event_config = EventConfig(); - - return response(view(__DIR__ . '/../../templates/layout.html', [ - 'theme' => isset($user) ? $user['color'] : config('theme'), - 'title' => _('Page not found'), - 'atom_link' => '', - 'start_page_url' => page_link_to('/'), - 'credits_url' => page_link_to('credits'), - 'menu' => make_menu(), - 'content' => msg() . info($content), - 'header_toolbar' => header_toolbar(), - 'faq_url' => config('faq_url'), - 'contact_email' => config('contact_email'), - 'locale' => locale(), - 'event_info' => EventConfig_info($event_config) . ' <br />' - ]), 404); - } -} diff --git a/src/Middleware/RequestHandler.php b/src/Middleware/RequestHandler.php new file mode 100644 index 00000000..e1381abf --- /dev/null +++ b/src/Middleware/RequestHandler.php @@ -0,0 +1,50 @@ +<?php + +namespace Engelsystem\Middleware; + +use Engelsystem\Application; +use InvalidArgumentException; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class RequestHandler implements MiddlewareInterface +{ + use ResolvesMiddlewareTrait; + + /** @var Application */ + protected $container; + + /** + * @param Application $container + */ + public function __construct(Application $container) + { + $this->container = $container; + } + + /** + * Process an incoming server request and return a response, optionally delegating + * response creation to a handler. + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $requestHandler = $request->getAttribute('route-request-handler'); + $requestHandler = $this->resolveMiddleware($requestHandler); + + if ($requestHandler instanceof MiddlewareInterface) { + return $requestHandler->process($request, $handler); + } + + if ($requestHandler instanceof RequestHandlerInterface) { + return $requestHandler->handle($request); + } + + throw new InvalidArgumentException('Unable to process request handler of type ' . gettype($requestHandler)); + } +} diff --git a/src/Middleware/RequestHandlerServiceProvider.php b/src/Middleware/RequestHandlerServiceProvider.php new file mode 100644 index 00000000..c6488118 --- /dev/null +++ b/src/Middleware/RequestHandlerServiceProvider.php @@ -0,0 +1,17 @@ +<?php + +namespace Engelsystem\Middleware; + +use Engelsystem\Container\ServiceProvider; + +class RequestHandlerServiceProvider extends ServiceProvider +{ + public function register() + { + /** @var RequestHandler $requestHandler */ + $requestHandler = $this->app->make(RequestHandler::class); + + $this->app->instance('request.handler', $requestHandler); + $this->app->bind(RequestHandler::class, 'request.handler'); + } +} diff --git a/src/Middleware/ResolvesMiddlewareTrait.php b/src/Middleware/ResolvesMiddlewareTrait.php new file mode 100644 index 00000000..76557ce6 --- /dev/null +++ b/src/Middleware/ResolvesMiddlewareTrait.php @@ -0,0 +1,56 @@ +<?php + +namespace Engelsystem\Middleware; + +use Engelsystem\Application; +use InvalidArgumentException; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +trait ResolvesMiddlewareTrait +{ + /** + * Resolve the middleware with the container + * + * @param string|callable|MiddlewareInterface|RequestHandlerInterface $middleware + * @return MiddlewareInterface|RequestHandlerInterface + */ + protected function resolveMiddleware($middleware) + { + if ($this->isMiddleware($middleware)) { + return $middleware; + } + + if (!property_exists($this, 'container') || !$this->container instanceof Application) { + throw new InvalidArgumentException('Unable to resolve middleware'); + } + + /** @var Application $container */ + $container = $this->container; + + if (is_string($middleware)) { + $middleware = $container->make($middleware); + } + + if (is_callable($middleware)) { + $middleware = $container->make(CallableHandler::class, ['callable' => $middleware]); + } + + if ($this->isMiddleware($middleware)) { + return $middleware; + } + + throw new InvalidArgumentException('Unable to resolve middleware'); + } + + /** + * Checks if the given object is a middleware or middleware or request handler + * + * @param mixed $middleware + * @return bool + */ + protected function isMiddleware($middleware) + { + return ($middleware instanceof MiddlewareInterface || $middleware instanceof RequestHandlerInterface); + } +} diff --git a/src/Middleware/RouteDispatcher.php b/src/Middleware/RouteDispatcher.php new file mode 100644 index 00000000..f14faea8 --- /dev/null +++ b/src/Middleware/RouteDispatcher.php @@ -0,0 +1,75 @@ +<?php + +namespace Engelsystem\Middleware; + +use FastRoute\Dispatcher as FastRouteDispatcher; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class RouteDispatcher implements MiddlewareInterface +{ + /** @var FastRouteDispatcher */ + protected $dispatcher; + + /** @var ResponseInterface */ + protected $response; + + /** @var MiddlewareInterface|null */ + protected $notFound; + + /** + * @param FastRouteDispatcher $dispatcher + * @param ResponseInterface $response Default response + * @param MiddlewareInterface|null $notFound Handles any requests if the route can't be found + */ + public function __construct( + FastRouteDispatcher $dispatcher, + ResponseInterface $response, + MiddlewareInterface $notFound = null + ) { + $this->dispatcher = $dispatcher; + $this->response = $response; + $this->notFound = $notFound; + } + + /** + * Process an incoming server request and return a response, optionally delegating + * response creation to a handler. + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $route = $this->dispatcher->dispatch($request->getMethod(), urldecode($request->getUri()->getPath())); + + $status = $route[0]; + if ($status == FastRouteDispatcher::NOT_FOUND) { + if ($this->notFound instanceof MiddlewareInterface) { + return $this->notFound->process($request, $handler); + } + + return $this->response->withStatus(404); + } + + if ($status == FastRouteDispatcher::METHOD_NOT_ALLOWED) { + $methods = $route[1]; + return $this->response + ->withStatus(405) + ->withHeader('Allow', implode(', ', $methods)); + } + + $routeHandler = $route[1]; + $request = $request->withAttribute('route-request-handler', $routeHandler); + + $vars = $route[2]; + foreach ($vars as $name => $value) { + $request = $request->withAttribute($name, $value); + } + + return $handler->handle($request); + } +} diff --git a/src/Middleware/RouteDispatcherServiceProvider.php b/src/Middleware/RouteDispatcherServiceProvider.php new file mode 100644 index 00000000..3b4fa183 --- /dev/null +++ b/src/Middleware/RouteDispatcherServiceProvider.php @@ -0,0 +1,41 @@ +<?php + +namespace Engelsystem\Middleware; + +use Engelsystem\Container\ServiceProvider; +use FastRoute\Dispatcher as FastRouteDispatcher; +use FastRoute\RouteCollector; +use Psr\Http\Server\MiddlewareInterface; + +class RouteDispatcherServiceProvider extends ServiceProvider +{ + public function register() + { + $this->app->alias(RouteDispatcher::class, 'route.dispatcher'); + + $this->app + ->when(RouteDispatcher::class) + ->needs(FastRouteDispatcher::class) + ->give(function () { + return $this->generateRouting(); + }); + + $this->app + ->when(RouteDispatcher::class) + ->needs(MiddlewareInterface::class) + ->give(LegacyMiddleware::class); + } + + /** + * Includes the routes.php file + * + * @return FastRouteDispatcher + * @codeCoverageIgnore + */ + function generateRouting() + { + return \FastRoute\simpleDispatcher(function (RouteCollector $route) { + require config_path('routes.php'); + }); + } +} |