Add type hints to Router
This commit is contained in:
parent
967b6ac2a4
commit
ca204a07e7
|
|
@ -48,8 +48,10 @@ class Router
|
||||||
* Attribute name for matched path variables. A null value sets
|
* Attribute name for matched path variables. A null value sets
|
||||||
* attributes directly.
|
* attributes directly.
|
||||||
*/
|
*/
|
||||||
public function __construct($dispatcher = null, $pathVariablesAttributeName = null)
|
public function __construct(
|
||||||
{
|
?DispatcherInterface $dispatcher = null,
|
||||||
|
?string $pathVariablesAttributeName = null
|
||||||
|
) {
|
||||||
$this->dispatcher = $dispatcher ?: $this->getDefaultDispatcher();
|
$this->dispatcher = $dispatcher ?: $this->getDefaultDispatcher();
|
||||||
$this->pathVariablesAttributeName = $pathVariablesAttributeName;
|
$this->pathVariablesAttributeName = $pathVariablesAttributeName;
|
||||||
$this->factory = $this->getRouteFactory($this->dispatcher);
|
$this->factory = $this->getRouteFactory($this->dispatcher);
|
||||||
|
|
@ -63,8 +65,8 @@ class Router
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequestInterface $request,
|
ServerRequestInterface $request,
|
||||||
ResponseInterface $response,
|
ResponseInterface $response,
|
||||||
$next
|
callable $next
|
||||||
) {
|
): ResponseInterface {
|
||||||
// Use only the path for routing.
|
// Use only the path for routing.
|
||||||
$requestTarget = parse_url($request->getRequestTarget(), PHP_URL_PATH);
|
$requestTarget = parse_url($request->getRequestTarget(), PHP_URL_PATH);
|
||||||
|
|
||||||
|
|
@ -101,11 +103,11 @@ class Router
|
||||||
}
|
}
|
||||||
|
|
||||||
private function dispatch(
|
private function dispatch(
|
||||||
$route,
|
callable $route,
|
||||||
ServerRequestInterface $request,
|
ServerRequestInterface $request,
|
||||||
ResponseInterface $response,
|
ResponseInterface $response,
|
||||||
$next
|
callable $next
|
||||||
) {
|
): ResponseInterface {
|
||||||
if (!$this->stack) {
|
if (!$this->stack) {
|
||||||
return $route($request, $response, $next);
|
return $route($request, $response, $next);
|
||||||
}
|
}
|
||||||
|
|
@ -145,12 +147,12 @@ class Router
|
||||||
* - An array containing any of the items in this list.
|
* - 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 $method HTTP method(s) to match
|
* @param string $method HTTP method(s) to match
|
||||||
|
* @param string $target Request target or pattern to match
|
||||||
* @param mixed $dispatchable Handler or middleware to dispatch
|
* @param mixed $dispatchable Handler or middleware to dispatch
|
||||||
* @return static
|
* @return static
|
||||||
*/
|
*/
|
||||||
public function register($method, $target, $dispatchable)
|
public function register(string $method, string $target, $dispatchable): Router
|
||||||
{
|
{
|
||||||
$route = $this->getRouteForTarget($target);
|
$route = $this->getRouteForTarget($target);
|
||||||
$route->register($method, $dispatchable);
|
$route->register($method, $dispatchable);
|
||||||
|
|
@ -174,7 +176,7 @@ class Router
|
||||||
* @param mixed $middleware Middleware to dispatch in sequence
|
* @param mixed $middleware Middleware to dispatch in sequence
|
||||||
* @return static
|
* @return static
|
||||||
*/
|
*/
|
||||||
public function add($middleware)
|
public function add($middleware): Router
|
||||||
{
|
{
|
||||||
$this->stack[] = $middleware;
|
$this->stack[] = $middleware;
|
||||||
return $this;
|
return $this;
|
||||||
|
|
@ -186,38 +188,23 @@ class Router
|
||||||
*
|
*
|
||||||
* @return static
|
* @return static
|
||||||
*/
|
*/
|
||||||
public function continueOnNotFound()
|
public function continueOnNotFound(): Router
|
||||||
{
|
{
|
||||||
$this->continueOnNotFound = true;
|
$this->continueOnNotFound = true;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function getDefaultDispatcher(): DispatcherInterface
|
||||||
* Return an instance to dispatch middleware.
|
|
||||||
*
|
|
||||||
* @return DispatcherInterface
|
|
||||||
*/
|
|
||||||
protected function getDefaultDispatcher()
|
|
||||||
{
|
{
|
||||||
return new Dispatcher();
|
return new Dispatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactoryInterface
|
||||||
* @param DispatcherInterface $dispatcher
|
|
||||||
* @return RouteFactoryInterface
|
|
||||||
*/
|
|
||||||
protected function getRouteFactory($dispatcher)
|
|
||||||
{
|
{
|
||||||
return new RouteFactory($dispatcher);
|
return new RouteFactory($dispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function getRouteForTarget(string $target): RouteInterface
|
||||||
* Return the route for a given target.
|
|
||||||
*
|
|
||||||
* @param $target
|
|
||||||
* @return RouteInterface
|
|
||||||
*/
|
|
||||||
private function getRouteForTarget($target)
|
|
||||||
{
|
{
|
||||||
if (isset($this->routes[$target])) {
|
if (isset($this->routes[$target])) {
|
||||||
$route = $this->routes[$target];
|
$route = $this->routes[$target];
|
||||||
|
|
@ -228,7 +215,7 @@ class Router
|
||||||
return $route;
|
return $route;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function registerRouteForTarget($route, $target)
|
private function registerRouteForTarget(RouteInterface $route, string $target): void
|
||||||
{
|
{
|
||||||
// Store the route to the hash indexed by original target.
|
// Store the route to the hash indexed by original target.
|
||||||
$this->routes[$target] = $route;
|
$this->routes[$target] = $route;
|
||||||
|
|
@ -247,7 +234,7 @@ class Router
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getStaticRoute($requestTarget)
|
private function getStaticRoute(string $requestTarget): ?RouteInterface
|
||||||
{
|
{
|
||||||
if (isset($this->staticRoutes[$requestTarget])) {
|
if (isset($this->staticRoutes[$requestTarget])) {
|
||||||
return $this->staticRoutes[$requestTarget];
|
return $this->staticRoutes[$requestTarget];
|
||||||
|
|
@ -255,7 +242,7 @@ class Router
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPrefixRoute($requestTarget)
|
private function getPrefixRoute(string $requestTarget): ?RouteInterface
|
||||||
{
|
{
|
||||||
// Find all prefixes that match the start of this path.
|
// Find all prefixes that match the start of this path.
|
||||||
$prefixes = array_keys($this->prefixRoutes);
|
$prefixes = array_keys($this->prefixRoutes);
|
||||||
|
|
@ -273,7 +260,7 @@ class Router
|
||||||
// If there are multiple matches, sort them to find the one with the
|
// If there are multiple matches, sort them to find the one with the
|
||||||
// longest string length.
|
// longest string length.
|
||||||
if (count($matches) > 1) {
|
if (count($matches) > 1) {
|
||||||
$compareByLength = function ($a, $b) {
|
$compareByLength = function (string $a, string $b): int {
|
||||||
return strlen($b) - strlen($a);
|
return strlen($b) - strlen($a);
|
||||||
};
|
};
|
||||||
usort($matches, $compareByLength);
|
usort($matches, $compareByLength);
|
||||||
|
|
@ -283,7 +270,7 @@ class Router
|
||||||
return $this->prefixRoutes[$bestMatch];
|
return $this->prefixRoutes[$bestMatch];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function startsWith($haystack, $needle)
|
private function startsWith(string $haystack, string $needle): bool
|
||||||
{
|
{
|
||||||
$length = strlen($needle);
|
$length = strlen($needle);
|
||||||
return (substr($haystack, 0, $length) === $needle);
|
return (substr($haystack, 0, $length) === $needle);
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@ namespace WellRESTed\Test\Unit\Routing;
|
||||||
use Prophecy\Argument;
|
use Prophecy\Argument;
|
||||||
use Prophecy\PhpUnit\ProphecyTrait;
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
use WellRESTed\Dispatching\Dispatcher;
|
use WellRESTed\Dispatching\Dispatcher;
|
||||||
|
use WellRESTed\Dispatching\DispatcherInterface;
|
||||||
use WellRESTed\Message\Response;
|
use WellRESTed\Message\Response;
|
||||||
use WellRESTed\Message\ServerRequest;
|
use WellRESTed\Message\ServerRequest;
|
||||||
use WellRESTed\Routing\Route\RouteFactory;
|
use WellRESTed\Routing\Route\RouteFactory;
|
||||||
|
use WellRESTed\Routing\Route\RouteFactoryInterface;
|
||||||
use WellRESTed\Routing\Route\RouteInterface;
|
use WellRESTed\Routing\Route\RouteInterface;
|
||||||
use WellRESTed\Routing\Router;
|
use WellRESTed\Routing\Router;
|
||||||
use WellRESTed\Test\Doubles\NextMock;
|
use WellRESTed\Test\Doubles\NextMock;
|
||||||
|
|
@ -30,7 +32,7 @@ class RouterTest extends TestCase
|
||||||
|
|
||||||
$this->route = $this->prophesize(RouteInterface::class);
|
$this->route = $this->prophesize(RouteInterface::class);
|
||||||
$this->route->__invoke(Argument::cetera())->willReturn(new Response());
|
$this->route->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
$this->route->register(Argument::cetera())->willReturn();
|
$this->route->register(Argument::cetera());
|
||||||
$this->route->getType()->willReturn(RouteInterface::TYPE_STATIC);
|
$this->route->getType()->willReturn(RouteInterface::TYPE_STATIC);
|
||||||
$this->route->getTarget()->willReturn("/");
|
$this->route->getTarget()->willReturn("/");
|
||||||
$this->route->getPathVariables()->willReturn([]);
|
$this->route->getPathVariables()->willReturn([]);
|
||||||
|
|
@ -134,13 +136,13 @@ class RouterTest extends TestCase
|
||||||
public function testDispatchesStaticRouteBeforePrefixRoute()
|
public function testDispatchesStaticRouteBeforePrefixRoute()
|
||||||
{
|
{
|
||||||
$staticRoute = $this->prophesize(RouteInterface::class);
|
$staticRoute = $this->prophesize(RouteInterface::class);
|
||||||
$staticRoute->register(Argument::cetera())->willReturn();
|
$staticRoute->register(Argument::cetera());
|
||||||
$staticRoute->getTarget()->willReturn("/cats/");
|
$staticRoute->getTarget()->willReturn("/cats/");
|
||||||
$staticRoute->getType()->willReturn(RouteInterface::TYPE_STATIC);
|
$staticRoute->getType()->willReturn(RouteInterface::TYPE_STATIC);
|
||||||
$staticRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
$staticRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
||||||
$prefixRoute = $this->prophesize(RouteInterface::class);
|
$prefixRoute = $this->prophesize(RouteInterface::class);
|
||||||
$prefixRoute->register(Argument::cetera())->willReturn();
|
$prefixRoute->register(Argument::cetera());
|
||||||
$prefixRoute->getTarget()->willReturn("/cats/*");
|
$prefixRoute->getTarget()->willReturn("/cats/*");
|
||||||
$prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
$prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
||||||
$prefixRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
$prefixRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
@ -163,13 +165,13 @@ class RouterTest extends TestCase
|
||||||
// Note: The longest route is also good for 2 points in Settlers of Catan.
|
// Note: The longest route is also good for 2 points in Settlers of Catan.
|
||||||
|
|
||||||
$shortRoute = $this->prophesize(RouteInterface::class);
|
$shortRoute = $this->prophesize(RouteInterface::class);
|
||||||
$shortRoute->register(Argument::cetera())->willReturn();
|
$shortRoute->register(Argument::cetera());
|
||||||
$shortRoute->getTarget()->willReturn("/animals/*");
|
$shortRoute->getTarget()->willReturn("/animals/*");
|
||||||
$shortRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
$shortRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
||||||
$shortRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
$shortRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
||||||
$longRoute = $this->prophesize(RouteInterface::class);
|
$longRoute = $this->prophesize(RouteInterface::class);
|
||||||
$longRoute->register(Argument::cetera())->willReturn();
|
$longRoute->register(Argument::cetera());
|
||||||
$longRoute->getTarget()->willReturn("/animals/cats/*");
|
$longRoute->getTarget()->willReturn("/animals/cats/*");
|
||||||
$longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
$longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
||||||
$longRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
$longRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
@ -191,13 +193,13 @@ class RouterTest extends TestCase
|
||||||
public function testDispatchesPrefixRouteBeforePatternRoute()
|
public function testDispatchesPrefixRouteBeforePatternRoute()
|
||||||
{
|
{
|
||||||
$prefixRoute = $this->prophesize(RouteInterface::class);
|
$prefixRoute = $this->prophesize(RouteInterface::class);
|
||||||
$prefixRoute->register(Argument::cetera())->willReturn();
|
$prefixRoute->register(Argument::cetera());
|
||||||
$prefixRoute->getTarget()->willReturn("/cats/*");
|
$prefixRoute->getTarget()->willReturn("/cats/*");
|
||||||
$prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
$prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
|
||||||
$prefixRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
$prefixRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
||||||
$patternRoute = $this->prophesize(RouteInterface::class);
|
$patternRoute = $this->prophesize(RouteInterface::class);
|
||||||
$patternRoute->register(Argument::cetera())->willReturn();
|
$patternRoute->register(Argument::cetera());
|
||||||
$patternRoute->getTarget()->willReturn("/cats/{id}");
|
$patternRoute->getTarget()->willReturn("/cats/{id}");
|
||||||
$patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
$patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
||||||
$patternRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
$patternRoute->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
@ -218,7 +220,7 @@ class RouterTest extends TestCase
|
||||||
public function testDispatchesFirstMatchingPatternRoute()
|
public function testDispatchesFirstMatchingPatternRoute()
|
||||||
{
|
{
|
||||||
$patternRoute1 = $this->prophesize(RouteInterface::class);
|
$patternRoute1 = $this->prophesize(RouteInterface::class);
|
||||||
$patternRoute1->register(Argument::cetera())->willReturn();
|
$patternRoute1->register(Argument::cetera());
|
||||||
$patternRoute1->getTarget()->willReturn("/cats/{id}");
|
$patternRoute1->getTarget()->willReturn("/cats/{id}");
|
||||||
$patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
$patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
||||||
$patternRoute1->getPathVariables()->willReturn([]);
|
$patternRoute1->getPathVariables()->willReturn([]);
|
||||||
|
|
@ -226,7 +228,7 @@ class RouterTest extends TestCase
|
||||||
$patternRoute1->__invoke(Argument::cetera())->willReturn(new Response());
|
$patternRoute1->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
||||||
$patternRoute2 = $this->prophesize(RouteInterface::class);
|
$patternRoute2 = $this->prophesize(RouteInterface::class);
|
||||||
$patternRoute2->register(Argument::cetera())->willReturn();
|
$patternRoute2->register(Argument::cetera());
|
||||||
$patternRoute2->getTarget()->willReturn("/cats/{name}");
|
$patternRoute2->getTarget()->willReturn("/cats/{name}");
|
||||||
$patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
$patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
||||||
$patternRoute2->getPathVariables()->willReturn([]);
|
$patternRoute2->getPathVariables()->willReturn([]);
|
||||||
|
|
@ -249,7 +251,7 @@ class RouterTest extends TestCase
|
||||||
public function testStopsTestingPatternsAfterFirstSuccessfulMatch()
|
public function testStopsTestingPatternsAfterFirstSuccessfulMatch()
|
||||||
{
|
{
|
||||||
$patternRoute1 = $this->prophesize(RouteInterface::class);
|
$patternRoute1 = $this->prophesize(RouteInterface::class);
|
||||||
$patternRoute1->register(Argument::cetera())->willReturn();
|
$patternRoute1->register(Argument::cetera());
|
||||||
$patternRoute1->getTarget()->willReturn("/cats/{id}");
|
$patternRoute1->getTarget()->willReturn("/cats/{id}");
|
||||||
$patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
$patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
||||||
$patternRoute1->getPathVariables()->willReturn([]);
|
$patternRoute1->getPathVariables()->willReturn([]);
|
||||||
|
|
@ -257,7 +259,7 @@ class RouterTest extends TestCase
|
||||||
$patternRoute1->__invoke(Argument::cetera())->willReturn(new Response());
|
$patternRoute1->__invoke(Argument::cetera())->willReturn(new Response());
|
||||||
|
|
||||||
$patternRoute2 = $this->prophesize(RouteInterface::class);
|
$patternRoute2 = $this->prophesize(RouteInterface::class);
|
||||||
$patternRoute2->register(Argument::cetera())->willReturn();
|
$patternRoute2->register(Argument::cetera());
|
||||||
$patternRoute2->getTarget()->willReturn("/cats/{name}");
|
$patternRoute2->getTarget()->willReturn("/cats/{name}");
|
||||||
$patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
$patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN);
|
||||||
$patternRoute2->getPathVariables()->willReturn([]);
|
$patternRoute2->getPathVariables()->willReturn([]);
|
||||||
|
|
@ -447,7 +449,7 @@ class RouterWithFactory extends Router
|
||||||
{
|
{
|
||||||
static $routeFactory;
|
static $routeFactory;
|
||||||
|
|
||||||
protected function getRouteFactory($dispatcher)
|
protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactoryInterface
|
||||||
{
|
{
|
||||||
return self::$routeFactory;
|
return self::$routeFactory;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue