Add pre- and post-route hooks to Router

This commit is contained in:
PJ Dietz 2015-04-12 13:51:49 -04:00
parent b0a0f5262e
commit 963e1acd58
2 changed files with 93 additions and 1 deletions

View File

@ -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);
}
}
}
}

View File

@ -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();