Store StaticRoutes to separate hash array in Router

Add StaticRouteInterface
This commit is contained in:
PJ Dietz 2015-01-02 11:54:30 -05:00
parent 6ae85398db
commit 78fe57d736
4 changed files with 139 additions and 46 deletions

View File

@ -0,0 +1,28 @@
<?php
/**
* pjdietz\WellRESTed\Interfaces\ResponseInterface
*
* @author PJ Dietz <pj@pjdietz.com>
* @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();
}

View File

@ -14,7 +14,7 @@ use pjdietz\WellRESTed\Exceptions\HttpExceptions\HttpException;
use pjdietz\WellRESTed\Interfaces\HandlerInterface; use pjdietz\WellRESTed\Interfaces\HandlerInterface;
use pjdietz\WellRESTed\Interfaces\RequestInterface; use pjdietz\WellRESTed\Interfaces\RequestInterface;
use pjdietz\WellRESTed\Interfaces\ResponseInterface; use pjdietz\WellRESTed\Interfaces\ResponseInterface;
use pjdietz\WellRESTed\Routes\StaticRoute; use pjdietz\WellRESTed\Interfaces\Routes\StaticRouteInterface;
/** /**
* Router * Router
@ -25,6 +25,10 @@ class Router implements HandlerInterface
{ {
/** @var array Array of Route objects */ /** @var array Array of Route objects */
private $routes; 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. */ /** @var array Hash array of status code => qualified HandlerInterface names for error handling. */
private $errorHandlers; private $errorHandlers;
@ -32,30 +36,10 @@ class Router implements HandlerInterface
public function __construct() public function __construct()
{ {
$this->routes = array(); $this->routes = array();
$this->staticRoutes = array();
$this->errorHandlers = 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 * 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) public function getResponse(RequestInterface $request, array $args = null)
{ {
$path = $request->getPath(); $response = $this->getResponseFromRoutes($request, $args);
if (array_key_exists($path, $this->routes)) { if ($response) {
$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) {
// Check if the router has an error handler for this status code. // Check if the router has an error handler for this status code.
$status = $response->getStatusCode(); $status = $response->getStatusCode();
if (array_key_exists($status, $this->errorHandlers)) { if (array_key_exists($status, $this->errorHandlers)) {
@ -92,9 +63,8 @@ class Router implements HandlerInterface
} }
return $errorHandler->getResponse($request, $errorArgs); return $errorHandler->getResponse($request, $errorArgs);
} }
return $response;
} }
return null; return $response;
} }
/** /**
@ -104,11 +74,8 @@ class Router implements HandlerInterface
*/ */
public function addRoute(HandlerInterface $route) public function addRoute(HandlerInterface $route)
{ {
if ($route instanceof StaticRoute) { if ($route instanceof StaticRouteInterface) {
$handler = $route->getHandler(); $this->setStaticRoute($route->getPaths(), $route->getHandler());
foreach ($route->getPaths() as $path) {
$this->routes[$path] = $handler;
}
} else { } else {
$this->routes[] = $route; $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. * Add a custom error handler.
* *
@ -180,4 +163,62 @@ class Router implements HandlerInterface
return $response; 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;
}
} }

View File

@ -11,12 +11,14 @@
namespace pjdietz\WellRESTed\Routes; namespace pjdietz\WellRESTed\Routes;
use InvalidArgumentException; use InvalidArgumentException;
use pjdietz\WellRESTed\Interfaces\HandlerInterface;
use pjdietz\WellRESTed\Interfaces\RequestInterface; use pjdietz\WellRESTed\Interfaces\RequestInterface;
use pjdietz\WellRESTed\Interfaces\Routes\StaticRouteInterface;
/** /**
* Maps a list of static URI paths to a Handler * 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 */ /** @var array List of static URI paths */
protected $paths; protected $paths;
@ -67,7 +69,7 @@ class StaticRoute extends BaseRoute
/** /**
* Returns the target class this maps to. * Returns the target class this maps to.
* *
* @return HandlerInterface * @return string Fully qualified name for a HandlerInterface
*/ */
public function getHandler() public function getHandler()
{ {

View File

@ -48,6 +48,20 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(200, $resp->getStatusCode()); $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() public function testRespondWithDefaultErrorForException()
{ {
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface'); $mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
@ -348,3 +362,11 @@ class InjectionHandler implements HandlerInterface
return $response; return $response;
} }
} }
class NullResponseHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
return null;
}
}