Update Router to work with updated Routes and ErrorHandlers

Deprecate:
	- Router::setStaticRoute
	- Router::setPrefixRoute
This commit is contained in:
PJ Dietz 2015-02-19 22:03:50 -05:00
parent 4deac492dd
commit 04561076d5
2 changed files with 330 additions and 372 deletions

View File

@ -16,6 +16,8 @@ use pjdietz\WellRESTed\Interfaces\RequestInterface;
use pjdietz\WellRESTed\Interfaces\ResponseInterface;
use pjdietz\WellRESTed\Interfaces\Routes\PrefixRouteInterface;
use pjdietz\WellRESTed\Interfaces\Routes\StaticRouteInterface;
use pjdietz\WellRESTed\Routes\PrefixRoute;
use pjdietz\WellRESTed\Routes\StaticRoute;
/**
* Router
@ -27,13 +29,13 @@ class Router implements HandlerInterface
/** @var array Array of Route objects */
private $routes;
/** @var array Hash array mapping path prefixes to handlers */
/** @var array Hash array mapping path prefixes to routes */
private $prefixRoutes;
/** @var array Hash array mapping exact paths to handlers */
/** @var array Hash array mapping exact paths to routes */
private $staticRoutes;
/** @var array Hash array of status code => qualified HandlerInterface names for error handling. */
/** @var array Hash array of status code => error handler */
private $errorHandlers;
/** Create a new Router. */
@ -67,16 +69,16 @@ class Router implements HandlerInterface
}
/**
* Append a new route to the route route table.
* Append a new route to the route table.
*
* @param HandlerInterface $route
*/
public function addRoute(HandlerInterface $route)
{
if ($route instanceof StaticRouteInterface) {
$this->setStaticRoute($route->getPaths(), $route->getHandler());
$this->addStaticRoute($route);
} elseif ($route instanceof PrefixRouteInterface) {
$this->setPrefixRoute($route->getPrefixes(), $route->getHandler());
$this->addPrefixRoute($route);
} else {
$this->routes[] = $route;
}
@ -96,43 +98,11 @@ class Router implements HandlerInterface
}
}
/**
* Add a route for paths beginning with a given prefix.
*
* @param string|array $prefixes Prefix of a path to match
* @param string $handler Fully qualified name to an autoloadable handler class
*/
public function setPrefixRoute($prefixes, $handler)
{
if (is_string($prefixes)) {
$prefixes = array($prefixes);
}
foreach ($prefixes as $prefix) {
$this->prefixRoutes[$prefix] = $handler;
}
}
/**
* Add 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.
*
* @param integer $statusCode The error status code.
* @param string $errorHandler Fully qualified name to an autoloadable handler class.
* @param integer $statusCode The error status code
* @param callable|string|HandlerInterface $errorHandler
*/
public function setErrorHandler($statusCode, $errorHandler)
{
@ -142,7 +112,7 @@ class Router implements HandlerInterface
/**
* Add custom error handlers.
*
* @param array $errorHandlers Array mapping integer error codes to qualified handler names.
* @param array $errorHandlers Array mapping integer error codes to handlers
*/
public function setErrorHandlers(array $errorHandlers)
{
@ -185,11 +155,25 @@ class Router implements HandlerInterface
return $response;
}
private function addStaticRoute(StaticRouteInterface $staticRoute)
{
foreach ($staticRoute->getPaths() as $path) {
$this->staticRoutes[$path] = $staticRoute;
}
}
private function addPrefixRoute(PrefixRouteInterface $prefixRoute)
{
foreach ($prefixRoute->getPrefixes() as $prefix) {
$this->prefixRoutes[$prefix] = $prefixRoute;
}
}
private function getErrorResponse($status, $request, $args = null, $response = null)
{
if (isset($this->errorHandlers[$status])) {
/** @var HandlerInterface $errorHandler */
$errorHandler = new $this->errorHandlers[$status]();
$unpacker = new HandlerUnpacker();
$errorHandler = $unpacker->unpack($this->errorHandlers[$status]);
// Pass the response triggering this along to the error handler.
$errorArgs = array("response" => $response);
if ($args) {
@ -201,7 +185,7 @@ class Router implements HandlerInterface
}
/**
* Returning the matching static handler, or null if none match.
* Returning the handler associated with the matching static route, or null if none match.
*
* @param $path string The request's path
* @return HandlerInterface|null
@ -209,8 +193,8 @@ class Router implements HandlerInterface
private function getStaticHandler($path)
{
if (isset($this->staticRoutes[$path])) {
// Instantiate and return the handler identified by the path.
return new $this->staticRoutes[$path]();
$route = $this->staticRoutes[$path];
return $route->getHandler();
}
return null;
}
@ -237,7 +221,8 @@ class Router implements HandlerInterface
});
}
// Instantiate and return the handler identified as the best match.
return new $this->prefixRoutes[$matches[0]]();
$route = $this->prefixRoutes[$matches[0]];
return $route->getHandler();
}
return null;
}
@ -295,4 +280,28 @@ class Router implements HandlerInterface
}
return $response;
}
////////////////
// Deprecated //
////////////////
/**
* @deprecated Use {@see addRoute} instead.
* @see addRoute
*/
public function setPrefixRoute($prefixes, $handler)
{
$this->addPrefixRoute(new PrefixRoute($prefixes, $handler));
trigger_error("Router::setPrefixRoute is deprecated. Use addRoute", E_USER_DEPRECATED);
}
/**
* @deprecated Use {@see addRoute} instead.
* @see addRoute
*/
public function setStaticRoute($paths, $handler)
{
$this->addStaticRoute(new StaticRoute($paths, $handler));
trigger_error("Router::setStaticRoute is deprecated. Use addRoute", E_USER_DEPRECATED);
}
}

View File

@ -2,245 +2,341 @@
namespace pjdietz\WellRESTed\Test;
use pjdietz\WellRESTed\Exceptions\HttpExceptions\ForbiddenException;
use pjdietz\WellRESTed\Interfaces\HandlerInterface;
use pjdietz\WellRESTed\Interfaces\RequestInterface;
use pjdietz\WellRESTed\Interfaces\ResponseInterface;
use pjdietz\WellRESTed\Response;
use pjdietz\WellRESTed\Exceptions\HttpExceptions\HttpException;
use pjdietz\WellRESTed\Router;
use pjdietz\WellRESTed\Routes\PrefixRoute;
use pjdietz\WellRESTed\Routes\StaticRoute;
use pjdietz\WellRESTed\Routes\TemplateRoute;
use Prophecy\Argument;
/**
* @covers pjdietz\WellRESTed\Router
*/
class RouterTest extends \PHPUnit_Framework_TestCase
{
public function testAddRoute()
private $handler;
private $request;
private $response;
private $route;
public function setUp()
{
$path = "/";
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue($path));
$route = new StaticRoute($path, __NAMESPACE__ . '\\RouterTestHandler');
$router = new Router();
$router->addRoute($route);
$resp = $router->getResponse($mockRequest);
$this->assertNotNull($resp);
$this->request = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\RequestInterface");
$this->response = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\ResponseInterface");
$this->route = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$this->handler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
}
public function testAddRoutes()
public function testMatchesStaticRoute()
{
$path = "/";
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue($path));
$this->route->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\StaticRouteInterface");
$this->route->getPaths()->willReturn(["/cats/"]);
$this->route->getHandler()->willReturn($this->handler->reveal());
$routes = array();
$routes[] = new StaticRoute("/", __NAMESPACE__ . '\\RouterTestHandler');
$routes[] = new StaticRoute("/another/", __NAMESPACE__ . '\\RouterTestHandler');
$this->request->getPath()->willReturn("/cats/");
$router = new Router();
$router->addRoutes($routes);
$resp = $router->getResponse($mockRequest);
$this->assertEquals(200, $resp->getStatusCode());
$router->addRoute($this->route->reveal());
$router->getResponse($this->request->reveal());
$this->route->getHandler()->shouldHaveBeenCalled();
}
public function testAddStaticRoute()
public function testMatchesPrefixRoute()
{
$path = "/cats/";
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue($path));
$this->route->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$this->route->getPrefixes()->willReturn(["/cats/"]);
$this->route->getHandler()->willReturn($this->handler->reveal());
$this->request->getPath()->willReturn("/cats/molly");
$router = new Router();
$router->setStaticRoute($path, __NAMESPACE__ . '\\RouterTestHandler');
$resp = $router->getResponse($mockRequest);
$this->assertNotNull($resp);
$router->addRoute($this->route->reveal());
$router->getResponse($this->request->reveal());
$this->route->getHandler()->shouldHaveBeenCalled();
}
public function testAddPrefixRoute()
public function testMatchesBestPrefixRoute()
{
$path = "/cats/";
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue($path));
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route1->getPrefixes()->willReturn(["/animals/"]);
$route1->getHandler()->willReturn($this->handler->reveal());
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route2->getPrefixes()->willReturn(["/animals/cats/"]);
$route2->getHandler()->willReturn($this->handler->reveal());
$this->request->getPath()->willReturn("/animals/cats/molly");
$router = new Router();
$router->setPrefixRoute($path, __NAMESPACE__ . '\\RouterTestHandler');
$resp = $router->getResponse($mockRequest);
$this->assertNotNull($resp);
$router->addRoute($route1->reveal());
$router->addRoute($route2->reveal());
$router->getResponse($this->request->reveal());
$route1->getHandler()->shouldNotHaveBeenCalled();
$route2->getHandler()->shouldHaveBeenCalled();
}
public function testMatchStaticRouteBeforePrefixRoute()
public function testMatchesStaticRouteBeforePrefixRoute()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/amimals/cats/molly"));
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route1->getPrefixes()->willReturn(["/animals/cats/"]);
$route1->getHandler()->willReturn($this->handler->reveal());
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\StaticRouteInterface");
$route2->getPaths()->willReturn(["/animals/cats/molly"]);
$route2->getHandler()->willReturn($this->handler->reveal());
$this->request->getPath()->willReturn("/animals/cats/molly");
$router = new Router();
$router->addRoute(new PrefixRoute("/amimals/", __NAMESPACE__ . '\\NotFoundHandler'));
$router->addRoute(new PrefixRoute("/amimals/cats/", __NAMESPACE__ . '\\NotFoundHandler'));
$router->addRoute(new StaticRoute("/amimals/cats/molly", __NAMESPACE__ . '\\RouterTestHandler'));
$resp = $router->getResponse($mockRequest);
$this->assertEquals(200, $resp->getStatusCode());
$router->addRoute($route1->reveal());
$router->addRoute($route2->reveal());
$router->getResponse($this->request->reveal());
$route1->getHandler()->shouldNotHaveBeenCalled();
$route2->getHandler()->shouldHaveBeenCalled();
}
public function testMatchBestPrefixRoute()
public function testMatchesPrefixRouteBeforeHandlerRoute()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/amimals/cats/molly"));
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route1->getPrefixes()->willReturn(["/animals/cats/"]);
$route1->getHandler()->willReturn($this->handler->reveal());
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->getResponse(Argument::cetera())->willReturn(null);
$this->request->getPath()->willReturn("/animals/cats/molly");
$router = new Router();
$router->addRoute(new PrefixRoute("/amimals/", __NAMESPACE__ . '\\NotFoundHandler'));
$router->addRoute(new PrefixRoute("/amimals/dogs/", __NAMESPACE__ . '\\NotFoundHandler'));
$router->addRoute(new PrefixRoute("/amimals/cats/", __NAMESPACE__ . '\\RouterTestHandler'));
$resp = $router->getResponse($mockRequest);
$this->assertEquals(200, $resp->getStatusCode());
$router->addRoute($route1->reveal());
$router->addRoute($route2->reveal());
$router->getResponse($this->request->reveal());
$route1->getHandler()->shouldHaveBeenCalled();
$route2->getResponse(Argument::cetera())->shouldNotHaveBeenCalled();
}
public function testMatchBestPrefixRouteBeforeTemplateRoute()
public function testReturnsFirstNonNullResponse()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/amimals/cats/molly"));
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->getResponse(Argument::cetera())->willReturn(null);
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route3 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route3->getResponse(Argument::cetera())->willReturn(null);
$this->request->getPath()->willReturn("/");
$router = new Router();
$router->addRoute(new PrefixRoute("/amimals/", __NAMESPACE__ . '\\NotFoundHandler'));
$router->addRoute(new PrefixRoute("/amimals/cats/", __NAMESPACE__ . '\\RouterTestHandler'));
$router->addRoute(new TemplateRoute("/amimals/cats/*", __NAMESPACE__ . '\\NotFoundHandler'));
$resp = $router->getResponse($mockRequest);
$this->assertEquals(200, $resp->getStatusCode());
$router->addRoutes(
[
$route1->reveal(),
$route2->reveal(),
$route3->reveal()
]
);
$response = $router->getResponse($this->request->reveal());
$this->assertNotNull($response);
$route1->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route2->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route3->getResponse(Argument::cetera())->shouldNotHaveBeenCalled();
}
public function testRespondWithDefaultErrorForException()
public function testReturnsNullWhenNoRouteMatches()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/"));
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->getResponse(Argument::cetera())->willReturn(null);
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->getResponse(Argument::cetera())->willReturn(null);
$route3 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route3->getResponse(Argument::cetera())->willReturn(null);
$router = new Router();
$router->addRoute(new StaticRoute("/", __NAMESPACE__ . '\\ForbiddenExceptionHandler'));
$resp = $router->getResponse($mockRequest);
$this->assertEquals(403, $resp->getStatusCode());
$router->addRoutes(
[
$route1->reveal(),
$route2->reveal(),
$route3->reveal()
]
);
$response = $router->getResponse($this->request->reveal());
$this->assertNull($response);
$route1->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route2->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route3->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
public function testRespondWithErrorHandlerForException()
public function testRespondsWithErrorResponseForHttpException()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/"));
$this->route->getResponse(Argument::cetera())->willThrow(new HttpException());
$this->request->getPath()->willReturn("/");
$router = new Router();
$router->addRoute(new StaticRoute("/", __NAMESPACE__ . '\\ForbiddenExceptionHandler'));
$router->setErrorHandler(403, __NAMESPACE__ . '\\ForbiddenErrorHandler');
$resp = $router->getResponse($mockRequest);
$this->assertEquals("YOU SHALL NOT PASS!", $resp->getBody());
$router->addRoute($this->route->reveal());
$response = $router->getResponse($this->request->reveal());
$this->assertEquals(500, $response->getStatusCode());
}
public function testRespondWithErrorHandlerForStatusCode()
public function testDispatchesErrorHandlerForStatusCode()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/"));
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$this->route->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$router = new Router();
$router->addRoute(new StaticRoute("/", __NAMESPACE__ . '\\ForbiddenHandler'));
$router->setErrorHandler(403, __NAMESPACE__ . '\\ForbiddenErrorHandler');
$resp = $router->getResponse($mockRequest);
$this->assertEquals("YOU SHALL NOT PASS!", $resp->getBody());
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($this->request->reveal());
$errorHandler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
public function testRespondWithErrorHandlerUsingOriginalResponse()
public function testDispatchesErrorHandlerWithOriginalRequest()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/"));
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$this->route->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$request = $this->request->reveal();
$router = new Router();
$router->addRoute(new StaticRoute("/", __NAMESPACE__ . '\\MessageHandler'));
$router->setErrorHandlers([404 => __NAMESPACE__ . '\\MessageErrorHandler']);
$resp = $router->getResponse($mockRequest);
$this->assertEquals("<h1>Not Found</h1>", $resp->getBody());
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($request);
$errorHandler->getResponse(
Argument::that(
function ($arg) use ($request) {
return $arg === $request;
}
),
Argument::any()
)->shouldHaveBeenCalled();
}
public function testRespondWithErrorHandlerUsingInjection()
public function testDispatchesErrorHandlerWithOriginalArguments()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/"));
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$response = $this->response->reveal();
$this->route->getResponse(Argument::cetera())->willReturn($response);
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$arguments = [
"cat" => "Molly",
"dog" => "Bear"
];
$router = new Router();
$router->addRoute(new StaticRoute("/", __NAMESPACE__ . '\\ForbiddenHandler'));
$router->setErrorHandlers([403 => __NAMESPACE__ . '\\InjectionErrorHandler']);
$resp = $router->getResponse($mockRequest, ["message" => "Pass through"]);
$this->assertEquals("Pass through", $resp->getBody());
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($this->request->reveal(), $arguments);
$errorHandler->getResponse(
Argument::any(),
Argument::that(
function ($args) use ($arguments) {
return count(array_diff_assoc($arguments, $args)) === 0;
}
)
)->shouldHaveBeenCalled();
}
public function testReturnNullWhenNoRouteMatches()
public function testDispatchesErrorHandlerWithPreviousResponse()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/dog/"));
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$response = $this->response->reveal();
$this->route->getResponse(Argument::cetera())->willReturn($response);
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route = new StaticRoute("/cat/", __NAMESPACE__ . '\\RouterTestHandler');
$router = new Router();
$router->addRoute($route);
$resp = $router->getResponse($mockRequest);
$this->assertNull($resp);
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($this->request->reveal());
$errorHandler->getResponse(
Argument::any(),
Argument::that(
function ($arg) use ($response) {
return isset($arg["response"]) && $arg["response"] === $response;
}
public function testNestedRouters()
{
$path = "/cats/";
$router1 = new Router();
$router2 = new Router();
$router3 = new Router();
$router1->addRoute($router2);
$router2->addRoute($router3);
$router3->addRoute(new StaticRoute($path, __NAMESPACE__ . '\\RouterTestHandler'));
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue($path));
$resp = $router1->getResponse($mockRequest);
$this->assertNotNull($resp);
)
)->shouldHaveBeenCalled();
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testStaticRequestDoesNotMatchRouter()
public function testRoutesStaticRequest()
{
$_SERVER["REQUEST_URI"] = "/cats/";
$_SERVER["HTTP_HOST"] = "localhost";
$_SERVER["REQUEST_METHOD"] = "GET";
$route = new StaticRoute("/dogs/", __NAMESPACE__ . '\\RouterTestHandler');
$this->response->getStatusCode()->willReturn(200);
$this->response->respond()->willReturn();
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->route->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\StaticRouteInterface");
$this->route->getPaths()->willReturn(["/cats/"]);
$this->route->getHandler()->willReturn($this->handler->reveal());
$router = new Router();
$router->addRoute($route);
$router->addRoute($this->route->reveal());
ob_start();
$router->respond();
ob_end_clean();
$this->response->respond()->shouldHaveBeenCalled();
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testRoutesStaticRequestToNoRouteResponse()
{
$_SERVER["REQUEST_URI"] = "/cats/";
$_SERVER["HTTP_HOST"] = "localhost";
$_SERVER["REQUEST_METHOD"] = "GET";
$router = new Router();
ob_start();
$router->respond();
$captured = ob_get_contents();
@ -253,193 +349,46 @@ class RouterTest extends \PHPUnit_Framework_TestCase
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testRespondWithErrorHandlerForNoRoute()
public function testRoutesStaticRequestTo404ErrorHandler()
{
$_SERVER["REQUEST_URI"] = "/cats/";
$_SERVER["HTTP_HOST"] = "localhost";
$_SERVER["REQUEST_METHOD"] = "GET";
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$router = new Router();
$router->setErrorHandler(404, __NAMESPACE__ . '\\MessageHandler');
$router->setErrorHandler(404, $errorHandler->reveal());
ob_start();
$router->respond();
$captured = ob_get_contents();
ob_end_clean();
$this->assertEquals("Not Found", $captured);
$errorHandler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
/**
* @dataProvider nestedRouterRoutesProvider
*/
public function testNestedRouterFromWithRoutes($path, $expectedBody)
public function testDeprecatedSetStaticRoute()
{
$router = new Router();
$router->addRoutes(array(
new TemplateRoute("/cats/*", __NAMESPACE__ . "\\CatRouter"),
new TemplateRoute("/dogs/*", __NAMESPACE__ . "\\DogRouter"),
new NotFoundHandler()
));
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue($path));
$resp = $router->getResponse($mockRequest);
$this->assertEquals($expectedBody, $resp->getBody());
}
public function nestedRouterRoutesProvider()
{
return [
["/cats/", "/cats/"],
["/cats/molly", "/cats/molly"],
["/dogs/", "/dogs/"],
["/birds/", "No resource found at /birds/"]
];
}
public function testInjection()
{
$mockRequest = $this->getMock('\pjdietz\WellRESTed\Interfaces\RequestInterface');
$mockRequest->expects($this->any())
->method('getPath')
->will($this->returnValue("/2/3"));
$dependencies = [
"add" => function ($a, $b) {
return $a + $b;
}
];
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->request->getPath()->willReturn("/cats/");
$router = new Router();
$router->addRoute(new TemplateRoute("/{a}/{b}", __NAMESPACE__ . "\\InjectionHandler"));
$resp = $router->getResponse($mockRequest, $dependencies);
$this->assertEquals("5", $resp->getBody());
@$router->setStaticRoute(["/cats/"], $this->handler->reveal());
$router->getResponse($this->request->reveal());
$this->handler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
}
public function testDeprecatedSetPrefixRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->request->getPath()->willReturn("/cats/molly");
/**
* Mini Handler class that allways returns a 200 status code Response.
*/
class RouterTestHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
$resp = new Response();
$resp->setStatusCode(200);
$resp->setBody($request->getPath());
return $resp;
}
}
$router = new Router();
@$router->setPrefixRoute(["/cats/"], $this->handler->reveal());
$router->getResponse($this->request->reveal());
class CatRouter extends Router
{
public function __construct()
{
parent::__construct();
$this->addRoutes([
new StaticRoute("/cats/", __NAMESPACE__ . "\\RouterTestHandler"),
new StaticRoute("/cats/molly", __NAMESPACE__ . "\\RouterTestHandler"),
new StaticRoute("/cats/oscar", __NAMESPACE__ . "\\RouterTestHandler")
]);
}
}
class DogRouter extends Router
{
public function __construct()
{
parent::__construct();
$this->addRoutes([
new StaticRoute("/dogs/", __NAMESPACE__ . "\\RouterTestHandler"),
new StaticRoute("/dogs/bear", __NAMESPACE__ . "\\RouterTestHandler")
]);
}
}
class NotFoundHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
$response = new Response(404);
$response->setBody("No resource found at " . $request->getPath());
return $response;
}
}
class ForbiddenHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
$response = new Response(403);
$response->setBody("Forbidden");
return $response;
}
}
class ForbiddenExceptionHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
throw new ForbiddenException();
}
}
class ForbiddenErrorHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
$response = new Response(403);
$response->setBody("YOU SHALL NOT PASS!");
return $response;
}
}
class MessageHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
$response = new Response(404);
$response->setBody("Not Found");
return $response;
}
}
class MessageErrorHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
if (isset($args["response"])) {
/** @var ResponseInterface $response */
$response = $args["response"];
$message = "<h1>" . $response->getBody() . "</h1>";
$response->setBody($message);
return $response;
}
return null;
}
}
class InjectionErrorHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
$response = new Response(403);
$response->setBody($args["message"]);
return $response;
}
}
class InjectionHandler implements HandlerInterface
{
public function getResponse(RequestInterface $request, array $args = null)
{
$response = new Response(200);
$body = $args["add"]($args["a"], $args["b"]);
$response->setBody($body);
return $response;
$this->handler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
}