From 963e1acd58b90e0e64e1e370d23435accde7e794 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 12 Apr 2015 13:51:49 -0400 Subject: [PATCH] Add pre- and post-route hooks to Router --- src/Routing/Router.php | 55 +++++++++++++++++++++++++- test/tests/unit/Routing/RouterTest.php | 39 ++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 38c350c..9b17ae7 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -13,6 +13,12 @@ use WellRESTed\Stream\Stream; class Router implements MiddlewareInterface { + /** @var DispatcherInterface */ + protected $dispatcher; + /** @var array Middleware to dispatch before the router evaluates the route. */ + private $preRouteHooks; + /** @var array Middleware to dispatch after the router dispatches all other middleware */ + private $postRouteHooks; /** @var array Hash array of status code => error handler */ private $statusHandlers; /** @var RouteTable Collection of routes */ @@ -20,6 +26,8 @@ class Router implements MiddlewareInterface /** @var RouteFactoryInterface */ private $routeFactory; + // ------------------------------------------------------------------------ + public function __construct() { $this->routeFactory = $this->getRouteFactory(); @@ -27,6 +35,8 @@ class Router implements MiddlewareInterface $this->statusHandlers = []; } + // ------------------------------------------------------------------------ + /** * Create and return a route given a string path, a handler, and optional * extra arguments. @@ -53,6 +63,22 @@ class Router implements MiddlewareInterface $this->routeFactory->registerRoute($this->routeTable, $target, $middleware, $extra); } + public function addPreRouteHook($middleware) + { + if (!isset($this->preRouteHooks)) { + $this->preRouteHooks = []; + } + $this->preRouteHooks[] = $middleware; + } + + public function addPostRouteHook($middleware) + { + if (!isset($this->postRouteHooks)) { + $this->postRouteHooks = []; + } + $this->postRouteHooks[] = $middleware; + } + public function setStatusHandler($statusCode, $middleware) { $this->statusHandlers[$statusCode] = $middleware; @@ -60,6 +86,7 @@ class Router implements MiddlewareInterface public function dispatch(ServerRequestInterface $request, ResponseInterface &$response) { + $this->disptachPreRouteHooks($request, $response); try { $this->routeTable->dispatch($request, $response); } catch (HttpException $e) { @@ -72,6 +99,7 @@ class Router implements MiddlewareInterface $dispatcher = $this->getDispatcher(); $dispatcher->dispatch($middleware, $request, $response); } + $this->disptachPostRouteHooks($request, $response); } public function respond() @@ -97,7 +125,10 @@ class Router implements MiddlewareInterface */ protected function getDispatcher() { - return new Dispatcher(); + if (!isset($this->dispatcher)) { + $this->dispatcher = new Dispatcher(); + } + return $this->dispatcher; } /** @@ -149,4 +180,26 @@ class Router implements MiddlewareInterface } // @codeCoverageIgnoreEnd + + // ------------------------------------------------------------------------ + + private function disptachPreRouteHooks(ServerRequestInterface $request, ResponseInterface &$response) + { + if ($this->preRouteHooks) { + $dispatcher = $this->getDispatcher(); + foreach ($this->preRouteHooks as $hook) { + $dispatcher->dispatch($hook, $request, $response); + } + } + } + + private function disptachPostRouteHooks(ServerRequestInterface $request, ResponseInterface &$response) + { + if ($this->postRouteHooks) { + $dispatcher = $this->getDispatcher(); + foreach ($this->postRouteHooks as $hook) { + $dispatcher->dispatch($hook, $request, $response); + } + } + } } diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 24113a1..506706f 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -21,6 +21,7 @@ use WellRESTed\Routing\Router; */ class RouterTest extends \PHPUnit_Framework_TestCase { + private $dispatcher; private $middleware; private $request; private $responder; @@ -28,6 +29,8 @@ class RouterTest extends \PHPUnit_Framework_TestCase public function setUp() { + $this->dispatcher = $this->prophesize('\WellRESTed\Routing\DispatcherInterface'); + $this->dispatcher->dispatch(Argument::any())->willReturn(); $this->request = $this->prophesize("\\Psr\\Http\\Message\\ServerRequestInterface"); $this->response = $this->prophesize("\\Psr\\Http\\Message\\ResponseInterface"); $this->response->withStatus(Argument::any())->willReturn($this->response->reveal()); @@ -50,6 +53,36 @@ class RouterTest extends \PHPUnit_Framework_TestCase $this->middleware->dispatch(Argument::cetera())->shouldHaveBeenCalled(); } + public function testDispatchesPreRouteHooks() + { + $hook = $this->prophesize('\WellRESTed\Routing\MiddlewareInterface'); + $hook->dispatch(Argument::cetera())->willReturn(); + + $this->request->getRequestTarget()->willReturn("/cats/"); + + $router = new Router(); + $router->addPreRouteHook($hook->reveal()); + $router->add("/cats/", $this->middleware->reveal()); + $router->dispatch($this->request->reveal(), $this->response->reveal()); + + $hook->dispatch(Argument::cetera())->shouldHaveBeenCalled(); + } + + public function testDispatchesPostRouteHooks() + { + $hook = $this->prophesize('\WellRESTed\Routing\MiddlewareInterface'); + $hook->dispatch(Argument::cetera())->willReturn(); + + $this->request->getRequestTarget()->willReturn("/cats/"); + + $router = new Router(); + $router->addPostRouteHook($hook->reveal()); + $router->add("/cats/", $this->middleware->reveal()); + $router->dispatch($this->request->reveal(), $this->response->reveal()); + + $hook->dispatch(Argument::cetera())->shouldHaveBeenCalled(); + } + public function testRespondsWithErrorResponseForHttpException() { $this->request->getRequestTarget()->willReturn("/cats/"); @@ -110,11 +143,17 @@ class RouterTest extends \PHPUnit_Framework_TestCase */ class SettableRouter extends Router { + public $dispatcher; public $methodMap; public $request; public $response; public $responder; + public function getDispatcher() + { + return $this->dispatcher; + } + public function getMethodMap() { return $this->methodMap ?: parent::getMethodMap();