Add type hints for Routes

This commit is contained in:
PJ Dietz 2020-08-09 13:58:24 -04:00
parent c339512f01
commit 967b6ac2a4
9 changed files with 57 additions and 57 deletions

View File

@ -8,7 +8,9 @@ use WellRESTed\Dispatching\DispatcherInterface;
class MethodMap class MethodMap
{ {
/** @var DispatcherInterface */
private $dispatcher; private $dispatcher;
/** @var array */
private $map; private $map;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -39,7 +41,7 @@ class MethodMap
* @param string $method * @param string $method
* @param mixed $dispatchable * @param mixed $dispatchable
*/ */
public function register($method, $dispatchable) public function register($method, $dispatchable): void
{ {
$methods = explode(",", $method); $methods = explode(",", $method);
$methods = array_map("trim", $methods); $methods = array_map("trim", $methods);
@ -90,13 +92,16 @@ class MethodMap
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
private function addAllowHeader(ResponseInterface $response) private function addAllowHeader(ResponseInterface $response): ResponseInterface
{ {
$methods = join(",", $this->getAllowedMethods()); $methods = join(",", $this->getAllowedMethods());
return $response->withHeader("Allow", $methods); return $response->withHeader("Allow", $methods);
} }
private function getAllowedMethods() /**
* @return string[]
*/
private function getAllowedMethods(): array
{ {
$methods = array_keys($this->map); $methods = array_keys($this->map);
// Add HEAD if GET is allowed and HEAD is not present. // Add HEAD if GET is allowed and HEAD is not present.
@ -111,16 +116,16 @@ class MethodMap
} }
/** /**
* @param $middleware * @param mixed $middleware
* @param ServerRequestInterface $request * @param ServerRequestInterface $request
* @param ResponseInterface $response * @param ResponseInterface $response
* @param $next * @param callable $next
* @return ResponseInterface * @return ResponseInterface
*/ */
private function dispatchMiddleware( private function dispatchMiddleware(
$middleware, $middleware,
ServerRequestInterface $request, ServerRequestInterface $request,
ResponseInterface &$response, ResponseInterface $response,
$next $next
) { ) {
return $this->dispatcher->dispatch($middleware, $request, $response, $next); return $this->dispatcher->dispatch($middleware, $request, $response, $next);

View File

@ -4,12 +4,12 @@ namespace WellRESTed\Routing\Route;
class PrefixRoute extends Route class PrefixRoute extends Route
{ {
public function __construct($target, $methodMap) public function __construct(string $target, MethodMap $methodMap)
{ {
parent::__construct(rtrim($target, "*"), $methodMap); parent::__construct(rtrim($target, "*"), $methodMap);
} }
public function getType() public function getType(): int
{ {
return RouteInterface::TYPE_PREFIX; return RouteInterface::TYPE_PREFIX;
} }
@ -20,7 +20,7 @@ class PrefixRoute extends Route
* @param string $requestTarget * @param string $requestTarget
* @return boolean * @return boolean
*/ */
public function matchesRequestTarget($requestTarget) public function matchesRequestTarget(string $requestTarget): bool
{ {
return strrpos($requestTarget, $this->target, -strlen($requestTarget)) !== false; return strrpos($requestTarget, $this->target, -strlen($requestTarget)) !== false;
} }
@ -28,7 +28,7 @@ class PrefixRoute extends Route
/** /**
* Always returns an empty array. * Always returns an empty array.
*/ */
public function getPathVariables() public function getPathVariables(): array
{ {
return []; return [];
} }

View File

@ -4,9 +4,10 @@ namespace WellRESTed\Routing\Route;
class RegexRoute extends Route class RegexRoute extends Route
{ {
private $captures; /** @var array */
private $captures = [];
public function getType() public function getType(): int
{ {
return RouteInterface::TYPE_PATTERN; return RouteInterface::TYPE_PATTERN;
} }
@ -17,7 +18,7 @@ class RegexRoute extends Route
* @param string $requestTarget * @param string $requestTarget
* @return boolean * @return boolean
*/ */
public function matchesRequestTarget($requestTarget) public function matchesRequestTarget(string $requestTarget): bool
{ {
$this->captures = []; $this->captures = [];
$matched = preg_match($this->getTarget(), $requestTarget, $captures); $matched = preg_match($this->getTarget(), $requestTarget, $captures);
@ -36,7 +37,7 @@ class RegexRoute extends Route
* @see \preg_match * @see \preg_match
* @return array * @return array
*/ */
public function getPathVariables() public function getPathVariables(): array
{ {
return $this->captures; return $this->captures;
} }

View File

@ -12,16 +12,13 @@ abstract class Route implements RouteInterface
/** @var MethodMap */ /** @var MethodMap */
protected $methodMap; protected $methodMap;
public function __construct($target, $methodMap) public function __construct(string $target, MethodMap $methodMap)
{ {
$this->target = $target; $this->target = $target;
$this->methodMap = $methodMap; $this->methodMap = $methodMap;
} }
/** public function getTarget(): string
* @return string
*/
public function getTarget()
{ {
return $this->target; return $this->target;
} }
@ -40,7 +37,7 @@ abstract class Route implements RouteInterface
* @param string $method * @param string $method
* @param mixed $dispatchable * @param mixed $dispatchable
*/ */
public function register($method, $dispatchable) public function register(string $method, $dispatchable): void
{ {
$this->methodMap->register($method, $dispatchable); $this->methodMap->register($method, $dispatchable);
} }

View File

@ -34,7 +34,7 @@ interface RouteInterface extends MiddlewareInterface
* *
* @return int One of the RouteInterface::TYPE_ constants. * @return int One of the RouteInterface::TYPE_ constants.
*/ */
public function getType(); public function getType(): int;
/** /**
* Return an array of variables extracted from the path most recently * Return an array of variables extracted from the path most recently
@ -45,7 +45,7 @@ interface RouteInterface extends MiddlewareInterface
* *
* @return array * @return array
*/ */
public function getPathVariables(); public function getPathVariables(): array;
/** /**
* 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.
@ -55,7 +55,7 @@ interface RouteInterface extends MiddlewareInterface
* @throw \RuntimeException Error occurred testing the target such as an * @throw \RuntimeException Error occurred testing the target such as an
* invalid regular expression * invalid regular expression
*/ */
public function matchesRequestTarget($requestTarget); public function matchesRequestTarget(string $requestTarget): bool;
/** /**
* Register a dispatchable (handler or middleware) with a method. * Register a dispatchable (handler or middleware) with a method.
@ -71,5 +71,5 @@ interface RouteInterface extends MiddlewareInterface
* @param string $method * @param string $method
* @param mixed $dispatchable * @param mixed $dispatchable
*/ */
public function register($method, $dispatchable); public function register(string $method, $dispatchable): void;
} }

View File

@ -4,7 +4,7 @@ namespace WellRESTed\Routing\Route;
class StaticRoute extends Route class StaticRoute extends Route
{ {
public function getType() public function getType(): int
{ {
return RouteInterface::TYPE_STATIC; return RouteInterface::TYPE_STATIC;
} }
@ -15,7 +15,7 @@ class StaticRoute extends Route
* @param string $requestTarget * @param string $requestTarget
* @return boolean * @return boolean
*/ */
public function matchesRequestTarget($requestTarget) public function matchesRequestTarget(string $requestTarget): bool
{ {
return $requestTarget === $this->getTarget(); return $requestTarget === $this->getTarget();
} }
@ -23,7 +23,7 @@ class StaticRoute extends Route
/** /**
* Always returns an empty array. * Always returns an empty array.
*/ */
public function getPathVariables() public function getPathVariables(): array
{ {
return []; return [];
} }

View File

@ -4,25 +4,27 @@ namespace WellRESTed\Routing\Route;
class TemplateRoute extends Route class TemplateRoute extends Route
{ {
private $pathVariables; /** @var array */
private $explosions; private $pathVariables = [];
/** @var array */
private $explosions = [];
/** Regular expression matching a URI template variable (e.g., {id}) */
public const URI_TEMPLATE_EXPRESSION_RE = '/{([+.\/]?[a-zA-Z0-9_,]+\*?)}/';
/** /**
* Regular expression matching 1 or more unreserved characters. * Regular expression matching 1 or more unreserved characters.
* ALPHA / DIGIT / "-" / "." / "_" / "~" * ALPHA / DIGIT / "-" / "." / "_" / "~"
*/ */
const RE_UNRESERVED = '[0-9a-zA-Z\-._\~%]*'; private const RE_UNRESERVED = '[0-9a-zA-Z\-._\~%]*';
/** Regular expression matching a URI template variable (e.g., {id}) */
const URI_TEMPLATE_EXPRESSION_RE = '/{([+.\/]?[a-zA-Z0-9_,]+\*?)}/';
public function getType() public function getType(): int
{ {
return RouteInterface::TYPE_PATTERN; return RouteInterface::TYPE_PATTERN;
} }
public function getPathVariables() public function getPathVariables(): array
{ {
return $this->pathVariables ?: []; return $this->pathVariables;
} }
/** /**
@ -31,7 +33,7 @@ class TemplateRoute extends Route
* @param string $requestTarget * @param string $requestTarget
* @return bool * @return bool
*/ */
public function matchesRequestTarget($requestTarget) public function matchesRequestTarget(string $requestTarget): bool
{ {
$this->pathVariables = []; $this->pathVariables = [];
$this->explosions = []; $this->explosions = [];
@ -49,11 +51,7 @@ class TemplateRoute extends Route
return false; return false;
} }
/** private function matchesStartOfRequestTarget(string $requestTarget): bool
* @param $requestTarget
* @return bool
*/
private function matchesStartOfRequestTarget($requestTarget)
{ {
$firstVarPos = strpos($this->target, "{"); $firstVarPos = strpos($this->target, "{");
if ($firstVarPos === false) { if ($firstVarPos === false) {
@ -62,7 +60,7 @@ class TemplateRoute extends Route
return (substr($requestTarget, 0, $firstVarPos) === substr($this->target, 0, $firstVarPos)); return (substr($requestTarget, 0, $firstVarPos) === substr($this->target, 0, $firstVarPos));
} }
private function processMatches($matches) private function processMatches(array $matches): array
{ {
$variables = []; $variables = [];
@ -87,7 +85,7 @@ class TemplateRoute extends Route
return $variables; return $variables;
} }
private function getMatchingPattern() private function getMatchingPattern(): string
{ {
// Convert the template into the pattern // Convert the template into the pattern
$pattern = $this->target; $pattern = $this->target;
@ -119,7 +117,7 @@ class TemplateRoute extends Route
return $pattern; return $pattern;
} }
private function uriVariableReplacementCallback($matches) private function uriVariableReplacementCallback(array $matches): string
{ {
$name = $matches[1]; $name = $matches[1];
$pattern = self::RE_UNRESERVED; $pattern = self::RE_UNRESERVED;

View File

@ -23,8 +23,7 @@ class RouteTest extends TestCase
public function setUp(): void public function setUp(): void
{ {
$this->methodMap = $this->prophesize(MethodMap::class); $this->methodMap = $this->prophesize(MethodMap::class);
$this->methodMap->register(Argument::cetera()) $this->methodMap->register(Argument::cetera());
->willReturn();
$this->methodMap->__invoke(Argument::cetera()) $this->methodMap->__invoke(Argument::cetera())
->willReturn(new Response()); ->willReturn(new Response());

View File

@ -57,7 +57,7 @@ class TemplateRouteTest extends TestCase
/** @dataProvider nonMatchingTargetProvider */ /** @dataProvider nonMatchingTargetProvider */
public function testFailsToMatchNonMatchingTarget($template, $target) public function testFailsToMatchNonMatchingTarget($template, $target)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$this->assertFalse($route->matchesRequestTarget($target)); $this->assertFalse($route->matchesRequestTarget($target));
} }
@ -77,14 +77,14 @@ class TemplateRouteTest extends TestCase
/** @dataProvider simpleStringProvider */ /** @dataProvider simpleStringProvider */
public function testMatchesSimpleStrings($template, $target) public function testMatchesSimpleStrings($template, $target)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget($target)); $this->assertTrue($route->matchesRequestTarget($target));
} }
/** @dataProvider simpleStringProvider */ /** @dataProvider simpleStringProvider */
public function testCapturesFromSimpleStrings($template, $target, $variables) public function testCapturesFromSimpleStrings($template, $target, $variables)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$route->matchesRequestTarget($target); $route->matchesRequestTarget($target);
$this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables());
} }
@ -106,14 +106,14 @@ class TemplateRouteTest extends TestCase
/** @dataProvider reservedStringProvider */ /** @dataProvider reservedStringProvider */
public function testMatchesReservedStrings($template, $target) public function testMatchesReservedStrings($template, $target)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget($target)); $this->assertTrue($route->matchesRequestTarget($target));
} }
/** @dataProvider reservedStringProvider */ /** @dataProvider reservedStringProvider */
public function testCapturesFromReservedStrings($template, $target, $variables) public function testCapturesFromReservedStrings($template, $target, $variables)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$route->matchesRequestTarget($target); $route->matchesRequestTarget($target);
$this->assertSame($this->getExpectedValues($variables), $route->getPathVariables()); $this->assertSame($this->getExpectedValues($variables), $route->getPathVariables());
} }
@ -133,14 +133,14 @@ class TemplateRouteTest extends TestCase
/** @dataProvider labelWithDotPrefixProvider */ /** @dataProvider labelWithDotPrefixProvider */
public function testMatchesLabelWithDotPrefix($template, $target) public function testMatchesLabelWithDotPrefix($template, $target)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget($target)); $this->assertTrue($route->matchesRequestTarget($target));
} }
/** @dataProvider labelWithDotPrefixProvider */ /** @dataProvider labelWithDotPrefixProvider */
public function testCapturesFromLabelWithDotPrefix($template, $target, $variables) public function testCapturesFromLabelWithDotPrefix($template, $target, $variables)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$route->matchesRequestTarget($target); $route->matchesRequestTarget($target);
$this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables());
} }
@ -160,14 +160,14 @@ class TemplateRouteTest extends TestCase
/** @dataProvider pathSegmentProvider */ /** @dataProvider pathSegmentProvider */
public function testMatchesPathSegments($template, $target) public function testMatchesPathSegments($template, $target)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget($target)); $this->assertTrue($route->matchesRequestTarget($target));
} }
/** @dataProvider pathSegmentProvider */ /** @dataProvider pathSegmentProvider */
public function testCapturesFromPathSegments($template, $target, $variables) public function testCapturesFromPathSegments($template, $target, $variables)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$route->matchesRequestTarget($target); $route->matchesRequestTarget($target);
$this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables());
} }
@ -187,14 +187,14 @@ class TemplateRouteTest extends TestCase
/** @dataProvider pathExplosionProvider */ /** @dataProvider pathExplosionProvider */
public function testMatchesExplosion($template, $target) public function testMatchesExplosion($template, $target)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$this->assertTrue($route->matchesRequestTarget($target)); $this->assertTrue($route->matchesRequestTarget($target));
} }
/** @dataProvider pathExplosionProvider */ /** @dataProvider pathExplosionProvider */
public function testCapturesFromExplosion($template, $target, $variables) public function testCapturesFromExplosion($template, $target, $variables)
{ {
$route = new TemplateRoute($template, $this->methodMap); $route = new TemplateRoute($template, $this->methodMap->reveal());
$route->matchesRequestTarget($target); $route->matchesRequestTarget($target);
$this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables());
} }