From 78fe57d73615ab3b7e6b2bd006776802ffffe7fd Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 2 Jan 2015 11:54:30 -0500 Subject: [PATCH] Store StaticRoutes to separate hash array in Router Add StaticRouteInterface --- .../Routes/StaticRouteInterface.php | 28 ++++ src/pjdietz/WellRESTed/Router.php | 129 ++++++++++++------ src/pjdietz/WellRESTed/Routes/StaticRoute.php | 6 +- test/RouterTest.php | 22 +++ 4 files changed, 139 insertions(+), 46 deletions(-) create mode 100644 src/pjdietz/WellRESTed/Interfaces/Routes/StaticRouteInterface.php diff --git a/src/pjdietz/WellRESTed/Interfaces/Routes/StaticRouteInterface.php b/src/pjdietz/WellRESTed/Interfaces/Routes/StaticRouteInterface.php new file mode 100644 index 0000000..b3a008f --- /dev/null +++ b/src/pjdietz/WellRESTed/Interfaces/Routes/StaticRouteInterface.php @@ -0,0 +1,28 @@ + + * @copyright Copyright 2014 by PJ Dietz + * @license MIT + */ + +namespace pjdietz\WellRESTed\Interfaces\Routes; + +interface StaticRouteInterface +{ + /** + * Returns the target class this maps to. + * + * @return string Fully qualified name for a HandlerInterface + */ + public function getHandler(); + + /** + * Returns the paths this maps to a target handler. + * + * @return array Array of paths. + */ + public function getPaths(); +} diff --git a/src/pjdietz/WellRESTed/Router.php b/src/pjdietz/WellRESTed/Router.php index f4a9993..c221264 100644 --- a/src/pjdietz/WellRESTed/Router.php +++ b/src/pjdietz/WellRESTed/Router.php @@ -14,7 +14,7 @@ use pjdietz\WellRESTed\Exceptions\HttpExceptions\HttpException; use pjdietz\WellRESTed\Interfaces\HandlerInterface; use pjdietz\WellRESTed\Interfaces\RequestInterface; use pjdietz\WellRESTed\Interfaces\ResponseInterface; -use pjdietz\WellRESTed\Routes\StaticRoute; +use pjdietz\WellRESTed\Interfaces\Routes\StaticRouteInterface; /** * Router @@ -25,6 +25,10 @@ class Router implements HandlerInterface { /** @var array Array of Route objects */ private $routes; + + /** @var array Hash array mapping exact paths to handlers */ + private $staticRoutes; + /** @var array Hash array of status code => qualified HandlerInterface names for error handling. */ private $errorHandlers; @@ -32,30 +36,10 @@ class Router implements HandlerInterface public function __construct() { $this->routes = array(); + $this->staticRoutes = array(); $this->errorHandlers = array(); } - /** - * Wraps the getResponse method in a try-catch. - * - * @param HandlerInterface $handler The Route or Handle to try. - * @param RequestInterface $request The incoming request. - * @param array $args The array of arguments. - * @return null|Response - */ - private function tryResponse($handler, $request, $args) - { - $response = null; - try { - $response = $handler->getResponse($request, $args); - } catch (HttpException $e) { - $response = new Response(); - $response->setStatusCode($e->getCode()); - $response->setBody($e->getMessage()); - } - return $response; - } - /** * Return the response built by the handler based on the request * @@ -65,21 +49,8 @@ class Router implements HandlerInterface */ public function getResponse(RequestInterface $request, array $args = null) { - $path = $request->getPath(); - if (array_key_exists($path, $this->routes)) { - $handler = new $this->routes[$path](); - $response = $this->tryResponse($handler, $request, $args); - } else { - foreach ($this->routes as $path => $route) { - // Only take elements that are not $path => $handler mapped. - if (is_int($path)) { - /** @var HandlerInterface $route */ - $response = $this->tryResponse($route, $request, $args); - if ($response) break; - } - } - } - if (isset($response) and $response) { + $response = $this->getResponseFromRoutes($request, $args); + if ($response) { // Check if the router has an error handler for this status code. $status = $response->getStatusCode(); if (array_key_exists($status, $this->errorHandlers)) { @@ -92,9 +63,8 @@ class Router implements HandlerInterface } return $errorHandler->getResponse($request, $errorArgs); } - return $response; } - return null; + return $response; } /** @@ -104,11 +74,8 @@ class Router implements HandlerInterface */ public function addRoute(HandlerInterface $route) { - if ($route instanceof StaticRoute) { - $handler = $route->getHandler(); - foreach ($route->getPaths() as $path) { - $this->routes[$path] = $handler; - } + if ($route instanceof StaticRouteInterface) { + $this->setStaticRoute($route->getPaths(), $route->getHandler()); } else { $this->routes[] = $route; } @@ -128,6 +95,22 @@ class Router implements HandlerInterface } } + /** + * A route for an exact match to a path. + * + * @param string|array $paths Path component of the URI or a list of paths + * @param string $handler Fully qualified name to an autoloadable handler class. + */ + public function setStaticRoute($paths, $handler) + { + if (is_string($paths)) { + $paths = array($paths); + } + foreach ($paths as $path) { + $this->staticRoutes[$path] = $handler; + } + } + /** * Add a custom error handler. * @@ -180,4 +163,62 @@ class Router implements HandlerInterface return $response; } + private function getStaticHandler($path) + { + if (array_key_exists($path, $this->staticRoutes)) { + return new $this->staticRoutes[$path](); + } + return null; + } + + private function getResponseFromRoutes(RequestInterface $request, array $args = null) + { + $response = null; + + $path = $request->getPath(); + + // First check if there is a handler for this exact path. + $handler = $this->getStaticHandler($path); + if ($handler) { + $reponse = $this->tryResponse($handler, $request, $args); + if ($reponse) { + return $reponse; + } + } + + // Try each of the routes. + foreach ($this->routes as $route) { + /** @var HandlerInterface $route */ + $response = $this->tryResponse($route, $request, $args); + if ($response) { + return $response; + } + } + + return null; + } + + /** + * Wraps the getResponse method in a try-catch. + * + * In an HttpException is caught while trying to get a response, the method returns a response based on the + * HttpException's error code and message. + * + * @param HandlerInterface $handler The Route or Handler to try. + * @param RequestInterface $request The incoming request. + * @param array $args The array of arguments. + * @return null|Response + */ + private function tryResponse($handler, $request, $args) + { + $response = null; + try { + $response = $handler->getResponse($request, $args); + } catch (HttpException $e) { + $response = new Response(); + $response->setStatusCode($e->getCode()); + $response->setBody($e->getMessage()); + } + return $response; + } } diff --git a/src/pjdietz/WellRESTed/Routes/StaticRoute.php b/src/pjdietz/WellRESTed/Routes/StaticRoute.php index b146103..67e1af8 100644 --- a/src/pjdietz/WellRESTed/Routes/StaticRoute.php +++ b/src/pjdietz/WellRESTed/Routes/StaticRoute.php @@ -11,12 +11,14 @@ namespace pjdietz\WellRESTed\Routes; use InvalidArgumentException; +use pjdietz\WellRESTed\Interfaces\HandlerInterface; use pjdietz\WellRESTed\Interfaces\RequestInterface; +use pjdietz\WellRESTed\Interfaces\Routes\StaticRouteInterface; /** * Maps a list of static URI paths to a Handler */ -class StaticRoute extends BaseRoute +class StaticRoute extends BaseRoute implements StaticRouteInterface { /** @var array List of static URI paths */ protected $paths; @@ -67,7 +69,7 @@ class StaticRoute extends BaseRoute /** * Returns the target class this maps to. * - * @return HandlerInterface + * @return string Fully qualified name for a HandlerInterface */ public function getHandler() { diff --git a/test/RouterTest.php b/test/RouterTest.php index afd9c0a..5b4ceaf 100644 --- a/test/RouterTest.php +++ b/test/RouterTest.php @@ -48,6 +48,20 @@ class RouterTest extends \PHPUnit_Framework_TestCase $this->assertEquals(200, $resp->getStatusCode()); } + public function testTryRoutesAfterNullStaticRoute() + { + $mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface'); + $mockRequest->expects($this->any()) + ->method('getPath') + ->will($this->returnValue("/cat/")); + + $router = new Router(); + $router->setStaticRoute("/cat/", __NAMESPACE__ . '\\NullResponseHandler'); + $router->addRoute(new TemplateRoute("/cat/*", __NAMESPACE__ . '\\RouterTestHandler')); + $resp = $router->getResponse($mockRequest); + $this->assertEquals(200, $resp->getStatusCode()); + } + public function testRespondWithDefaultErrorForException() { $mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface'); @@ -348,3 +362,11 @@ class InjectionHandler implements HandlerInterface return $response; } } + +class NullResponseHandler implements HandlerInterface +{ + public function getResponse(RequestInterface $request, array $args = null) + { + return null; + } +}