Remove MethodMapInterface

This commit is contained in:
PJ Dietz 2018-06-22 15:10:50 -04:00
parent 73b6e4ab83
commit ac8bdce037
10 changed files with 121 additions and 160 deletions

View File

@ -6,7 +6,7 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Dispatching\DispatcherInterface;
class MethodMap implements MethodMapInterface class MethodMap
{ {
private $dispatcher; private $dispatcher;
private $map; private $map;

View File

@ -1,39 +0,0 @@
<?php
namespace WellRESTed\Routing;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use WellRESTed\MiddlewareInterface;
/**
* Maps HTTP methods to handlers and middleware
*/
interface MethodMapInterface extends MiddlewareInterface
{
/**
* Evaluate $request's method and dispatches matching dispatchable.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callable $next
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next);
/**
* 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

@ -4,13 +4,13 @@ namespace WellRESTed\Routing\Route;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use WellRESTed\Routing\MethodMapInterface; use WellRESTed\Routing\MethodMap;
abstract class Route implements RouteInterface abstract class Route implements RouteInterface
{ {
/** @var string */ /** @var string */
protected $target; protected $target;
/** @var MethodMapInterface */ /** @var MethodMap */
protected $methodMap; protected $methodMap;
public function __construct($target, $methodMap) public function __construct($target, $methodMap)
@ -19,16 +19,6 @@ abstract class Route implements RouteInterface
$this->methodMap = $methodMap; $this->methodMap = $methodMap;
} }
/**
* Return the instance mapping methods to middleware for this route.
*
* @return MethodMapInterface
*/
public function getMethodMap()
{
return $this->methodMap;
}
/** /**
* @return string * @return string
*/ */

View File

@ -3,7 +3,6 @@
namespace WellRESTed\Routing\Route; namespace WellRESTed\Routing\Route;
use WellRESTed\MiddlewareInterface; use WellRESTed\MiddlewareInterface;
use WellRESTed\Routing\MethodMapInterface;
interface RouteInterface extends MiddlewareInterface interface RouteInterface extends MiddlewareInterface
{ {
@ -48,13 +47,6 @@ interface RouteInterface extends MiddlewareInterface
*/ */
public function getPathVariables(); public function getPathVariables();
/**
* Return the instance mapping methods to middleware for this route.
*
* @return MethodMapInterface
*/
public function getMethodMap();
/** /**
* Examines a request target to see if it is a match for the route. * Examines a request target to see if it is a match for the route.
* *

View File

@ -111,37 +111,44 @@ class Router implements RouterInterface
} }
/** /**
* Register middleware with the router for a given path and method. * Register handlers and middleware with the router for a given path and
* method.
* *
* $method may be: * $method may be:
* - A single verb ("GET"), * - A single verb ("GET"),
* - A comma-separated list of verbs ("GET,PUT,DELETE") * - A comma-separated list of verbs ("GET,PUT,DELETE")
* - "*" to indicate any method. * - "*" to indicate any method.
* @see MethodMapInterface::register
* *
* $target may be: * $target may be:
* - An exact path (e.g., "/path/") * - An exact path (e.g., "/path/")
* - An prefix path ending with "*"" ("/path/*"") * - A prefix path ending with "*"" ("/path/*"")
* - A URI template with variables enclosed in "{}" ("/path/{id}") * - A URI template with variables enclosed in "{}" ("/path/{id}")
* - A regular expression ("~/cat/([0-9]+)~") * - A regular expression ("~/cat/([0-9]+)~")
* *
* $middleware may be: * $dispatchable may be:
* - An instance implementing MiddlewareInterface * - An instance implementing one of these interfaces:
* - Psr\Http\Server\RequestHandlerInterface
* - Psr\Http\Server\MiddlewareInterface
* - WellRESTed\MiddlewareInterface
* - Psr\Http\Message\ResponseInterface
* - A string containing the fully qualified class name of a class * - A string containing the fully qualified class name of a class
* implementing MiddlewareInterface * implementing one of the interfaces listed above.
* - A callable that returns an instance implementing MiddleInterface * - A callable that returns an instance implementing one of the
* - A callable matching the signature of MiddlewareInterface::dispatch * interfaces listed above.
* - A callable with a signature matching the signature of
* WellRESTed\MiddlewareInterface::__invoke
* - An array containing any of the items in this list.
* @see DispatchedInterface::dispatch * @see DispatchedInterface::dispatch
* *
* @param string $target Request target or pattern to match * @param string $target Request target or pattern to match
* @param string $method HTTP method(s) to match * @param string $method HTTP method(s) to match
* @param mixed $middleware Middleware to dispatch * @param mixed $dispatchable Handler or middleware to dispatch
* @return self * @return static
*/ */
public function register($method, $target, $middleware) public function register($method, $target, $dispatchable)
{ {
$route = $this->getRouteForTarget($target); $route = $this->getRouteForTarget($target);
$route->register($method, $middleware); $route->register($method, $dispatchable);
return $this; return $this;
} }

View File

@ -25,34 +25,41 @@ interface RouterInterface extends MiddlewareInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next); public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next);
/** /**
* Register middleware with the router for a given path and method. * Register handlers and middleware with the router for a given path and
* method.
* *
* $method may be: * $method may be:
* - A single verb ("GET") * - A single verb ("GET"),
* - A comma-separated list of verbs ("GET,PUT,DELETE") * - A comma-separated list of verbs ("GET,PUT,DELETE")
* - "*" to indicate any method * - "*" to indicate any method.
* @see MethodMapInterface::register
* *
* $target may be: * $target may be:
* - An exact path (e.g., "/path/") * - An exact path (e.g., "/path/")
* - A prefix path ending with "*"" ("/path/*"") * - A prefix path ending with "*"" ("/path/*"")
* - A URI template with one or more variables ("/path/{id}") * - A URI template with variables enclosed in "{}" ("/path/{id}")
* - A regular expression ("~/cat/([0-9]+)~") * - A regular expression ("~/cat/([0-9]+)~")
* *
* $middleware may be: * $dispatchable may be:
* - An instance implementing MiddlewareInterface * - An instance implementing one of these interfaces:
* - Psr\Http\Server\RequestHandlerInterface
* - Psr\Http\Server\MiddlewareInterface
* - WellRESTed\MiddlewareInterface
* - Psr\Http\Message\ResponseInterface
* - A string containing the fully qualified class name of a class * - A string containing the fully qualified class name of a class
* implementing MiddlewareInterface * implementing one of the interfaces listed above.
* - A callable that returns an instance implementing MiddleInterface * - A callable that returns an instance implementing one of the
* - A callable matching the signature of MiddlewareInterface::dispatch * interfaces listed above.
* - A callable with a signature matching the signature of
* WellRESTed\MiddlewareInterface::__invoke
* - An array containing any of the items in this list.
* @see DispatchedInterface::dispatch * @see DispatchedInterface::dispatch
* *
* @param string $target Request target or pattern to match * @param string $target Request target or pattern to match
* @param string $method HTTP method(s) to match * @param string $method HTTP method(s) to match
* @param mixed $middleware Middleware to dispatch * @param mixed $dispatchable Middleware to dispatch
* @return static * @return static
*/ */
public function register($method, $target, $middleware); public function register($method, $target, $dispatchable);
/** /**
* Push a new middleware onto the stack. Middleware for a router runs only * Push a new middleware onto the stack. Middleware for a router runs only

View File

@ -2,6 +2,7 @@
namespace WellRESTed\Test\Unit\Routing\Route; namespace WellRESTed\Test\Unit\Routing\Route;
use WellRESTed\Routing\MethodMap;
use WellRESTed\Routing\Route\PrefixRoute; use WellRESTed\Routing\Route\PrefixRoute;
use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\RouteInterface;
use WellRESTed\Test\TestCase; use WellRESTed\Test\TestCase;
@ -10,43 +11,43 @@ class PrefixRouteTest extends TestCase
{ {
public function testTrimsAsteriskFromEndOfTarget() public function testTrimsAsteriskFromEndOfTarget()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new PrefixRoute("/cats/*", $methodMap->reveal()); $route = new PrefixRoute('/cats/*', $methodMap->reveal());
$this->assertEquals("/cats/", $route->getTarget()); $this->assertEquals('/cats/', $route->getTarget());
} }
public function testReturnsPrefixType() public function testReturnsPrefixType()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new PrefixRoute("/*", $methodMap->reveal()); $route = new PrefixRoute('/*', $methodMap->reveal());
$this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType()); $this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType());
} }
public function testReturnsEmptyArrayForPathVariables() public function testReturnsEmptyArrayForPathVariables()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new PrefixRoute("/*", $methodMap->reveal()); $route = new PrefixRoute('/*', $methodMap->reveal());
$this->assertSame([], $route->getPathVariables()); $this->assertSame([], $route->getPathVariables());
} }
public function testMatchesExactRequestTarget() public function testMatchesExactRequestTarget()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new PrefixRoute("/*", $methodMap->reveal()); $route = new PrefixRoute('/*', $methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget("/")); $this->assertTrue($route->matchesRequestTarget('/'));
} }
public function testMatchesRequestTargetWithSamePrefix() public function testMatchesRequestTargetWithSamePrefix()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new PrefixRoute("/*", $methodMap->reveal()); $route = new PrefixRoute('/*', $methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget("/cats/")); $this->assertTrue($route->matchesRequestTarget('/cats/'));
} }
public function testDoesNotMatchNonmatchingRequestTarget() public function testDoesNotMatchNonmatchingRequestTarget()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new PrefixRoute("/animals/cats/", $methodMap->reveal()); $route = new PrefixRoute('/animals/cats/', $methodMap->reveal());
$this->assertFalse($route->matchesRequestTarget("/animals/dogs/")); $this->assertFalse($route->matchesRequestTarget('/animals/dogs/'));
} }
} }

View File

@ -4,6 +4,7 @@ namespace WellRESTed\Test\Unit\Routing\Route;
use PHPUnit\Framework\Error\Notice; use PHPUnit\Framework\Error\Notice;
use PHPUnit\Framework\Error\Warning; use PHPUnit\Framework\Error\Warning;
use WellRESTed\Routing\MethodMap;
use WellRESTed\Routing\Route\RegexRoute; use WellRESTed\Routing\Route\RegexRoute;
use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\RouteInterface;
use WellRESTed\Test\TestCase; use WellRESTed\Test\TestCase;
@ -14,12 +15,12 @@ class RegexRouteTest extends TestCase
public function setUp() public function setUp()
{ {
$this->methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $this->methodMap = $this->prophesize(MethodMap::class);
} }
public function testReturnsPatternType() public function testReturnsPatternType()
{ {
$route = new RegexRoute("/", $this->methodMap->reveal()); $route = new RegexRoute('/', $this->methodMap->reveal());
$this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType());
} }
@ -48,16 +49,16 @@ class RegexRouteTest extends TestCase
public function matchingRouteProvider() public function matchingRouteProvider()
{ {
return [ return [
["~/cat/[0-9]+~", "/cat/2", [0 => "/cat/2"]], ['~/cat/[0-9]+~', '/cat/2', [0 => '/cat/2']],
["#/dog/.*#", "/dog/his-name-is-bear", [0 => "/dog/his-name-is-bear"]], ['#/dog/.*#', '/dog/his-name-is-bear', [0 => '/dog/his-name-is-bear']],
["~/cat/([0-9]+)~", "/cat/2", [ ['~/cat/([0-9]+)~', '/cat/2', [
0 => "/cat/2", 0 => '/cat/2',
1 => "2" 1 => '2'
]], ]],
["~/dog/(?<id>[0-9+])~", "/dog/2", [ ['~/dog/(?<id>[0-9+])~', '/dog/2', [
0 => "/dog/2", 0 => '/dog/2',
1 => "2", 1 => '2',
"id" => "2" 'id' => '2'
]] ]]
]; ];
} }
@ -72,9 +73,9 @@ class RegexRouteTest extends TestCase
public function mismatchingRouteProvider() public function mismatchingRouteProvider()
{ {
return [ return [
["~/cat/[0-9]+~", "/cat/molly"], ['~/cat/[0-9]+~', '/cat/molly'],
["~/cat/[0-9]+~", "/dog/bear"], ['~/cat/[0-9]+~', '/dog/bear'],
["#/dog/.*#", "/dog"] ['#/dog/.*#', '/dog']
]; ];
} }
@ -89,7 +90,7 @@ class RegexRouteTest extends TestCase
Notice::$enabled = false; Notice::$enabled = false;
$level = error_reporting(); $level = error_reporting();
error_reporting($level & ~E_WARNING); error_reporting($level & ~E_WARNING);
$route->matchesRequestTarget("/"); $route->matchesRequestTarget('/');
error_reporting($level); error_reporting($level);
Warning::$enabled = true; Warning::$enabled = true;
Notice::$enabled = true; Notice::$enabled = true;
@ -98,8 +99,8 @@ class RegexRouteTest extends TestCase
public function invalidRouteProvider() public function invalidRouteProvider()
{ {
return [ return [
["~/unterminated"], ['~/unterminated'],
["/nope"] ['/nope']
]; ];
} }
} }

View File

@ -2,6 +2,7 @@
namespace WellRESTed\Test\Unit\Routing\Route; namespace WellRESTed\Test\Unit\Routing\Route;
use WellRESTed\Routing\MethodMap;
use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\RouteInterface;
use WellRESTed\Routing\Route\StaticRoute; use WellRESTed\Routing\Route\StaticRoute;
use WellRESTed\Test\TestCase; use WellRESTed\Test\TestCase;
@ -10,29 +11,29 @@ class StaticRouteTest extends TestCase
{ {
public function testReturnsStaticType() public function testReturnsStaticType()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new StaticRoute("/", $methodMap->reveal()); $route = new StaticRoute('/', $methodMap->reveal());
$this->assertSame(RouteInterface::TYPE_STATIC, $route->getType()); $this->assertSame(RouteInterface::TYPE_STATIC, $route->getType());
} }
public function testMatchesExactRequestTarget() public function testMatchesExactRequestTarget()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new StaticRoute("/", $methodMap->reveal()); $route = new StaticRoute('/', $methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget("/")); $this->assertTrue($route->matchesRequestTarget('/'));
} }
public function testReturnsEmptyArrayForPathVariables() public function testReturnsEmptyArrayForPathVariables()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new StaticRoute("/", $methodMap->reveal()); $route = new StaticRoute('/', $methodMap->reveal());
$this->assertSame([], $route->getPathVariables()); $this->assertSame([], $route->getPathVariables());
} }
public function testDoesNotMatchNonmatchingRequestTarget() public function testDoesNotMatchNonmatchingRequestTarget()
{ {
$methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $methodMap = $this->prophesize(MethodMap::class);
$route = new StaticRoute("/", $methodMap->reveal()); $route = new StaticRoute('/', $methodMap->reveal());
$this->assertFalse($route->matchesRequestTarget("/cats/")); $this->assertFalse($route->matchesRequestTarget('/cats/'));
} }
} }

View File

@ -2,6 +2,7 @@
namespace WellRESTed\Test\Unit\Routing\Route; namespace WellRESTed\Test\Unit\Routing\Route;
use WellRESTed\Routing\MethodMap;
use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\RouteInterface;
use WellRESTed\Routing\Route\TemplateRoute; use WellRESTed\Routing\Route\TemplateRoute;
use WellRESTed\Test\TestCase; use WellRESTed\Test\TestCase;
@ -12,22 +13,22 @@ class TemplateRouteTest extends TestCase
public function setUp() public function setUp()
{ {
$this->methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); $this->methodMap = $this->prophesize(MethodMap::class);
} }
private function getExpectedValues($keys) private function getExpectedValues($keys)
{ {
$expectedValues = [ $expectedValues = [
"var" => "value", 'var' => 'value',
"hello" => "Hello World!", 'hello' => 'Hello World!',
"x" => "1024", 'x' => '1024',
"y" => "768", 'y' => '768',
"path" => "/foo/bar", 'path' => '/foo/bar',
"who" => "fred", 'who' => 'fred',
"half" => "50%", 'half' => '50%',
"empty" => "", 'empty' => '',
"count" => ["one", "two", "three"], 'count' => ['one', 'two', 'three'],
"list" => ["red", "green", "blue"] 'list' => ['red', 'green', 'blue']
]; ];
return array_intersect_key($expectedValues, array_flip($keys)); return array_intersect_key($expectedValues, array_flip($keys));
} }
@ -43,7 +44,7 @@ class TemplateRouteTest extends TestCase
public function testReturnsPatternType() public function testReturnsPatternType()
{ {
$route = new TemplateRoute("/", $this->methodMap->reveal()); $route = new TemplateRoute('/', $this->methodMap->reveal());
$this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType());
} }
@ -60,10 +61,10 @@ class TemplateRouteTest extends TestCase
public function nonMatchingTargetProvider() public function nonMatchingTargetProvider()
{ {
return [ return [
["/foo/{var}", "/bar/12", "Mismatch before first template expression"], ['/foo/{var}', '/bar/12', 'Mismatch before first template expression'],
["/foo/{foo}/bar/{bar}", "/foo/12/13", "Mismatch after first template expression"], ['/foo/{foo}/bar/{bar}', '/foo/12/13', 'Mismatch after first template expression'],
["/hello/{hello}", "/hello/Hello%20World!", "Requires + operator to match reserved characters"], ['/hello/{hello}', '/hello/Hello%20World!', 'Requires + operator to match reserved characters'],
["{/var}", "/bar/12", "Path contains more segments than template"], ['{/var}', '/bar/12', 'Path contains more segments than template'],
]; ];
} }
@ -88,11 +89,11 @@ class TemplateRouteTest extends TestCase
public function simpleStringProvider() public function simpleStringProvider()
{ {
return [ return [
["/foo", "/foo", []], ['/foo', '/foo', []],
["/{var}", "/value", ["var"]], ['/{var}', '/value', ['var']],
["/{hello}", "/Hello%20World%21", ["hello"]], ['/{hello}', '/Hello%20World%21', ['hello']],
["/{x,hello,y}", "/1024,Hello%20World%21,768", ["x", "hello", "y"]], ['/{x,hello,y}', '/1024,Hello%20World%21,768', ['x', 'hello', 'y']],
["/{x,hello,y}", "/1024,Hello%20World%21,768", ["x", "hello", "y"]], ['/{x,hello,y}', '/1024,Hello%20World%21,768', ['x', 'hello', 'y']],
]; ];
} }
@ -117,9 +118,9 @@ class TemplateRouteTest extends TestCase
public function reservedStringProvider() public function reservedStringProvider()
{ {
return [ return [
["/{+var}", "/value", ["var"]], ['/{+var}', '/value', ['var']],
["/{+hello}", "/Hello%20World!", ["hello"]], ['/{+hello}', '/Hello%20World!', ['hello']],
["{+path}/here", "/foo/bar/here", ["path"]], ['{+path}/here', '/foo/bar/here', ['path']],
]; ];
} }
@ -144,9 +145,9 @@ class TemplateRouteTest extends TestCase
public function labelWithDotPrefixProvider() public function labelWithDotPrefixProvider()
{ {
return [ return [
["/{.who}", "/.fred", ["who"]], ['/{.who}', '/.fred', ['who']],
["/{.half,who}", "/.50%25.fred", ["half", "who"]], ['/{.half,who}', '/.50%25.fred', ['half', 'who']],
["/X{.empty}", "/X.", ["empty"]] ['/X{.empty}', '/X.', ['empty']]
]; ];
} }
@ -171,9 +172,9 @@ class TemplateRouteTest extends TestCase
public function pathSegmentProvider() public function pathSegmentProvider()
{ {
return [ return [
["{/who}", "/fred", ["who"]], ['{/who}', '/fred', ['who']],
["{/half,who}", "/50%25/fred", ["half", "who"]], ['{/half,who}', '/50%25/fred', ['half', 'who']],
["{/var,empty}", "/value/", ["var", "empty"]] ['{/var,empty}', '/value/', ['var', 'empty']]
]; ];
} }
@ -198,9 +199,9 @@ class TemplateRouteTest extends TestCase
public function pathExplosionProvider() public function pathExplosionProvider()
{ {
return [ return [
["/{count*}", "/one,two,three", ["count"]], ['/{count*}', '/one,two,three', ['count']],
["{/count*}", "/one/two/three", ["count"]], ['{/count*}', '/one/two/three', ['count']],
["X{.list*}", "X.red.green.blue", ["list"]] ['X{.list*}', 'X.red.green.blue', ['list']]
]; ];
} }
} }