diff --git a/src/Routing/MethodMap.php b/src/Routing/MethodMap.php index 76a230f..20c5134 100644 --- a/src/Routing/MethodMap.php +++ b/src/Routing/MethodMap.php @@ -6,7 +6,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use WellRESTed\Dispatching\DispatcherInterface; -class MethodMap implements MethodMapInterface +class MethodMap { private $dispatcher; private $map; diff --git a/src/Routing/MethodMapInterface.php b/src/Routing/MethodMapInterface.php deleted file mode 100644 index 2ac0e6a..0000000 --- a/src/Routing/MethodMapInterface.php +++ /dev/null @@ -1,39 +0,0 @@ -methodMap = $methodMap; } - /** - * Return the instance mapping methods to middleware for this route. - * - * @return MethodMapInterface - */ - public function getMethodMap() - { - return $this->methodMap; - } - /** * @return string */ diff --git a/src/Routing/Route/RouteInterface.php b/src/Routing/Route/RouteInterface.php index 3339a1f..22413a3 100644 --- a/src/Routing/Route/RouteInterface.php +++ b/src/Routing/Route/RouteInterface.php @@ -3,7 +3,6 @@ namespace WellRESTed\Routing\Route; use WellRESTed\MiddlewareInterface; -use WellRESTed\Routing\MethodMapInterface; interface RouteInterface extends MiddlewareInterface { @@ -48,13 +47,6 @@ interface RouteInterface extends MiddlewareInterface */ 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. * diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 3653c95..1bf8a50 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -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: * - A single verb ("GET"), * - A comma-separated list of verbs ("GET,PUT,DELETE") * - "*" to indicate any method. - * @see MethodMapInterface::register * * $target may be: * - 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 regular expression ("~/cat/([0-9]+)~") * - * $middleware may be: - * - An instance implementing MiddlewareInterface + * $dispatchable may be: + * - 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 - * implementing MiddlewareInterface - * - A callable that returns an instance implementing MiddleInterface - * - A callable matching the signature of MiddlewareInterface::dispatch + * implementing one of the interfaces listed above. + * - A callable that returns an instance implementing one of the + * 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 * * @param string $target Request target or pattern to match * @param string $method HTTP method(s) to match - * @param mixed $middleware Middleware to dispatch - * @return self + * @param mixed $dispatchable Handler or middleware to dispatch + * @return static */ - public function register($method, $target, $middleware) + public function register($method, $target, $dispatchable) { $route = $this->getRouteForTarget($target); - $route->register($method, $middleware); + $route->register($method, $dispatchable); return $this; } diff --git a/src/Routing/RouterInterface.php b/src/Routing/RouterInterface.php index e94e158..7f7d330 100644 --- a/src/Routing/RouterInterface.php +++ b/src/Routing/RouterInterface.php @@ -25,34 +25,41 @@ interface RouterInterface extends MiddlewareInterface 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: - * - A single verb ("GET") + * - A single verb ("GET"), * - A comma-separated list of verbs ("GET,PUT,DELETE") - * - "*" to indicate any method - * @see MethodMapInterface::register + * - "*" to indicate any method. * * $target may be: * - An exact path (e.g., "/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]+)~") * - * $middleware may be: - * - An instance implementing MiddlewareInterface + * $dispatchable may be: + * - 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 - * implementing MiddlewareInterface - * - A callable that returns an instance implementing MiddleInterface - * - A callable matching the signature of MiddlewareInterface::dispatch + * implementing one of the interfaces listed above. + * - A callable that returns an instance implementing one of the + * 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 * * @param string $target Request target or pattern to match * @param string $method HTTP method(s) to match - * @param mixed $middleware Middleware to dispatch + * @param mixed $dispatchable Middleware to dispatch * @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 diff --git a/test/tests/unit/Routing/Route/PrefixRouteTest.php b/test/tests/unit/Routing/Route/PrefixRouteTest.php index edcd004..05c6359 100644 --- a/test/tests/unit/Routing/Route/PrefixRouteTest.php +++ b/test/tests/unit/Routing/Route/PrefixRouteTest.php @@ -2,6 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; +use WellRESTed\Routing\MethodMap; use WellRESTed\Routing\Route\PrefixRoute; use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Test\TestCase; @@ -10,43 +11,43 @@ class PrefixRouteTest extends TestCase { public function testTrimsAsteriskFromEndOfTarget() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new PrefixRoute("/cats/*", $methodMap->reveal()); - $this->assertEquals("/cats/", $route->getTarget()); + $methodMap = $this->prophesize(MethodMap::class); + $route = new PrefixRoute('/cats/*', $methodMap->reveal()); + $this->assertEquals('/cats/', $route->getTarget()); } public function testReturnsPrefixType() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new PrefixRoute("/*", $methodMap->reveal()); + $methodMap = $this->prophesize(MethodMap::class); + $route = new PrefixRoute('/*', $methodMap->reveal()); $this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType()); } public function testReturnsEmptyArrayForPathVariables() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new PrefixRoute("/*", $methodMap->reveal()); + $methodMap = $this->prophesize(MethodMap::class); + $route = new PrefixRoute('/*', $methodMap->reveal()); $this->assertSame([], $route->getPathVariables()); } public function testMatchesExactRequestTarget() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new PrefixRoute("/*", $methodMap->reveal()); - $this->assertTrue($route->matchesRequestTarget("/")); + $methodMap = $this->prophesize(MethodMap::class); + $route = new PrefixRoute('/*', $methodMap->reveal()); + $this->assertTrue($route->matchesRequestTarget('/')); } public function testMatchesRequestTargetWithSamePrefix() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new PrefixRoute("/*", $methodMap->reveal()); - $this->assertTrue($route->matchesRequestTarget("/cats/")); + $methodMap = $this->prophesize(MethodMap::class); + $route = new PrefixRoute('/*', $methodMap->reveal()); + $this->assertTrue($route->matchesRequestTarget('/cats/')); } public function testDoesNotMatchNonmatchingRequestTarget() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new PrefixRoute("/animals/cats/", $methodMap->reveal()); - $this->assertFalse($route->matchesRequestTarget("/animals/dogs/")); + $methodMap = $this->prophesize(MethodMap::class); + $route = new PrefixRoute('/animals/cats/', $methodMap->reveal()); + $this->assertFalse($route->matchesRequestTarget('/animals/dogs/')); } } diff --git a/test/tests/unit/Routing/Route/RegexRouteTest.php b/test/tests/unit/Routing/Route/RegexRouteTest.php index 3b1280f..a3a72ae 100644 --- a/test/tests/unit/Routing/Route/RegexRouteTest.php +++ b/test/tests/unit/Routing/Route/RegexRouteTest.php @@ -4,6 +4,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; use PHPUnit\Framework\Error\Notice; use PHPUnit\Framework\Error\Warning; +use WellRESTed\Routing\MethodMap; use WellRESTed\Routing\Route\RegexRoute; use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Test\TestCase; @@ -14,12 +15,12 @@ class RegexRouteTest extends TestCase public function setUp() { - $this->methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); + $this->methodMap = $this->prophesize(MethodMap::class); } public function testReturnsPatternType() { - $route = new RegexRoute("/", $this->methodMap->reveal()); + $route = new RegexRoute('/', $this->methodMap->reveal()); $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); } @@ -48,16 +49,16 @@ class RegexRouteTest extends TestCase public function matchingRouteProvider() { return [ - ["~/cat/[0-9]+~", "/cat/2", [0 => "/cat/2"]], - ["#/dog/.*#", "/dog/his-name-is-bear", [0 => "/dog/his-name-is-bear"]], - ["~/cat/([0-9]+)~", "/cat/2", [ - 0 => "/cat/2", - 1 => "2" + ['~/cat/[0-9]+~', '/cat/2', [0 => '/cat/2']], + ['#/dog/.*#', '/dog/his-name-is-bear', [0 => '/dog/his-name-is-bear']], + ['~/cat/([0-9]+)~', '/cat/2', [ + 0 => '/cat/2', + 1 => '2' ]], - ["~/dog/(?[0-9+])~", "/dog/2", [ - 0 => "/dog/2", - 1 => "2", - "id" => "2" + ['~/dog/(?[0-9+])~', '/dog/2', [ + 0 => '/dog/2', + 1 => '2', + 'id' => '2' ]] ]; } @@ -72,9 +73,9 @@ class RegexRouteTest extends TestCase public function mismatchingRouteProvider() { return [ - ["~/cat/[0-9]+~", "/cat/molly"], - ["~/cat/[0-9]+~", "/dog/bear"], - ["#/dog/.*#", "/dog"] + ['~/cat/[0-9]+~', '/cat/molly'], + ['~/cat/[0-9]+~', '/dog/bear'], + ['#/dog/.*#', '/dog'] ]; } @@ -89,7 +90,7 @@ class RegexRouteTest extends TestCase Notice::$enabled = false; $level = error_reporting(); error_reporting($level & ~E_WARNING); - $route->matchesRequestTarget("/"); + $route->matchesRequestTarget('/'); error_reporting($level); Warning::$enabled = true; Notice::$enabled = true; @@ -98,8 +99,8 @@ class RegexRouteTest extends TestCase public function invalidRouteProvider() { return [ - ["~/unterminated"], - ["/nope"] + ['~/unterminated'], + ['/nope'] ]; } } diff --git a/test/tests/unit/Routing/Route/StaticRouteTest.php b/test/tests/unit/Routing/Route/StaticRouteTest.php index b0e39dc..66032b2 100644 --- a/test/tests/unit/Routing/Route/StaticRouteTest.php +++ b/test/tests/unit/Routing/Route/StaticRouteTest.php @@ -2,6 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; +use WellRESTed\Routing\MethodMap; use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\StaticRoute; use WellRESTed\Test\TestCase; @@ -10,29 +11,29 @@ class StaticRouteTest extends TestCase { public function testReturnsStaticType() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new StaticRoute("/", $methodMap->reveal()); + $methodMap = $this->prophesize(MethodMap::class); + $route = new StaticRoute('/', $methodMap->reveal()); $this->assertSame(RouteInterface::TYPE_STATIC, $route->getType()); } public function testMatchesExactRequestTarget() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new StaticRoute("/", $methodMap->reveal()); - $this->assertTrue($route->matchesRequestTarget("/")); + $methodMap = $this->prophesize(MethodMap::class); + $route = new StaticRoute('/', $methodMap->reveal()); + $this->assertTrue($route->matchesRequestTarget('/')); } public function testReturnsEmptyArrayForPathVariables() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new StaticRoute("/", $methodMap->reveal()); + $methodMap = $this->prophesize(MethodMap::class); + $route = new StaticRoute('/', $methodMap->reveal()); $this->assertSame([], $route->getPathVariables()); } public function testDoesNotMatchNonmatchingRequestTarget() { - $methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); - $route = new StaticRoute("/", $methodMap->reveal()); - $this->assertFalse($route->matchesRequestTarget("/cats/")); + $methodMap = $this->prophesize(MethodMap::class); + $route = new StaticRoute('/', $methodMap->reveal()); + $this->assertFalse($route->matchesRequestTarget('/cats/')); } } diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index 5f9745e..7dc1492 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -2,6 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; +use WellRESTed\Routing\MethodMap; use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\TemplateRoute; use WellRESTed\Test\TestCase; @@ -12,22 +13,22 @@ class TemplateRouteTest extends TestCase public function setUp() { - $this->methodMap = $this->prophesize('WellRESTed\Routing\MethodMapInterface'); + $this->methodMap = $this->prophesize(MethodMap::class); } private function getExpectedValues($keys) { $expectedValues = [ - "var" => "value", - "hello" => "Hello World!", - "x" => "1024", - "y" => "768", - "path" => "/foo/bar", - "who" => "fred", - "half" => "50%", - "empty" => "", - "count" => ["one", "two", "three"], - "list" => ["red", "green", "blue"] + 'var' => 'value', + 'hello' => 'Hello World!', + 'x' => '1024', + 'y' => '768', + 'path' => '/foo/bar', + 'who' => 'fred', + 'half' => '50%', + 'empty' => '', + 'count' => ['one', 'two', 'three'], + 'list' => ['red', 'green', 'blue'] ]; return array_intersect_key($expectedValues, array_flip($keys)); } @@ -43,7 +44,7 @@ class TemplateRouteTest extends TestCase public function testReturnsPatternType() { - $route = new TemplateRoute("/", $this->methodMap->reveal()); + $route = new TemplateRoute('/', $this->methodMap->reveal()); $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); } @@ -60,10 +61,10 @@ class TemplateRouteTest extends TestCase public function nonMatchingTargetProvider() { return [ - ["/foo/{var}", "/bar/12", "Mismatch before 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"], - ["{/var}", "/bar/12", "Path contains more segments than template"], + ['/foo/{var}', '/bar/12', 'Mismatch before 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'], + ['{/var}', '/bar/12', 'Path contains more segments than template'], ]; } @@ -88,11 +89,11 @@ class TemplateRouteTest extends TestCase public function simpleStringProvider() { return [ - ["/foo", "/foo", []], - ["/{var}", "/value", ["var"]], - ["/{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"]], + ['/foo', '/foo', []], + ['/{var}', '/value', ['var']], + ['/{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']], ]; } @@ -117,9 +118,9 @@ class TemplateRouteTest extends TestCase public function reservedStringProvider() { return [ - ["/{+var}", "/value", ["var"]], - ["/{+hello}", "/Hello%20World!", ["hello"]], - ["{+path}/here", "/foo/bar/here", ["path"]], + ['/{+var}', '/value', ['var']], + ['/{+hello}', '/Hello%20World!', ['hello']], + ['{+path}/here', '/foo/bar/here', ['path']], ]; } @@ -144,9 +145,9 @@ class TemplateRouteTest extends TestCase public function labelWithDotPrefixProvider() { return [ - ["/{.who}", "/.fred", ["who"]], - ["/{.half,who}", "/.50%25.fred", ["half", "who"]], - ["/X{.empty}", "/X.", ["empty"]] + ['/{.who}', '/.fred', ['who']], + ['/{.half,who}', '/.50%25.fred', ['half', 'who']], + ['/X{.empty}', '/X.', ['empty']] ]; } @@ -171,9 +172,9 @@ class TemplateRouteTest extends TestCase public function pathSegmentProvider() { return [ - ["{/who}", "/fred", ["who"]], - ["{/half,who}", "/50%25/fred", ["half", "who"]], - ["{/var,empty}", "/value/", ["var", "empty"]] + ['{/who}', '/fred', ['who']], + ['{/half,who}', '/50%25/fred', ['half', 'who']], + ['{/var,empty}', '/value/', ['var', 'empty']] ]; } @@ -198,9 +199,9 @@ class TemplateRouteTest extends TestCase public function pathExplosionProvider() { return [ - ["/{count*}", "/one,two,three", ["count"]], - ["{/count*}", "/one/two/three", ["count"]], - ["X{.list*}", "X.red.green.blue", ["list"]] + ['/{count*}', '/one,two,three', ['count']], + ['{/count*}', '/one/two/three', ['count']], + ['X{.list*}', 'X.red.green.blue', ['list']] ]; } }