summaryrefslogtreecommitdiff
path: root/src/Middleware
diff options
context:
space:
mode:
authorIgor Scheller <igor.scheller@igorshp.de>2018-08-25 21:16:20 +0200
committerIgor Scheller <igor.scheller@igorshp.de>2018-08-25 21:48:39 +0200
commita1bc763a16ee8be109de5c9053fbc5eded53824e (patch)
tree7253db0c8ea918e82253bef3926bcba461a7105d /src/Middleware
parent73c9d923e7cc77847cfcbff4b90ad4815699a4fa (diff)
Added nikic/fast-route as routing dispatcher
Diffstat (limited to 'src/Middleware')
-rw-r--r--src/Middleware/CallableHandler.php77
-rw-r--r--src/Middleware/Dispatcher.php26
-rw-r--r--src/Middleware/LegacyMiddleware.php13
-rw-r--r--src/Middleware/NotFoundResponse.php56
-rw-r--r--src/Middleware/RequestHandler.php50
-rw-r--r--src/Middleware/RequestHandlerServiceProvider.php17
-rw-r--r--src/Middleware/ResolvesMiddlewareTrait.php56
-rw-r--r--src/Middleware/RouteDispatcher.php75
-rw-r--r--src/Middleware/RouteDispatcherServiceProvider.php41
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');
+ });
+ }
+}