Browse Source

Use clean nullable for Route and RouteCollection. Add typehinting.

mscherer 7 years ago
parent
commit
27301c8f97

+ 7 - 8
src/Routing/Route/DashedRoute.php

@@ -23,7 +23,6 @@ use Cake\Utility\Inflector;
  */
 class DashedRoute extends Route
 {
-
     /**
      * Flag for tracking whether or not the defaults have been inflected.
      *
@@ -40,7 +39,7 @@ class DashedRoute extends Route
      * @param string $plugin Plugin name
      * @return string
      */
-    protected function _camelizePlugin($plugin)
+    protected function _camelizePlugin(string $plugin): string
     {
         $plugin = str_replace('-', '_', $plugin);
         if (strpos($plugin, '/') === false) {
@@ -58,13 +57,13 @@ class DashedRoute extends Route
      *
      * @param string $url The URL to parse
      * @param string $method The HTTP method.
-     * @return array|false An array of request parameters, or false on failure.
+     * @return array|null An array of request parameters, or null on failure.
      */
-    public function parse($url, $method = '')
+    public function parse(string $url, string $method = ''): ?array
     {
         $params = parent::parse($url, $method);
         if (!$params) {
-            return false;
+            return null;
         }
         if (!empty($params['controller'])) {
             $params['controller'] = Inflector::camelize($params['controller'], '-');
@@ -91,9 +90,9 @@ class DashedRoute extends Route
      * @param array $context An array of the current request context.
      *   Contains information such as the current host, scheme, port, and base
      *   directory.
-     * @return bool|string Either false or a string URL.
+     * @return string|null Either a string URL or null.
      */
-    public function match(array $url, array $context = [])
+    public function match(array $url, array $context = []): ?string
     {
         $url = $this->_dasherize($url);
         if (!$this->_inflectedDefaults) {
@@ -110,7 +109,7 @@ class DashedRoute extends Route
      * @param array $url An array of URL keys.
      * @return array
      */
-    protected function _dasherize($url)
+    protected function _dasherize(array $url): array
     {
         foreach (['controller', 'plugin', 'action'] as $element) {
             if (!empty($url[$element])) {

+ 3 - 3
src/Routing/Route/EntityRoute.php

@@ -37,9 +37,9 @@ class EntityRoute extends Route
      * @param array $context An array of the current request context.
      *   Contains information such as the current host, scheme, port, and base
      *   directory.
-     * @return bool|string Either false or a string URL.
+     * @return string|null Either a string URL or null.
      */
-    public function match(array $url, array $context = [])
+    public function match(array $url, array $context = []): ?string
     {
         if (isset($url['_entity'])) {
             $entity = $url['_entity'];
@@ -64,7 +64,7 @@ class EntityRoute extends Route
      * @param \ArrayAccess|array $entity Entity value from the URL options
      * @return void
      */
-    protected function _checkEntity($entity)
+    protected function _checkEntity($entity): void
     {
         if (!$entity instanceof ArrayAccess && !is_array($entity)) {
             throw new RuntimeException(sprintf(

+ 5 - 6
src/Routing/Route/InflectedRoute.php

@@ -22,7 +22,6 @@ use Cake\Utility\Inflector;
  */
 class InflectedRoute extends Route
 {
-
     /**
      * Flag for tracking whether or not the defaults have been inflected.
      *
@@ -39,13 +38,13 @@ class InflectedRoute extends Route
      *
      * @param string $url The URL to parse
      * @param string $method The HTTP method being matched.
-     * @return array|false An array of request parameters, or false on failure.
+     * @return array|null An array of request parameters, or null on failure.
      */
-    public function parse($url, $method = '')
+    public function parse(string $url, string $method = ''): ?array
     {
         $params = parent::parse($url, $method);
         if (!$params) {
-            return false;
+            return null;
         }
         if (!empty($params['controller'])) {
             $params['controller'] = Inflector::camelize($params['controller']);
@@ -70,9 +69,9 @@ class InflectedRoute extends Route
      * @param array $context An array of the current request context.
      *   Contains information such as the current host, scheme, port, and base
      *   directory.
-     * @return string|false Either a string URL for the parameters if they match or false.
+     * @return string|null Either a string URL for the parameters if they match or null.
      */
-    public function match(array $url, array $context = [])
+    public function match(array $url, array $context = []): ?string
     {
         $url = $this->_underscore($url);
         if (!$this->_inflectedDefaults) {

+ 5 - 6
src/Routing/Route/PluginShortRoute.php

@@ -20,7 +20,6 @@ namespace Cake\Routing\Route;
  */
 class PluginShortRoute extends InflectedRoute
 {
-
     /**
      * Parses a string URL into an array. If a plugin key is found, it will be copied to the
      * controller parameter.
@@ -29,11 +28,11 @@ class PluginShortRoute extends InflectedRoute
      * @param string $method The HTTP method
      * @return array|false An array of request parameters, or boolean false on failure.
      */
-    public function parse($url, $method = '')
+    public function parse(string $url, string $method = ''): ?array
     {
         $params = parent::parse($url, $method);
         if (!$params) {
-            return false;
+            return null;
         }
         $params['controller'] = $params['plugin'];
 
@@ -48,12 +47,12 @@ class PluginShortRoute extends InflectedRoute
      * @param array $context An array of the current request context.
      *   Contains information such as the current host, scheme, port, and base
      *   directory.
-     * @return string|false Either a string URL for the parameters if they match or false.
+     * @return string|null Either a string URL for the parameters if they match or null.
      */
-    public function match(array $url, array $context = [])
+    public function match(array $url, array $context = []): ?string
     {
         if (isset($url['controller'], $url['plugin']) && $url['plugin'] !== $url['controller']) {
-            return false;
+            return null;
         }
         $this->defaults['controller'] = $url['controller'];
         $result = parent::match($url, $context);

+ 12 - 12
src/Routing/Route/RedirectRoute.php

@@ -38,16 +38,16 @@ class RedirectRoute extends Route
      * Constructor
      *
      * @param string $template Template string with parameter placeholders
-     * @param array|string $defaults Defaults for the route. Either a string or a CakePHP array URL.
+     * @param array $defaults Defaults for the route. Either a redirect=>value array or a CakePHP array URL.
      * @param array $options Array of additional options for the Route
      */
-    public function __construct($template, $defaults = [], array $options = [])
+    public function __construct(string $template, array $defaults = [], array $options = [])
     {
         parent::__construct($template, $defaults, $options);
-        if (is_array($defaults) && isset($defaults['redirect'])) {
-            $defaults = $defaults['redirect'];
+        if (isset($defaults['redirect'])) {
+            $defaults = (array)$defaults['redirect'];
         }
-        $this->redirect = (array)$defaults;
+        $this->redirect = $defaults;
     }
 
     /**
@@ -56,18 +56,18 @@ class RedirectRoute extends Route
      *
      * @param string $url The URL to parse.
      * @param string $method The HTTP method being used.
-     * @return bool|null False on failure. An exception is raised on a successful match.
+     * @return array|null Null on failure. An exception is raised on a successful match. Array return type is unused.
      * @throws \Cake\Routing\Exception\RedirectException An exception is raised on successful match.
      *   This is used to halt route matching and signal to the middleware that a redirect should happen.
      */
-    public function parse($url, $method = '')
+    public function parse(string $url, string $method = ''): ?array
     {
         $params = parent::parse($url, $method);
         if (!$params) {
-            return false;
+            return null;
         }
         $redirect = $this->redirect;
-        if (count($this->redirect) === 1 && !isset($this->redirect['controller'])) {
+        if ($this->redirect && count($this->redirect) === 1 && !isset($this->redirect['controller'])) {
             $redirect = $this->redirect[0];
         }
         if (isset($this->options['persist']) && is_array($redirect)) {
@@ -93,10 +93,10 @@ class RedirectRoute extends Route
      *
      * @param array $url Array of parameters to convert to a string.
      * @param array $context Array of request context parameters.
-     * @return bool Always false.
+     * @return string|null Always null, string return result unused.
      */
-    public function match(array $url, array $context = [])
+    public function match(array $url, array $context = []): ?string
     {
-        return false;
+        return null;
     }
 }

+ 35 - 36
src/Routing/Route/Route.php

@@ -26,7 +26,6 @@ use Psr\Http\Message\ServerRequestInterface;
  */
 class Route
 {
-
     /**
      * An array of named segments in a Route.
      * `/:controller/:action/:id` has 3 key elements
@@ -52,7 +51,7 @@ class Route
     /**
      * The routes template string.
      *
-     * @var string|null
+     * @var string
      */
     public $template;
 
@@ -119,13 +118,13 @@ class Route
      *   e.g. `*.example.com` matches all subdomains on `example.com`.
      *
      * @param string $template Template string with parameter placeholders
-     * @param array|string $defaults Defaults for the route.
+     * @param array $defaults Defaults for the route.
      * @param array $options Array of additional options for the Route
      */
-    public function __construct($template, $defaults = [], array $options = [])
+    public function __construct(string $template, array $defaults = [], array $options = [])
     {
         $this->template = $template;
-        $this->defaults = (array)$defaults;
+        $this->defaults = $defaults;
         $this->options = $options + ['_ext' => [], '_middleware' => []];
         $this->setExtensions((array)$this->options['_ext']);
         $this->setMiddleware((array)$this->options['_middleware']);
@@ -138,7 +137,7 @@ class Route
      * @param array $extensions The extensions to set.
      * @return $this
      */
-    public function setExtensions(array $extensions)
+    public function setExtensions(array $extensions): self
     {
         $this->_extensions = [];
         foreach ($extensions as $ext) {
@@ -153,7 +152,7 @@ class Route
      *
      * @return array
      */
-    public function getExtensions()
+    public function getExtensions(): array
     {
         return $this->_extensions;
     }
@@ -165,7 +164,7 @@ class Route
      * @return $this
      * @throws \InvalidArgumentException
      */
-    public function setMethods(array $methods)
+    public function setMethods(array $methods): self
     {
         $methods = array_map('strtoupper', $methods);
         $diff = array_diff($methods, static::VALID_METHODS);
@@ -188,7 +187,7 @@ class Route
      * @param array $patterns The patterns to apply to routing elements
      * @return $this
      */
-    public function setPatterns(array $patterns)
+    public function setPatterns(array $patterns): self
     {
         $patternValues = implode("", $patterns);
         if (mb_strlen($patternValues) < strlen($patternValues)) {
@@ -205,7 +204,7 @@ class Route
      * @param string $host The host name this route is bound to
      * @return $this
      */
-    public function setHost($host)
+    public function setHost(string $host): self
     {
         $this->options['_host'] = $host;
 
@@ -218,7 +217,7 @@ class Route
      * @param array $names The names of the parameters that should be passed.
      * @return $this
      */
-    public function setPass(array $names)
+    public function setPass(array $names): self
     {
         $this->options['pass'] = $names;
 
@@ -240,7 +239,7 @@ class Route
      * @param array $names The names of the parameters that should be passed.
      * @return $this
      */
-    public function setPersist(array $names)
+    public function setPersist(array $names): self
     {
         $this->options['persist'] = $names;
 
@@ -252,7 +251,7 @@ class Route
      *
      * @return bool
      */
-    public function compiled()
+    public function compiled(): bool
     {
         return !empty($this->_compiledRoute);
     }
@@ -265,7 +264,7 @@ class Route
      *
      * @return string Returns a string regular expression of the compiled route.
      */
-    public function compile()
+    public function compile(): string
     {
         if ($this->_compiledRoute) {
             return $this->_compiledRoute;
@@ -283,7 +282,7 @@ class Route
      *
      * @return void
      */
-    protected function _writeRoute()
+    protected function _writeRoute(): void
     {
         if (empty($this->template) || ($this->template === '/')) {
             $this->_compiledRoute = '#^/*$#';
@@ -352,7 +351,7 @@ class Route
      *
      * @return string
      */
-    public function getName()
+    public function getName(): string
     {
         if (!empty($this->_name)) {
             return $this->_name;
@@ -391,16 +390,16 @@ class Route
      * false will be returned.
      *
      * @param \Psr\Http\Message\ServerRequestInterface $request The URL to attempt to parse.
-     * @return array|false An array of request parameters, or false on failure.
+     * @return array|null An array of request parameters, or null on failure.
      */
-    public function parseRequest(ServerRequestInterface $request)
+    public function parseRequest(ServerRequestInterface $request): ?array
     {
         $uri = $request->getUri();
         if (isset($this->options['_host']) && !$this->hostMatches($uri->getHost())) {
-            return false;
+            return null;
         }
 
-        return $this->parse($uri->getPath(), $request->getMethod());
+        return $this->parse($uri->getPath(), (string)$request->getMethod());
     }
 
     /**
@@ -411,9 +410,9 @@ class Route
      *
      * @param string $url The URL to attempt to parse.
      * @param string $method The HTTP method of the request being parsed.
-     * @return array|false An array of request parameters, or false on failure.
+     * @return array|null An array of request parameters, or null on failure.
      */
-    public function parse($url, $method)
+    public function parse(string $url, string $method): ?array
     {
         if (empty($this->_compiledRoute)) {
             $this->compile();
@@ -421,13 +420,13 @@ class Route
         list($url, $ext) = $this->_parseExtension($url);
 
         if (!preg_match($this->_compiledRoute, urldecode($url), $route)) {
-            return false;
+            return null;
         }
 
         if (isset($this->defaults['_method']) &&
             !in_array($method, (array)$this->defaults['_method'], true)
         ) {
-            return false;
+            return null;
         }
 
         array_shift($route);
@@ -492,7 +491,7 @@ class Route
      * @param string $host The request's host name
      * @return bool Whether or not the host matches any conditions set in for this route.
      */
-    public function hostMatches($host)
+    public function hostMatches(string $host): bool
     {
         $pattern = '@^' . str_replace('\*', '.*', preg_quote($this->options['_host'], '@')) . '$@';
 
@@ -576,9 +575,9 @@ class Route
      * @param array $context An array of the current request context.
      *   Contains information such as the current host, scheme, port, base
      *   directory and other url params.
-     * @return string|false Either a string URL for the parameters if they match or false.
+     * @return string|null Either a string URL for the parameters if they match or null.
      */
-    public function match(array $url, array $context = [])
+    public function match(array $url, array $context = []): ?string
     {
         if (empty($this->_compiledRoute)) {
             $this->compile();
@@ -604,8 +603,8 @@ class Route
             }
 
             // The host did not match the route preferences
-            if (!$this->hostMatches($hostOptions['_host'])) {
-                return false;
+            if (!$this->hostMatches((string)$hostOptions['_host'])) {
+                return null;
             }
         }
 
@@ -639,18 +638,18 @@ class Route
 
         // Check the method first as it is special.
         if (!$this->_matchMethod($url)) {
-            return false;
+            return null;
         }
         unset($url['_method'], $url['[method]'], $defaults['_method']);
 
         // Missing defaults is a fail.
         if (array_diff_key($defaults, $url) !== []) {
-            return false;
+            return null;
         }
 
         // Defaults with different values are a fail.
         if (array_intersect_key($url, $defaults) != $defaults) {
-            return false;
+            return null;
         }
 
         // If this route uses pass option, and the passed elements are
@@ -667,7 +666,7 @@ class Route
         // check that all the key names are in the url
         $keyNames = array_flip($this->keys);
         if (array_intersect_key($keyNames, $url) !== $keyNames) {
-            return false;
+            return null;
         }
 
         $pass = [];
@@ -700,14 +699,14 @@ class Route
 
         // if not a greedy route, no extra params are allowed.
         if (!$this->_greedy && !empty($pass)) {
-            return false;
+            return null;
         }
 
         // check patterns for routed params
         if (!empty($this->options)) {
             foreach ($this->options as $key => $pattern) {
                 if (isset($url[$key]) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
-                    return false;
+                    return null;
                 }
             }
         }
@@ -819,7 +818,7 @@ class Route
      *
      * @return string
      */
-    public function staticPath()
+    public function staticPath(): string
     {
         $routeKey = strpos($this->template, ':');
         if ($routeKey !== false) {

+ 3 - 3
src/Routing/RouteCollection.php

@@ -137,7 +137,7 @@ class RouteCollection
      * @return array An array of request parameters parsed from the URL.
      * @throws \Cake\Routing\Exception\MissingRouteException When a URL has no matching route.
      */
-    public function parse($url, $method = '')
+    public function parse(string $url, string $method = ''): array
     {
         $decoded = urldecode($url);
 
@@ -158,7 +158,7 @@ class RouteCollection
             /* @var \Cake\Routing\Route\Route $route */
             foreach ($this->_paths[$path] as $route) {
                 $r = $route->parse($url, $method);
-                if ($r === false) {
+                if ($r === null) {
                     continue;
                 }
                 if ($queryParameters) {
@@ -203,7 +203,7 @@ class RouteCollection
             /* @var \Cake\Routing\Route\Route $route */
             foreach ($this->_paths[$path] as $route) {
                 $r = $route->parseRequest($request);
-                if ($r === false) {
+                if ($r === null) {
                     continue;
                 }
                 if ($uri->getQuery()) {

+ 7 - 7
tests/TestCase/Routing/Route/DashedRouteTest.php

@@ -33,7 +33,7 @@ class DashedRouteTest extends TestCase
     {
         $route = new DashedRoute('/:controller/:action/:id', ['plugin' => null]);
         $result = $route->match(['controller' => 'Posts', 'action' => 'myView', 'plugin' => null]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match([
             'plugin' => null,
@@ -41,7 +41,7 @@ class DashedRouteTest extends TestCase
             'action' => 'myView',
             0
         ]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match([
             'plugin' => null,
@@ -56,7 +56,7 @@ class DashedRouteTest extends TestCase
         $this->assertEquals('/', $result);
 
         $result = $route->match(['controller' => 'Pages', 'action' => 'display', 'about']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new DashedRoute('/blog/:action', ['controller' => 'Posts']);
         $result = $route->match(['controller' => 'Posts', 'action' => 'myView']);
@@ -66,7 +66,7 @@ class DashedRouteTest extends TestCase
         $this->assertEquals('/blog/my-view?id=2', $result);
 
         $result = $route->match(['controller' => 'Posts', 'action' => 'myView', 1]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new DashedRoute('/foo/:controller/:action', ['action' => 'index']);
         $result = $route->match(['controller' => 'Posts', 'action' => 'myView']);
@@ -96,7 +96,7 @@ class DashedRouteTest extends TestCase
             'action' => 'myView',
             'id' => 1
         ]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match([
             'plugin' => 'TestPlugin',
@@ -104,7 +104,7 @@ class DashedRouteTest extends TestCase
             'action' => 'edit',
             'id' => 1
         ]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new DashedRoute('/admin/subscriptions/:action/*', [
             'controller' => 'Subscribe', 'prefix' => 'admin'
@@ -171,7 +171,7 @@ class DashedRouteTest extends TestCase
         );
         $route->compile();
         $result = $route->parse('/admin/', 'GET');
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->parse('/admin/my-posts', 'GET');
         $this->assertEquals('MyPosts', $result['controller']);

+ 8 - 8
tests/TestCase/Routing/Route/InflectedRouteTest.php

@@ -33,7 +33,7 @@ class InflectedRouteTest extends TestCase
     {
         $route = new InflectedRoute('/:controller/:action/:id', ['plugin' => null]);
         $result = $route->match(['controller' => 'Posts', 'action' => 'my_view', 'plugin' => null]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match([
             'plugin' => null,
@@ -41,7 +41,7 @@ class InflectedRouteTest extends TestCase
             'action' => 'my_view',
             0
         ]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match([
             'plugin' => null,
@@ -56,7 +56,7 @@ class InflectedRouteTest extends TestCase
         $this->assertEquals('/', $result);
 
         $result = $route->match(['controller' => 'Pages', 'action' => 'display', 'about']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new InflectedRoute('/blog/:action', ['controller' => 'Posts']);
         $result = $route->match(['controller' => 'Posts', 'action' => 'my_view']);
@@ -66,7 +66,7 @@ class InflectedRouteTest extends TestCase
         $this->assertEquals('/blog/my_view?id=2', $result);
 
         $result = $route->match(['controller' => 'Posts', 'action' => 'my_view', 1]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new InflectedRoute('/foo/:controller/:action', ['action' => 'index']);
         $result = $route->match(['controller' => 'Posts', 'action' => 'my_view']);
@@ -96,7 +96,7 @@ class InflectedRouteTest extends TestCase
             'action' => 'my_view',
             'id' => 1
         ]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match([
             'plugin' => 'TestPlugin',
@@ -104,7 +104,7 @@ class InflectedRouteTest extends TestCase
             'action' => 'edit',
             'id' => 1
         ]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new InflectedRoute('/admin/subscriptions/:action/*', [
             'controller' => 'Subscribe', 'prefix' => 'admin'
@@ -171,7 +171,7 @@ class InflectedRouteTest extends TestCase
         );
         $route->compile();
         $result = $route->parse('/admin/', 'GET');
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->parse('/admin/my_posts', 'GET');
         $this->assertEquals('MyPosts', $result['controller']);
@@ -200,7 +200,7 @@ class InflectedRouteTest extends TestCase
     public function testParseMethodMatch()
     {
         $route = new InflectedRoute('/:controller/:action', ['_method' => 'POST']);
-        $this->assertFalse($route->parse('/blog_posts/add_new', 'GET'));
+        $this->assertNull($route->parse('/blog_posts/add_new', 'GET'));
 
         $result = $route->parse('/blog_posts/add_new', 'POST');
         $this->assertEquals('BlogPosts', $result['controller']);

+ 2 - 2
tests/TestCase/Routing/Route/PluginShortRouteTest.php

@@ -52,7 +52,7 @@ class PluginShortRouteTest extends TestCase
         $this->assertEquals('index', $result['action']);
 
         $result = $route->parse('/wrong', 'GET');
-        $this->assertFalse($result, 'Wrong plugin name matched %s');
+        $this->assertNull($result, 'Wrong plugin name matched %s');
     }
 
     /**
@@ -65,7 +65,7 @@ class PluginShortRouteTest extends TestCase
         $route = new PluginShortRoute('/:plugin', ['action' => 'index'], ['plugin' => 'foo|bar']);
 
         $result = $route->match(['plugin' => 'foo', 'controller' => 'posts', 'action' => 'index']);
-        $this->assertFalse($result, 'plugin controller mismatch was converted. %s');
+        $this->assertNull($result, 'plugin controller mismatch was converted. %s');
 
         $result = $route->match(['plugin' => 'foo', 'controller' => 'foo', 'action' => 'index']);
         $this->assertEquals('/foo', $result);

+ 5 - 5
tests/TestCase/Routing/Route/RedirectRouteTest.php

@@ -47,7 +47,7 @@ class RedirectRouteTest extends TestCase
     public function testMatch()
     {
         $route = new RedirectRoute('/home', ['controller' => 'posts']);
-        $this->assertFalse($route->match(['controller' => 'posts', 'action' => 'index']));
+        $this->assertNull($route->match(['controller' => 'posts', 'action' => 'index']));
     }
 
     /**
@@ -58,8 +58,8 @@ class RedirectRouteTest extends TestCase
     public function testParseMiss()
     {
         $route = new RedirectRoute('/home', ['controller' => 'posts']);
-        $this->assertFalse($route->parse('/nope'));
-        $this->assertFalse($route->parse('/homes'));
+        $this->assertNull($route->parse('/nope'));
+        $this->assertNull($route->parse('/homes'));
     }
 
     /**
@@ -114,7 +114,7 @@ class RedirectRouteTest extends TestCase
         $this->expectException(\Cake\Routing\Exception\RedirectException::class);
         $this->expectExceptionMessage('http://google.com');
         $this->expectExceptionCode(301);
-        $route = new RedirectRoute('/google', 'http://google.com');
+        $route = new RedirectRoute('/google', ['redirect' => 'http://google.com']);
         $route->parse('/google');
     }
 
@@ -176,7 +176,7 @@ class RedirectRouteTest extends TestCase
         $this->expectException(\Cake\Routing\Exception\RedirectException::class);
         $this->expectExceptionMessage('http://localhost/test');
         $this->expectExceptionCode(301);
-        $route = new RedirectRoute('/posts/*', '/test', ['persist' => true]);
+        $route = new RedirectRoute('/posts/*', ['redirect' => '/test'], ['persist' => true]);
         $route->parse('/posts/2');
     }
 

+ 32 - 30
tests/TestCase/Routing/Route/RouteTest.php

@@ -558,7 +558,7 @@ class RouteTest extends TestCase
                 'action' => 'branches|history|branch|logs|view|start|add|edit|modify'
             ]
         );
-        $this->assertFalse($route->parse('/chaw_test/wiki', 'GET'));
+        $this->assertNull($route->parse('/chaw_test/wiki', 'GET'));
 
         $result = $route->compile();
         $this->assertNotRegExp($result, '/some_project/source');
@@ -577,10 +577,10 @@ class RouteTest extends TestCase
     {
         $route = new Route('/:controller/:action/:id', ['plugin' => null]);
         $result = $route->match(['controller' => 'posts', 'action' => 'view', 'plugin' => null]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['plugin' => null, 'controller' => 'posts', 'action' => 'view', 0]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => 1]);
         $this->assertEquals('/posts/view/1', $result);
@@ -590,7 +590,7 @@ class RouteTest extends TestCase
         $this->assertEquals('/', $result);
 
         $result = $route->match(['controller' => 'pages', 'action' => 'display', 'about']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new Route('/pages/*', ['controller' => 'pages', 'action' => 'display']);
         $result = $route->match(['controller' => 'pages', 'action' => 'display', 'home']);
@@ -607,10 +607,10 @@ class RouteTest extends TestCase
         $this->assertEquals('/blog/view?id=2', $result);
 
         $result = $route->match(['controller' => 'nodes', 'action' => 'view']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['controller' => 'posts', 'action' => 'view', 1]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new Route('/foo/:controller/:action', ['action' => 'index']);
         $result = $route->match(['controller' => 'posts', 'action' => 'view']);
@@ -624,10 +624,10 @@ class RouteTest extends TestCase
         $this->assertEquals('/fo/1/0', $result);
 
         $result = $route->match(['plugin' => 'fo', 'controller' => 'nodes', 'action' => 'view', 'id' => 1]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['plugin' => 'fo', 'controller' => 'posts', 'action' => 'edit', 'id' => 1]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new Route('/admin/subscriptions/:action/*', [
             'controller' => 'subscribe', 'prefix' => 'admin'
@@ -776,20 +776,20 @@ class RouteTest extends TestCase
             'controller' => 'Articles',
             'action' => 'index'
         ]);
-        $this->assertFalse($result, 'No request context means no match');
+        $this->assertNull($result, 'No request context means no match');
 
         $result = $route->match([
             'controller' => 'Articles',
             'action' => 'index',
         ], ['_host' => 'wrong.com']);
-        $this->assertFalse($result, 'Request context has bad host');
+        $this->assertNull($result, 'Request context has bad host');
 
         $result = $route->match([
             'controller' => 'Articles',
             'action' => 'index',
             '_host' => 'wrong.com'
         ]);
-        $this->assertFalse($result, 'Url param is wrong');
+        $this->assertNull($result, 'Url param is wrong');
 
         $result = $route->match([
             'controller' => 'Articles',
@@ -827,11 +827,11 @@ class RouteTest extends TestCase
     {
         $route = new Route('/:controller/:action', ['plugin' => null]);
         $result = $route->match(['controller' => 'posts', 'action' => 'view', '0']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $route = new Route('/:controller/:action', ['plugin' => null]);
         $result = $route->match(['controller' => 'posts', 'action' => 'view', 'test']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
     }
 
     /**
@@ -871,13 +871,13 @@ class RouteTest extends TestCase
 
         $route = new Route('/test2/*', ['controller' => 'pages', 'action' => 'display', 2]);
         $result = $route->match(['controller' => 'pages', 'action' => 'display', 1]);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['controller' => 'pages', 'action' => 'display', 2, 'something']);
         $this->assertEquals('/test2/something', $result);
 
         $result = $route->match(['controller' => 'pages', 'action' => 'display', 5, 'something']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
     }
 
     /**
@@ -924,7 +924,7 @@ class RouteTest extends TestCase
             1 => 2,
             2 => 'second'
         ]);
-        $this->assertFalse($result, 'Positional args must match exactly.');
+        $this->assertNull($result, 'Positional args must match exactly.');
     }
 
     /**
@@ -1020,7 +1020,7 @@ class RouteTest extends TestCase
     {
         $route = new Route('/:controller/:action/:id', ['plugin' => null], ['id' => '[0-9]+']);
         $result = $route->match(['controller' => 'posts', 'action' => 'view', 'id' => 'foo']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => '9']);
         $this->assertEquals('/posts/view/9', $result);
@@ -1029,7 +1029,7 @@ class RouteTest extends TestCase
         $this->assertEquals('/posts/view/922', $result);
 
         $result = $route->match(['plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => 'a99']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
     }
 
     /**
@@ -1098,6 +1098,7 @@ class RouteTest extends TestCase
      */
     public function testParseRequestDelegates()
     {
+        /** @var \Cake\Routing\Route\Route|\PHPUnit\Framework\MockObject\MockObject $route */
         $route = $this->getMockBuilder('Cake\Routing\Route\Route')
             ->setMethods(['parse'])
             ->setConstructorArgs(['/forward', ['controller' => 'Articles', 'action' => 'index']])
@@ -1106,7 +1107,7 @@ class RouteTest extends TestCase
         $route->expects($this->once())
             ->method('parse')
             ->with('/forward', 'GET')
-            ->will($this->returnValue('works!'));
+            ->will($this->returnValue(['works!']));
 
         $request = new ServerRequest([
             'environment' => [
@@ -1115,6 +1116,7 @@ class RouteTest extends TestCase
             ]
         ]);
         $result = $route->parseRequest($request);
+        $this->assertNotEmpty($result);
     }
 
     /**
@@ -1160,7 +1162,7 @@ class RouteTest extends TestCase
                 'PATH_INFO' => '/fallback'
             ]
         ]);
-        $this->assertFalse($route->parseRequest($request));
+        $this->assertNull($route->parseRequest($request));
     }
 
     /**
@@ -1187,7 +1189,7 @@ class RouteTest extends TestCase
         );
         $route->compile();
         $result = $route->parse('/admin/', 'GET');
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->parse('/admin/posts', 'GET');
         $this->assertEquals('posts', $result['controller']);
@@ -1277,7 +1279,7 @@ class RouteTest extends TestCase
     public function testParseWithHttpHeaderConditions()
     {
         $route = new Route('/sample', ['controller' => 'posts', 'action' => 'index', '_method' => 'POST']);
-        $this->assertFalse($route->parse('/sample', 'GET'));
+        $this->assertNull($route->parse('/sample', 'GET'));
 
         $expected = [
             'controller' => 'posts',
@@ -1301,7 +1303,7 @@ class RouteTest extends TestCase
             'action' => 'index',
             '_method' => ['PUT', 'POST']
         ]);
-        $this->assertFalse($route->parse('/sample', 'GET'));
+        $this->assertNull($route->parse('/sample', 'GET'));
 
         $expected = [
             'controller' => 'posts',
@@ -1329,14 +1331,14 @@ class RouteTest extends TestCase
             'controller' => 'posts',
             'action' => 'index',
         ];
-        $this->assertFalse($route->match($url));
+        $this->assertNull($route->match($url));
 
         $url = [
             'controller' => 'posts',
             'action' => 'index',
             '_method' => 'GET',
         ];
-        $this->assertFalse($route->match($url));
+        $this->assertNull($route->match($url));
 
         $url = [
             'controller' => 'posts',
@@ -1373,7 +1375,7 @@ class RouteTest extends TestCase
             ['action' => 'other|actions']
         );
         $result = $route->match(['controller' => 'blog_posts', 'action' => 'foo']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['controller' => 'blog_posts', 'action' => 'actions']);
         $this->assertNotEmpty($result);
@@ -1388,7 +1390,7 @@ class RouteTest extends TestCase
         $this->assertEquals($expected, $result);
 
         $result = $route->parse('/blog/foobar', 'GET');
-        $this->assertFalse($result);
+        $this->assertNull($result);
     }
 
     /**
@@ -1696,7 +1698,7 @@ class RouteTest extends TestCase
         ]);
         $this->assertInstanceOf('Cake\Routing\Route\Route', $route);
         $this->assertSame('/', $route->match(['controller' => 'pages', 'action' => 'display', 'home']));
-        $this->assertFalse($route->match(['controller' => 'pages', 'action' => 'display', 'about']));
+        $this->assertNull($route->match(['controller' => 'pages', 'action' => 'display', 'about']));
         $expected = [
             'controller' => 'pages',
             'action' => 'display',
@@ -1754,7 +1756,7 @@ class RouteTest extends TestCase
         $this->assertSame('[a-z]+', $route->options['id']);
         $this->assertArrayNotHasKey('multibytePattern', $route->options);
 
-        $this->assertFalse($route->parse('/reviews/a-b-c/xyz', 'GET'));
+        $this->assertNull($route->parse('/reviews/a-b-c/xyz', 'GET'));
         $this->assertNotEmpty($route->parse('/reviews/2016-05-12/xyz', 'GET'));
     }
 
@@ -1792,7 +1794,7 @@ class RouteTest extends TestCase
                 'PATH_INFO' => '/reviews'
             ]
         ]);
-        $this->assertFalse($route->parseRequest($request));
+        $this->assertNull($route->parseRequest($request));
 
         $uri = $request->getUri();
         $request = $request->withUri($uri->withHost('blog.example.com'));

+ 9 - 1
tests/TestCase/Routing/RouteCollectionTest.php

@@ -23,6 +23,10 @@ use Cake\TestSuite\TestCase;
 
 class RouteCollectionTest extends TestCase
 {
+    /**
+     * @var \Cake\Routing\RouteCollection
+     */
+    protected $collection;
 
     /**
      * Setup method
@@ -38,6 +42,7 @@ class RouteCollectionTest extends TestCase
     /**
      * Test parse() throws an error on unknown routes.
      *
+     * @return void
      */
     public function testParseMissingRoute()
     {
@@ -54,6 +59,7 @@ class RouteCollectionTest extends TestCase
     /**
      * Test parse() throws an error on known routes called with unknown methods.
      *
+     * @return void
      */
     public function testParseMissingRouteMethod()
     {
@@ -245,6 +251,7 @@ class RouteCollectionTest extends TestCase
     /**
      * Test parseRequest() throws an error on unknown routes.
      *
+     * @return void
      */
     public function testParseRequestMissingRoute()
     {
@@ -443,6 +450,7 @@ class RouteCollectionTest extends TestCase
     /**
      * Test match() throws an error on unknown routes.
      *
+     * @return void
      */
     public function testMatchError()
     {
@@ -511,6 +519,7 @@ class RouteCollectionTest extends TestCase
     /**
      * Test match() throws an error on named routes that fail to match
      *
+     * @return void
      */
     public function testMatchNamedError()
     {
@@ -640,7 +649,6 @@ class RouteCollectionTest extends TestCase
     /**
      * Test the add() with some _name.
      *
-     *
      * @return void
      */
     public function testAddingDuplicateNamedRoutes()

+ 28 - 37
tests/TestCase/Routing/RouterTest.php

@@ -63,7 +63,7 @@ class RouterTest extends TestCase
      */
     public function testBaseUrl()
     {
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $routes->fallbacks();
         });
         $this->assertRegExp('/^http(s)?:\/\//', Router::url('/', true));
@@ -78,7 +78,7 @@ class RouterTest extends TestCase
      */
     public function testFullBaseURL()
     {
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $routes->fallbacks();
         });
         Router::fullBaseUrl('http://example.com');
@@ -188,7 +188,7 @@ class RouterTest extends TestCase
      */
     public function testGenerateUrlResourceRoute()
     {
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $routes->resources('Posts');
         });
 
@@ -814,8 +814,8 @@ class RouterTest extends TestCase
      */
     public function testUrlGenerationPrefixedPlugin()
     {
-        Router::prefix('admin', function ($routes) {
-            $routes->plugin('MyPlugin', function ($routes) {
+        Router::prefix('admin', function (RouteBuilder $routes) {
+            $routes->plugin('MyPlugin', function (RouteBuilder $routes) {
                 $routes->fallbacks('InflectedRoute');
             });
         });
@@ -831,8 +831,8 @@ class RouterTest extends TestCase
      */
     public function testUrlGenerationMultiplePrefixes()
     {
-        Router::prefix('admin', function ($routes) {
-            $routes->prefix('backoffice', function ($routes) {
+        Router::prefix('admin', function (RouteBuilder $routes) {
+            $routes->prefix('backoffice', function (RouteBuilder $routes) {
                 $routes->fallbacks('InflectedRoute');
             });
         });
@@ -1566,11 +1566,11 @@ class RouterTest extends TestCase
     {
         Router::extensions(['json']);
 
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $routes->setExtensions('rss');
             $routes->connect('/', ['controller' => 'Pages', 'action' => 'index']);
 
-            $routes->scope('/api', function ($routes) {
+            $routes->scope('/api', function (RouteBuilder $routes) {
                 $routes->setExtensions('xml');
                 $routes->connect('/docs', ['controller' => 'ApiDocs', 'action' => 'index']);
             });
@@ -1586,7 +1586,7 @@ class RouterTest extends TestCase
      */
     public function testResourcesInScope()
     {
-        Router::scope('/api', ['prefix' => 'api'], function ($routes) {
+        Router::scope('/api', ['prefix' => 'api'], function (RouteBuilder $routes) {
             $routes->setExtensions(['json']);
             $routes->resources('Articles');
         });
@@ -2472,7 +2472,7 @@ class RouterTest extends TestCase
 
     public function testReverseFull()
     {
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $routes->fallbacks();
         });
         $params = [
@@ -2693,7 +2693,7 @@ class RouterTest extends TestCase
             ['action' => 'other|actions']
         );
         $result = $route->match(['controller' => 'blog_posts', 'action' => 'foo']);
-        $this->assertFalse($result);
+        $this->assertNull($result);
 
         $result = $route->match(['controller' => 'blog_posts', 'action' => 'actions']);
         $this->assertEquals('/blog/actions/', $result);
@@ -2708,7 +2708,7 @@ class RouterTest extends TestCase
         $this->assertEquals($expected, $result);
 
         $result = $route->parseRequest($this->makeRequest('/blog/foobar', 'GET'));
-        $this->assertFalse($result);
+        $this->assertNull($result);
     }
 
     /**
@@ -2718,8 +2718,7 @@ class RouterTest extends TestCase
      */
     public function testScope()
     {
-        Router::scope('/path', ['param' => 'value'], function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::scope('/path', ['param' => 'value'], function (RouteBuilder $routes) {
             $this->assertEquals('/path', $routes->path());
             $this->assertEquals(['param' => 'value'], $routes->params());
             $this->assertEquals('', $routes->namePrefix());
@@ -2748,7 +2747,7 @@ class RouterTest extends TestCase
     public function testScopeExtensionsContained()
     {
         Router::extensions(['json']);
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $this->assertEquals(['json'], $routes->getExtensions(), 'Should default to global extensions.');
             $routes->setExtensions(['rss']);
 
@@ -2762,13 +2761,13 @@ class RouterTest extends TestCase
 
         $this->assertEquals(['json', 'rss'], array_values(Router::extensions()));
 
-        Router::scope('/api', function ($routes) {
+        Router::scope('/api', function (RouteBuilder $routes) {
             $this->assertEquals(['json'], $routes->getExtensions(), 'Should default to global extensions.');
 
             $routes->setExtensions(['json', 'csv']);
             $routes->connect('/export', []);
 
-            $routes->scope('/v1', function ($routes) {
+            $routes->scope('/v1', function (RouteBuilder $routes) {
                 $this->assertEquals(['json', 'csv'], $routes->getExtensions());
             });
         });
@@ -2784,7 +2783,7 @@ class RouterTest extends TestCase
     public function testScopeOptions()
     {
         $options = ['param' => 'value', 'routeClass' => 'InflectedRoute', 'extensions' => ['json']];
-        Router::scope('/path', $options, function ($routes) {
+        Router::scope('/path', $options, function (RouteBuilder $routes) {
             $this->assertSame('InflectedRoute', $routes->getRouteClass());
             $this->assertSame(['json'], $routes->getExtensions());
             $this->assertEquals('/path', $routes->path());
@@ -2799,8 +2798,7 @@ class RouterTest extends TestCase
      */
     public function testScopeNamePrefix()
     {
-        Router::scope('/path', ['param' => 'value', '_namePrefix' => 'path:'], function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::scope('/path', ['param' => 'value', '_namePrefix' => 'path:'], function (RouteBuilder $routes) {
             $this->assertEquals('/path', $routes->path());
             $this->assertEquals(['param' => 'value'], $routes->params());
             $this->assertEquals('path:', $routes->namePrefix());
@@ -2816,14 +2814,12 @@ class RouterTest extends TestCase
      */
     public function testPrefix()
     {
-        Router::prefix('admin', function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::prefix('admin', function (RouteBuilder $routes) {
             $this->assertEquals('/admin', $routes->path());
             $this->assertEquals(['prefix' => 'admin'], $routes->params());
         });
 
-        Router::prefix('admin', ['_namePrefix' => 'admin:'], function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::prefix('admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $routes) {
             $this->assertEquals('admin:', $routes->namePrefix());
             $this->assertEquals(['prefix' => 'admin'], $routes->params());
         });
@@ -2836,14 +2832,12 @@ class RouterTest extends TestCase
      */
     public function testPrefixOptions()
     {
-        Router::prefix('admin', ['param' => 'value'], function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::prefix('admin', ['param' => 'value'], function (RouteBuilder $routes) {
             $this->assertEquals('/admin', $routes->path());
             $this->assertEquals(['prefix' => 'admin', 'param' => 'value'], $routes->params());
         });
 
-        Router::prefix('CustomPath', ['path' => '/custom-path'], function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::prefix('CustomPath', ['path' => '/custom-path'], function (RouteBuilder $routes) {
             $this->assertEquals('/custom-path', $routes->path());
             $this->assertEquals(['prefix' => 'custom_path'], $routes->params());
         });
@@ -2856,8 +2850,7 @@ class RouterTest extends TestCase
      */
     public function testPlugin()
     {
-        Router::plugin('DebugKit', function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::plugin('DebugKit', function (RouteBuilder $routes) {
             $this->assertEquals('/debug_kit', $routes->path());
             $this->assertEquals(['plugin' => 'DebugKit'], $routes->params());
         });
@@ -2870,14 +2863,12 @@ class RouterTest extends TestCase
      */
     public function testPluginOptions()
     {
-        Router::plugin('DebugKit', ['path' => '/debugger'], function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::plugin('DebugKit', ['path' => '/debugger'], function (RouteBuilder $routes) {
             $this->assertEquals('/debugger', $routes->path());
             $this->assertEquals(['plugin' => 'DebugKit'], $routes->params());
         });
 
-        Router::plugin('Contacts', ['_namePrefix' => 'contacts:'], function ($routes) {
-            $this->assertInstanceOf('Cake\Routing\RouteBuilder', $routes);
+        Router::plugin('Contacts', ['_namePrefix' => 'contacts:'], function (RouteBuilder $routes) {
             $this->assertEquals('contacts:', $routes->namePrefix());
         });
     }
@@ -2906,7 +2897,7 @@ class RouterTest extends TestCase
 
         Router::reload();
         Router::defaultRouteClass('DashedRoute');
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $routes->fallbacks();
         });
 
@@ -3045,7 +3036,7 @@ class RouterTest extends TestCase
      */
     protected function _connectDefaultRoutes()
     {
-        Router::scope('/', function ($routes) {
+        Router::scope('/', function (RouteBuilder $routes) {
             $routes->fallbacks('InflectedRoute');
         });
     }