Browse Source

Implementing reverse routing syntax

Florian Krämer 8 years ago
parent
commit
4f251f074e
3 changed files with 100 additions and 4 deletions
  1. 6 2
      src/Routing/RouteBuilder.php
  2. 47 2
      src/Routing/Router.php
  3. 47 0
      tests/TestCase/Routing/RouterTest.php

+ 6 - 2
src/Routing/RouteBuilder.php

@@ -693,7 +693,7 @@ class RouteBuilder
      * The above route will only be matched for GET requests. POST requests will fail to match this route.
      *
      * @param string $route A string describing the template of the route
-     * @param array $defaults An array describing the default route parameters. These parameters will be used by default
+     * @param array|string|null $defaults An array describing the default route parameters. These parameters will be used by default
      *   and can supply routing parameters that are not dynamic. See above.
      * @param array $options An array matching the named elements in the route to regular expressions which that
      *   element should match. Also contains additional parameters such as which routed parameters should be
@@ -703,8 +703,12 @@ class RouteBuilder
      * @throws \InvalidArgumentException
      * @throws \BadMethodCallException
      */
-    public function connect($route, array $defaults = [], array $options = [])
+    public function connect($route, array $defaults = null, array $options = [])
     {
+        if ($defaults === null) {
+            $defaults = [];
+        }
+
         if (!isset($options['action']) && !isset($defaults['action'])) {
             $defaults['action'] = 'index';
         }

+ 47 - 2
src/Routing/Router.php

@@ -191,7 +191,7 @@ class Router
      * Compatibility proxy to \Cake\Routing\RouteBuilder::connect() in the `/` scope.
      *
      * @param string $route A string describing the template of the route
-     * @param array $defaults An array describing the default route parameters. These parameters will be used by default
+     * @param array|string|null $defaults An array describing the default route parameters. These parameters will be used by default
      *   and can supply routing parameters that are not dynamic. See above.
      * @param array $options An array matching the named elements in the route to regular expressions which that
      *   element should match. Also contains additional parameters such as which routed parameters should be
@@ -202,8 +202,10 @@ class Router
      * @see \Cake\Routing\RouteBuilder::connect()
      * @see \Cake\Routing\Router::scope()
      */
-    public static function connect($route, $defaults = [], $options = [])
+    public static function connect($route, $defaults = null, $options = [])
     {
+        $defaults = static::parseDefaults($defaults);
+
         static::$initialized = true;
         static::scope('/', function ($routes) use ($route, $defaults, $options) {
             $routes->connect($route, $defaults, $options);
@@ -211,6 +213,49 @@ class Router
     }
 
     /**
+     * Parse the defaults if they're a string
+     *
+     * @param string|array
+     * @return mixed
+     */
+    protected static function parseDefaults($defaults)
+    {
+        if (!is_string($defaults)) {
+            return $defaults;
+        }
+
+        $regex = '/(?:([a-zA-Z0-9]*)\.)?([a-zA-Z0-9]*)(?:\\\\)?([a-zA-Z0-9]*):{2}([a-zA-Z0-9]*)/i';
+
+        if (preg_match($regex, $defaults, $matches)) {
+            unset($matches[0]);
+            $matches = array_filter($matches, function($value) {
+                return $value !== '' && $value !== '::';
+            });
+
+            switch (count($matches)) {
+                case 2:
+                    return [
+                        'controller' => $matches[2],
+                        'view' => $matches[4]
+                    ];
+                case 3:
+                    return [
+                        'prefix' => $matches[2],
+                        'controller' => $matches[3],
+                        'view' => $matches[4]
+                    ];
+                case 4:
+                    return [
+                        'plugin' => $matches[1],
+                        'prefix' => $matches[2],
+                        'controller' => $matches[3],
+                        'view' => $matches[4]
+                    ];
+            }
+        }
+    }
+
+    /**
      * Connects a new redirection Route in the router.
      *
      * Compatibility proxy to \Cake\Routing\RouteBuilder::redirect() in the `/` scope.

+ 47 - 0
tests/TestCase/Routing/RouterTest.php

@@ -3423,6 +3423,53 @@ class RouterTest extends TestCase
     }
 
     /**
+     * testShortStringSyntax
+     *
+     * @return void
+     */
+    public function testShortStringSyntax()
+    {
+        Router::connect('/admin/articles/view', 'Admin\Articles::view');
+        $result = Router::parseRequest($this->makeRequest('/admin/articles/view', 'GET'));
+        $expected = [
+            'pass' => [],
+            'prefix' => 'Admin',
+            'controller' => 'Articles',
+            'view' => 'view',
+            'action' => 'index',
+            'plugin' => null,
+            '_matchedRoute' => '/admin/articles/view'
+
+        ];
+        $this->assertEquals($result, $expected);
+
+        Router::connect('/admin/blog/articles/view', 'Blog.Admin\Articles::view');
+        $result = Router::parseRequest($this->makeRequest('/admin/blog/articles/view', 'GET'));
+        $expected = [
+            'pass' => [],
+            'plugin' => 'Blog',
+            'prefix' => 'Admin',
+            'controller' => 'Articles',
+            'view' => 'view',
+            'action' => 'index',
+            '_matchedRoute' => '/admin/blog/articles/view'
+        ];
+        $this->assertEquals($result, $expected);
+
+        Router::connect('/my-articles/view', 'Articles::view');
+        $result = Router::parseRequest($this->makeRequest('/my-articles/view', 'GET'));
+        $expected = [
+            'pass' => [],
+            'controller' => 'Articles',
+            'view' => 'view',
+            'action' => 'index',
+            'plugin' => null,
+            '_matchedRoute' => '/my-articles/view'
+        ];
+        $this->assertEquals($result, $expected);
+    }
+
+    /**
      * Connect some fallback routes for testing router behavior.
      *
      * @return void