Add Route::register method to delegate to MethodMap

This commit is contained in:
PJ Dietz 2018-06-22 14:44:43 -04:00
parent 72d5df244d
commit 9b29f2a09e
5 changed files with 93 additions and 61 deletions

View File

@ -23,33 +23,28 @@ class MethodMap implements MethodMapInterface
// MethodMapInterface
/**
* Register middleware with a method.
* Register a dispatchable (handler or middleware) with a method.
*
* $method may be:
* - A single verb ("GET"),
* - A comma-separated list of verbs ("GET,PUT,DELETE")
* - "*" to indicate any method.
*
* $middleware may be:
* - An instance implementing MiddlewareInterface
* - A string containing the fully qualified class name of a class
* implementing MiddlewareInterface
* - A callable that returns an instance implementing MiddleInterface
* - A callable matching the signature of MiddlewareInterface::dispatch
* @see DispatchedInterface::dispatch
* $dispatchable may be anything a Dispatcher can dispatch.
* @see DispatcherInterface::dispatch
*
* $middleware may also be null, in which case any previously set
* middleware for that method or methods will be unset.
* $dispatchable may also be null, in which case any previously set
* handlers and middle for that method or methods will be unset.
*
* @param string $method
* @param mixed $middleware
* @param mixed $dispatchable
*/
public function register($method, $middleware)
public function register($method, $dispatchable)
{
$methods = explode(",", $method);
$methods = array_map("trim", $methods);
foreach ($methods as $method) {
$this->map[$method] = $middleware;
$this->map[$method] = $dispatchable;
}
}
@ -62,8 +57,11 @@ class MethodMap implements MethodMapInterface
* @param callable $next
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
$next
) {
$method = $request->getMethod();
// Dispatch middleware registered with the explicitly matching method.
if (isset($this->map[$method])) {
@ -119,8 +117,12 @@ class MethodMap implements MethodMapInterface
* @param $next
* @return ResponseInterface
*/
private function dispatchMiddleware($middleware, ServerRequestInterface $request, ResponseInterface &$response, $next)
{
private function dispatchMiddleware(
$middleware,
ServerRequestInterface $request,
ResponseInterface &$response,
$next
) {
return $this->dispatcher->dispatch($middleware, $request, $response, $next);
}
}

View File

@ -7,15 +7,12 @@ use Psr\Http\Message\ServerRequestInterface;
use WellRESTed\MiddlewareInterface;
/**
* Maps HTTP methods to middleware
* Maps HTTP methods to handlers and middleware
*/
interface MethodMapInterface extends MiddlewareInterface
{
/**
* Evaluate $request's method and dispatches matching middleware.
*
* Implementations MUST pass $request, $response, and $next to the matching
* middleware.
* Evaluate $request's method and dispatches matching dispatchable.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
@ -25,23 +22,18 @@ interface MethodMapInterface extends MiddlewareInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next);
/**
* Register middleware with a method.
* Register a dispatchable (handler or middleware) with a method.
*
* $method may be:
* - A single verb ("GET"),
* - A comma-separated list of verbs ("GET,PUT,DELETE")
* - "*" to indicate any method.
*
* $middleware may be:
* - An instance implementing MiddlewareInterface
* - A string containing the fully qualified class name of a class
* implementing MiddlewareInterface
* - A callable that returns an instance implementing MiddleInterface
* - A callable matching the signature of MiddlewareInterface::dispatch
* $dispatchable may be anything a Dispatcher can dispatch.
* @see DispatcherInterface::dispatch
*
* @param string $method
* @param mixed $middleware
* @param mixed $dispatchable
*/
public function register($method, $middleware);
public function register($method, $dispatchable);
}

View File

@ -37,6 +37,25 @@ abstract class Route implements RouteInterface
return $this->target;
}
/**
* Register a dispatchable (handler or middleware) with a method.
*
* $method may be:
* - A single verb ("GET"),
* - A comma-separated list of verbs ("GET,PUT,DELETE")
* - "*" to indicate any method.
*
* $dispatchable may be anything a Dispatcher can dispatch.
* @see DispatcherInterface::dispatch
*
* @param string $method
* @param mixed $dispatchable
*/
public function register($method, $dispatchable)
{
$this->methodMap->register($method, $dispatchable);
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
$map = $this->methodMap;

View File

@ -64,4 +64,20 @@ interface RouteInterface extends MiddlewareInterface
* invalid regular expression
*/
public function matchesRequestTarget($requestTarget);
/**
* Register a dispatchable (handler or middleware) with a method.
*
* $method may be:
* - A single verb ("GET"),
* - A comma-separated list of verbs ("GET,PUT,DELETE")
* - "*" to indicate any method.
*
* $dispatchable may be anything a Dispatcher can dispatch.
* @see DispatcherInterface::dispatch
*
* @param string $method
* @param mixed $dispatchable
*/
public function register($method, $dispatchable);
}

View File

@ -3,53 +3,56 @@
namespace WellRESTed\Test\Unit\Routing\Route;
use Prophecy\Argument;
use Psr\Http\Server\RequestHandlerInterface;
use WellRESTed\Message\Response;
use WellRESTed\Message\ServerRequest;
use WellRESTed\Routing\MethodMap;
use WellRESTed\Routing\Route\StaticRoute;
use WellRESTed\Test\TestCase;
class RouteTest extends TestCase
{
public function testCreatesInstance()
const TARGET = '/target';
private $methodMap;
private $route;
public function setUp()
{
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface');
$route = $this->getMockForAbstractClass(
'WellRESTed\Routing\Route\Route',
["/target", $methodMap->reveal()]);
$this->assertNotNull($route);
$this->methodMap = $this->prophesize(MethodMap::class);
$this->methodMap->register(Argument::cetera())
->willReturn();
$this->methodMap->__invoke(Argument::cetera())
->willReturn(new Response());
$this->route = new StaticRoute(
self::TARGET, $this->methodMap->reveal());
}
public function testReturnsTarget()
{
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface');
$route = $this->getMockForAbstractClass(
'WellRESTed\Routing\Route\Route',
["/target", $methodMap->reveal()]);
$this->assertSame("/target", $route->getTarget());
$this->assertSame(self::TARGET, $this->route->getTarget());
}
public function testReturnsMethodMap()
public function testRegistersDispatchableWithMethodMap()
{
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface');
$route = $this->getMockForAbstractClass(
'WellRESTed\Routing\Route\Route',
["/target", $methodMap->reveal()]);
$this->assertSame($methodMap->reveal(), $route->getMethodMap());
$handler = $this->prophesize(RequestHandlerInterface::class)->reveal();
$this->route->register('GET', $handler);
$this->methodMap->register('GET', $handler)->shouldHaveBeenCalled();
}
public function testDispatchesMethodMap()
{
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface');
$methodMap->__invoke(Argument::cetera())->willReturn();
$route = $this->getMockForAbstractClass(
'WellRESTed\Routing\Route\Route',
["/target", $methodMap->reveal()]);
$request = $this->prophesize('Psr\Http\Message\ServerRequestInterface')->reveal();
$response = $this->prophesize('Psr\Http\Message\ResponseInterface')->reveal();
$next = function ($request, $response) {
return $response;
$request = new ServerRequest();
$response = new Response();
$next = function ($rqst, $resp) {
return $resp;
};
$route->__invoke($request, $response, $next);
$methodMap->__invoke(Argument::cetera())->shouldHaveBeenCalled();
$this->route->__invoke($request, $response, $next);
$this->methodMap->__invoke(Argument::cetera())->shouldHaveBeenCalled();
}
}