From f5a023117aacbf069de1626a1f91bc70f3a48ada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Thu, 29 Mar 2018 18:51:28 +0200 Subject: [PATCH] Development - Added event-arguments data. - Added event-arguments to the event list in documentation. - Fixed missing exceptions thrown in phpDocs. - Added unit-tests for new event functionality. --- README.md | 43 +++++----- .../SimpleRouter/Event/EventArgument.php | 28 +++++++ .../Handlers/DebugEventHandler.php | 4 +- .../SimpleRouter/Handlers/EventHandler.php | 8 +- .../SimpleRouter/Handlers/IEventHandler.php | 4 +- .../SimpleRouter/Route/LoadableRoute.php | 6 +- src/Pecee/SimpleRouter/Route/Route.php | 2 +- src/Pecee/SimpleRouter/Router.php | 80 ++++++++++++++----- src/Pecee/SimpleRouter/SimpleRouter.php | 2 + tests/Pecee/SimpleRouter/EventHandlerTest.php | 40 ++++++---- tests/Pecee/SimpleRouter/InputHandlerTest.php | 15 ++-- 11 files changed, 162 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index a592726..6e6294c 100644 --- a/README.md +++ b/README.md @@ -1238,23 +1238,25 @@ It will also cover the basics of event-handlers; how to use the handlers provide This section contains all available events that can be registered using the `EventHandler`. -| Name | Description | -| ------------- |------------- | -| `EventHandler::EVENT_ALL` | Fires when a event is triggered. | -| `EventHandler::EVENT_INIT` | Fires when router is initializing and before routes are loaded. | -| `EventHandler::EVENT_LOAD` | Fires when all routes has been loaded and rendered, just before the output is returned. | -| `EventHandler::EVENT_REWRITE` | Fires when a url-rewrite is and just before the routes are re-initialized. | -| `EventHandler::EVENT_BOOT` | Fires when the router is booting. This happens just before boot-managers are rendered and before any routes has been loaded. | -| `EventHandler::EVENT_RENDER_BOOTMANAGER` | Fires before a boot-manager is rendered. | -| `EventHandler::EVENT_LOAD_ROUTES` | Fires when the router is about to load all routes. | -| `EventHandler::EVENT_FIND_ROUTE` | Fires whenever the `findRoute` method is called within the `Router`. This usually happens when the router tries to find routes that contains a certain url, usually after the `EventHandler::EVENT_GET_URL` event. | -| `EventHandler::EVENT_GET_URL` | Fires whenever the `Router::getUrl` method or `url`-helper function is called and the router tries to find the route. | -| `EventHandler::EVENT_MATCH_ROUTE` | Fires when a route is matched and valid (correct request-type etc). and before the route is rendered. | -| `EventHandler::EVENT_RENDER_ROUTE` | Fires before a route is rendered. | -| `EventHandler::EVENT_LOAD_EXCEPTIONS` | Fires when the router is loading exception-handlers. | -| `EventHandler::EVENT_RENDER_EXCEPTION` | Fires before the router is rendering a exception-handler. | -| `EventHandler::EVENT_RENDER_MIDDLEWARE` | Fires before a middleware is rendered. | -| `EventHandler::EVENT_RENDER_CSRF` | Fires before the CSRF-verifier is rendered. | +All event callbacks will retrieve a `EventArgument` object as parameter. This object contains easy access to event-name, router- and request instance and any special event-arguments related to the given event. You can see what special event arguments each event returns in the list below. + +| Name | Special arguments | Description | +| ------------- |----------- | ---- | +| `EVENT_ALL` | - | Fires when a event is triggered. | +| `EVENT_INIT` | - | Fires when router is initializing and before routes are loaded. | +| `EVENT_LOAD` | `loadedRoutes` | Fires when all routes has been loaded and rendered, just before the output is returned. | +| `EVENT_REWRITE` | `rewriteUrl`
`rewriteRoute` | Fires when a url-rewrite is and just before the routes are re-initialized. | +| `EVENT_BOOT` | `bootmanagers` | Fires when the router is booting. This happens just before boot-managers are rendered and before any routes has been loaded. | +| `EVENT_RENDER_BOOTMANAGER` | `bootmanagers`
`bootmanager` | Fires before a boot-manager is rendered. | +| `EVENT_LOAD_ROUTES` | `routes` | Fires when the router is about to load all routes. | +| `EVENT_FIND_ROUTE` | `name` | Fires whenever the `findRoute` method is called within the `Router`. This usually happens when the router tries to find routes that contains a certain url, usually after the `EventHandler::EVENT_GET_URL` event. | +| `EVENT_GET_URL` | `name`
`parameters`
`getParams` | Fires whenever the `Router::getUrl` method or `url`-helper function is called and the router tries to find the route. | +| `EVENT_MATCH_ROUTE` | `route` | Fires when a route is matched and valid (correct request-type etc). and before the route is rendered. | +| `EVENT_RENDER_ROUTE` | `route` | Fires before a route is rendered. | +| `EVENT_LOAD_EXCEPTIONS` | `exception`
`exceptionHandlers` | Fires when the router is loading exception-handlers. | +| `EVENT_RENDER_EXCEPTION` | `exception`
`exceptionHandler`
`exceptionHandlers` | Fires before the router is rendering a exception-handler. | +| `EVENT_RENDER_MIDDLEWARES` | `route`
`middlewares` | Fires before middlewares for a route is rendered. | +| `EVENT_RENDER_CSRF` | `csrfVerifier` | Fires before the CSRF-verifier is rendered. | ## Registering new event @@ -1272,9 +1274,14 @@ use Pecee\SimpleRouter\Event\EventArgument; // --- your routes goes here --- $eventHandler = new EventHandler(); + +// Add event that fires when a route is rendered $eventHandler->register(EventHandler::EVENT_RENDER_ROUTE, function(EventArgument $argument) { - // Fires when route is rendered ... + // Get the route by using the special argument for this event. + $route = $argument->route; + + // DO STUFF... }); diff --git a/src/Pecee/SimpleRouter/Event/EventArgument.php b/src/Pecee/SimpleRouter/Event/EventArgument.php index f4aeed8..3346ffe 100644 --- a/src/Pecee/SimpleRouter/Event/EventArgument.php +++ b/src/Pecee/SimpleRouter/Event/EventArgument.php @@ -70,6 +70,34 @@ class EventArgument implements IEventArgument return $this->getRouter()->getRequest(); } + /** + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->arguments[$name] ?? null; + } + + /** + * @param string $name + * @return bool + */ + public function __isset($name) + { + return array_key_exists($name, $this->arguments); + } + + /** + * @param string $name + * @param mixed $value + * @throws \InvalidArgumentException + */ + public function __set($name, $value) + { + throw new \InvalidArgumentException('Not supported'); + } + /** * Get arguments * diff --git a/src/Pecee/SimpleRouter/Handlers/DebugEventHandler.php b/src/Pecee/SimpleRouter/Handlers/DebugEventHandler.php index 2aa693f..690b275 100644 --- a/src/Pecee/SimpleRouter/Handlers/DebugEventHandler.php +++ b/src/Pecee/SimpleRouter/Handlers/DebugEventHandler.php @@ -41,9 +41,9 @@ class DebugEventHandler implements IEventHandler * * @param Router $router Router instance * @param string $name Event name - * @param array ...$eventArgs Event arguments + * @param array $eventArgs Event arguments */ - public function fireEvents(Router $router, string $name, ...$eventArgs): void + public function fireEvents(Router $router, string $name, array $eventArgs = []): void { $callback = $this->callback; $callback(new EventArgument($router, $eventArgs)); diff --git a/src/Pecee/SimpleRouter/Handlers/EventHandler.php b/src/Pecee/SimpleRouter/Handlers/EventHandler.php index 7b3b5af..57e0727 100644 --- a/src/Pecee/SimpleRouter/Handlers/EventHandler.php +++ b/src/Pecee/SimpleRouter/Handlers/EventHandler.php @@ -80,7 +80,7 @@ class EventHandler implements IEventHandler /** * Fires before a middleware is rendered. */ - public const EVENT_RENDER_MIDDLEWARE = 'onRenderMiddleware'; + public const EVENT_RENDER_MIDDLEWARES = 'onRenderMiddlewares'; /** * Fires before the CSRF-verifier is rendered. @@ -105,7 +105,7 @@ class EventHandler implements IEventHandler self::EVENT_RENDER_ROUTE, self::EVENT_LOAD_EXCEPTIONS, self::EVENT_RENDER_EXCEPTION, - self::EVENT_RENDER_MIDDLEWARE, + self::EVENT_RENDER_MIDDLEWARES, self::EVENT_RENDER_CSRF, ]; @@ -163,9 +163,9 @@ class EventHandler implements IEventHandler * * @param Router $router Router instance * @param string $name Event name - * @param array ...$eventArgs Event arguments + * @param array $eventArgs Event arguments */ - public function fireEvents(Router $router, string $name, ...$eventArgs): void + public function fireEvents(Router $router, string $name, array $eventArgs = []): void { $events = $this->getEvents(static::EVENT_ALL, $name); diff --git a/src/Pecee/SimpleRouter/Handlers/IEventHandler.php b/src/Pecee/SimpleRouter/Handlers/IEventHandler.php index 2276778..9ae63c2 100644 --- a/src/Pecee/SimpleRouter/Handlers/IEventHandler.php +++ b/src/Pecee/SimpleRouter/Handlers/IEventHandler.php @@ -19,8 +19,8 @@ interface IEventHandler { * * @param Router $router Router instance * @param string $name Event name - * @param array ...$eventArgs Event arguments + * @param array $eventArgs Event arguments */ - public function fireEvents(Router $router, string $name, ...$eventArgs) : void; + public function fireEvents(Router $router, string $name, array $eventArgs = []) : void; } \ No newline at end of file diff --git a/src/Pecee/SimpleRouter/Route/LoadableRoute.php b/src/Pecee/SimpleRouter/Route/LoadableRoute.php index 51c2591..d76cee7 100644 --- a/src/Pecee/SimpleRouter/Route/LoadableRoute.php +++ b/src/Pecee/SimpleRouter/Route/LoadableRoute.php @@ -42,9 +42,11 @@ abstract class LoadableRoute extends Route implements ILoadableRoute throw new HttpException($middleware . ' must be inherit the IMiddleware interface'); } - $router->debug('Loading middleware "%s"', \get_class($middleware)); + $className = \get_class($middleware); + + $router->debug('Loading middleware "%s"', $className); $middleware->handle($request); - $router->debug('Finished loading middleware'); + $router->debug('Finished loading middleware "%s"', $className); } $router->debug('Finished loading middlewares'); diff --git a/src/Pecee/SimpleRouter/Route/Route.php b/src/Pecee/SimpleRouter/Route/Route.php index 2f0d4eb..0426dfb 100644 --- a/src/Pecee/SimpleRouter/Route/Route.php +++ b/src/Pecee/SimpleRouter/Route/Route.php @@ -82,7 +82,7 @@ abstract class Route implements IRoute */ public function renderRoute(Request $request, Router $router): ?string { - $router->debug('Starting rendering route'); + $router->debug('Starting rendering route "%s"', \get_class($this)); $callback = $this->getCallback(); diff --git a/src/Pecee/SimpleRouter/Router.php b/src/Pecee/SimpleRouter/Router.php index c2a0eec..425a44d 100644 --- a/src/Pecee/SimpleRouter/Router.php +++ b/src/Pecee/SimpleRouter/Router.php @@ -258,23 +258,31 @@ class Router { $this->debug('Loading routes'); - $this->fireEvents(EventHandler::EVENT_BOOT); + $this->fireEvents(EventHandler::EVENT_BOOT, [ + 'bootmanagers' => $this->bootManagers, + ]); /* Initialize boot-managers */ /* @var $manager IRouterBootManager */ foreach ($this->bootManagers as $manager) { - $this->debug('Rendering bootmanager %s', \get_class($manager)); - $this->fireEvents(EventHandler::EVENT_RENDER_BOOTMANAGER, $manager); + $className = \get_class($manager); + $this->debug('Rendering bootmanager "%s"', $className); + $this->fireEvents(EventHandler::EVENT_RENDER_BOOTMANAGER, [ + 'bootmanagers' => $this->bootManagers, + 'bootmanager' => $manager, + ]); /* Render bootmanager */ $manager->boot($this, $this->request); - $this->debug('Finished rendering bootmanager'); + $this->debug('Finished rendering bootmanager "%s"', $className); } - $this->fireEvents(EventHandler::EVENT_LOAD_ROUTES); + $this->fireEvents(EventHandler::EVENT_LOAD_ROUTES, [ + 'routes' => $this->routes, + ]); /* Loop through each route-request */ $this->processRoutes($this->routes); @@ -301,7 +309,9 @@ class Router if ($this->csrfVerifier !== null) { - $this->fireEvents(EventHandler::EVENT_RENDER_CSRF); + $this->fireEvents(EventHandler::EVENT_RENDER_CSRF, [ + 'csrfVerifier' => $this->csrfVerifier, + ]); /* Verify csrf token for request */ $this->csrfVerifier->handle($this->request); @@ -309,7 +319,9 @@ class Router $output = $this->routeRequest(); - $this->fireEvents(EventHandler::EVENT_LOAD); + $this->fireEvents(EventHandler::EVENT_LOAD, [ + 'loadedRoutes' => $this->getRequest()->getLoadedRoutes(), + ]); $this->debug('Routing complete'); @@ -340,7 +352,9 @@ class Router /* If the route matches */ if ($route->matchRoute($url, $this->request) === true) { - $this->fireEvents(EventHandler::EVENT_MATCH_ROUTE); + $this->fireEvents(EventHandler::EVENT_MATCH_ROUTE, [ + 'route' => $route, + ]); /* Check if request method matches */ if (\count($route->getRequestMethods()) !== 0 && \in_array($this->request->getMethod(), $route->getRequestMethods(), true) === false) { @@ -349,7 +363,10 @@ class Router continue; } - $this->fireEvents(EventHandler::EVENT_RENDER_MIDDLEWARE); + $this->fireEvents(EventHandler::EVENT_RENDER_MIDDLEWARES, [ + 'route' => $route, + 'middlewares' => $route->getMiddlewares(), + ]); $route->loadMiddleware($this->request, $this); @@ -361,6 +378,11 @@ class Router $methodNotAllowed = false; $this->request->addLoadedRoute($route); + + $this->fireEvents(EventHandler::EVENT_RENDER_ROUTE, [ + 'route' => $route, + ]); + $output = $route->renderRoute($this->request, $this); if ($output !== null) { return $output; @@ -427,7 +449,10 @@ class Router unset($this->processedRoutes[$key]); $this->request->setHasPendingRewrite(false); - $this->fireEvents(EventHandler::EVENT_REWRITE); + $this->fireEvents(EventHandler::EVENT_REWRITE, [ + 'rewriteUrl' => $this->request->getRewriteUrl(), + 'rewriteRoute' => $this->request->getRewriteRoute(), + ]); return $this->routeRequest(); } @@ -445,7 +470,10 @@ class Router { $this->debug('Starting exception handling for "%s"', \get_class($e)); - $this->fireEvents(EventHandler::EVENT_LOAD_EXCEPTIONS); + $this->fireEvents(EventHandler::EVENT_LOAD_EXCEPTIONS, [ + 'exception' => $e, + 'exceptionHandlers' => $this->exceptionHandlers, + ]); /* @var $handler IExceptionHandler */ foreach ($this->exceptionHandlers as $key => $handler) { @@ -454,7 +482,11 @@ class Router $handler = new $handler(); } - $this->fireEvents(EventHandler::EVENT_RENDER_EXCEPTION); + $this->fireEvents(EventHandler::EVENT_RENDER_EXCEPTION, [ + 'exception' => $e, + 'exceptionHandler' => $handler, + 'exceptionHandlers' => $this->exceptionHandlers, + ]); $this->debug('Processing exception-handler "%s"', \get_class($handler)); @@ -473,7 +505,10 @@ class Router $this->debug('Exception handler contains rewrite, reloading routes'); - $this->fireEvents(EventHandler::EVENT_REWRITE); + $this->fireEvents(EventHandler::EVENT_REWRITE, [ + 'rewriteUrl' => $this->request->getRewriteUrl(), + 'rewriteRoute' => $this->request->getRewriteRoute(), + ]); return $this->routeRequest(); } @@ -498,7 +533,10 @@ class Router public function findRoute(string $name): ?ILoadableRoute { $this->debug('Finding route by name "%s"', $name); - $this->fireEvents(EventHandler::EVENT_FIND_ROUTE); + + $this->fireEvents(EventHandler::EVENT_FIND_ROUTE, [ + 'name' => $name, + ]); /* @var $route ILoadableRoute */ foreach ($this->processedRoutes as $route) { @@ -576,7 +614,11 @@ class Router { $this->debug('Finding url', \func_get_args()); - $this->fireEvents(EventHandler::EVENT_GET_URL); + $this->fireEvents(EventHandler::EVENT_GET_URL, [ + 'name' => $name, + 'parameters' => $parameters, + 'getParams' => $getParams, + ]); if ($getParams !== null && \is_array($getParams) === false) { throw new InvalidArgumentException('Invalid type for getParams. Must be array or null'); @@ -772,12 +814,12 @@ class Router } /** - * Fire event + * Fire event in event-handler. * * @param string $name - * @param array ...$args + * @param array $arguments */ - protected function fireEvents($name, ...$args): void + protected function fireEvents($name, array $arguments = []): void { if (\count($this->eventHandlers) === 0) { return; @@ -785,7 +827,7 @@ class Router /* @var IEventHandler $eventHandler */ foreach ($this->eventHandlers as $eventHandler) { - $eventHandler->fireEvents($this, $name, $args); + $eventHandler->fireEvents($this, $name, $arguments); } } diff --git a/src/Pecee/SimpleRouter/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php index 4f495e6..8e56f2d 100644 --- a/src/Pecee/SimpleRouter/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -51,6 +51,8 @@ class SimpleRouter /** * Start routing * + * @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException + * @throws \Pecee\Http\Middleware\Exceptions\TokenMismatchException * @throws HttpException * @throws \Exception */ diff --git a/tests/Pecee/SimpleRouter/EventHandlerTest.php b/tests/Pecee/SimpleRouter/EventHandlerTest.php index 7e49e6a..2447c9f 100644 --- a/tests/Pecee/SimpleRouter/EventHandlerTest.php +++ b/tests/Pecee/SimpleRouter/EventHandlerTest.php @@ -4,6 +4,7 @@ require_once 'Dummy/DummyMiddleware.php'; require_once 'Dummy/DummyController.php'; require_once 'Dummy/Handler/ExceptionHandler.php'; require_once 'Dummy/Security/SilentTokenProvider.php'; +require_once 'Dummy/Managers/TestBootManager.php'; use \Pecee\SimpleRouter\Handlers\EventHandler; use \Pecee\SimpleRouter\Event\EventArgument; @@ -11,21 +12,22 @@ use \Pecee\SimpleRouter\Event\EventArgument; class EventHandlerTest extends \PHPUnit\Framework\TestCase { - public function testMissingEvents() { - + public function testAllEventTriggered() + { $events = EventHandler::$events; // Remove the all event - unset($events[\array_search(EventHandler::EVENT_ALL, $events, true)], $events[\array_search(EventHandler::EVENT_REWRITE, $events, true)]); + unset($events[\array_search(EventHandler::EVENT_ALL, $events, true)]); $eventHandler = new EventHandler(); - $eventHandler->register(EventHandler::EVENT_ALL, function(EventArgument $arg) use(&$events) { + $eventHandler->register(EventHandler::EVENT_ALL, function (EventArgument $arg) use (&$events) { $key = \array_search($arg->getEventName(), $events, true); unset($events[$key]); }); TestRouter::addEventHandler($eventHandler); + // Add rewrite TestRouter::error(function (\Pecee\Http\Request $request, \Exception $error) { // Trigger rewrite @@ -35,28 +37,36 @@ class EventHandlerTest extends \PHPUnit\Framework\TestCase TestRouter::get('/', 'DummyController@method1')->name('home'); + // Trigger findRoute TestRouter::router()->findRoute('home'); + + // Trigger getUrl TestRouter::router()->getUrl('home'); + // Add csrf-verifier $csrfVerifier = new \Pecee\Http\Middleware\BaseCsrfVerifier(); $csrfVerifier->setTokenProvider(new SilentTokenProvider()); TestRouter::csrfVerifier($csrfVerifier); - TestRouter::debug('/not-existing'); + // Add boot-manager + TestRouter::addBootManager(new TestBootManager([ + '/test', + ], '/')); + + // Start router + TestRouter::debug('/non-existing'); $this->assertEquals($events, []); - - TestRouter::router()->reset(); - } - public function testAllEvent() { + public function testAllEvent() + { - $status = 0; + $status = false; $eventHandler = new EventHandler(); - $eventHandler->register(EventHandler::EVENT_ALL, function(EventArgument $arg) use(&$status) { - $status++; + $eventHandler->register(EventHandler::EVENT_ALL, function (EventArgument $arg) use (&$status) { + $status = true; }); TestRouter::addEventHandler($eventHandler); @@ -65,11 +75,7 @@ class EventHandlerTest extends \PHPUnit\Framework\TestCase TestRouter::debug('/'); // All event should fire for each other event - $this->assertEquals(\count(EventHandler::$events), $status); - } - - public function testEvents() { - $this->assertEquals(true, true); + $this->assertEquals(true, $status); } } \ No newline at end of file diff --git a/tests/Pecee/SimpleRouter/InputHandlerTest.php b/tests/Pecee/SimpleRouter/InputHandlerTest.php index 69e36c0..7cdebc3 100644 --- a/tests/Pecee/SimpleRouter/InputHandlerTest.php +++ b/tests/Pecee/SimpleRouter/InputHandlerTest.php @@ -7,23 +7,28 @@ require_once 'Dummy/Handler/ExceptionHandler.php'; class InputHandlerTest extends \PHPUnit\Framework\TestCase { - public function testGet() { + public function testGet() + { $this->assertEquals(true, true); } - public function testPost() { + public function testPost() + { $this->assertEquals(true, true); } - public function testFile() { + public function testFile() + { $this->assertEquals(true, true); } - public function testFiles() { + public function testFiles() + { $this->assertEquals(true, true); } - public function testAll() { + public function testAll() + { $this->assertEquals(true, true); }