Browse Source

Restore 'persist' option for routes.

Refs #6038
ADmad 11 years ago
parent
commit
7f62d57a0f

+ 27 - 2
src/Routing/Route/Route.php

@@ -377,6 +377,28 @@ class Route
     }
 
     /**
+     * Apply persistent parameters to a URL array. Persistent parameters are a
+     * special key used during route creation to force route parameters to
+     * persist when omitted from a URL array.
+     *
+     * @param array $url The array to apply persistent parameters to.
+     * @param array $params An array of persistent values to replace persistent ones.
+     * @return array An array with persistent parameters applied.
+     */
+    public function persistParams(array $url, array $params)
+    {
+        if (empty($this->options['persist']) || !is_array($this->options['persist'])) {
+            return $url;
+        }
+        foreach ($this->options['persist'] as $persistKey) {
+            if (array_key_exists($persistKey, $params) && !isset($url[$persistKey])) {
+                $url[$persistKey] = $params[$persistKey];
+            }
+        }
+        return $url;
+    }
+
+    /**
      * Check if a URL array matches this route instance.
      *
      * If the URL matches the route parameters and settings, then
@@ -385,8 +407,8 @@ class Route
      *
      * @param array $url An array of parameters to check matching with.
      * @param array $context An array of the current request context.
-     *   Contains information such as the current host, scheme, port, and base
-     *   directory.
+     *   Contains information such as the current host, scheme, port, base
+     *   directory and other url params.
      * @return mixed Either a string url for the parameters if they match or false.
      */
     public function match(array $url, array $context = [])
@@ -395,7 +417,10 @@ class Route
             $this->compile();
         }
         $defaults = $this->defaults;
+        $context += ['params' => []];
 
+        $url = $this->persistParams($url, $context['params']);
+        unset($context['params']);
         $hostOptions = array_intersect_key($url, $context);
 
         // Check for properties that will cause an

+ 4 - 0
src/Routing/RouteBuilder.php

@@ -350,6 +350,10 @@ class RouteBuilder
      * - `routeClass` is used to extend and change how individual routes parse requests
      *   and handle reverse routing, via a custom routing class.
      *   Ex. `'routeClass' => 'SlugRoute'`
+     * -  `persist` is used to define which route parameters should be automatically
+     *   included when generating new URLs. You can override persistent parameters
+     *   by redefining them in a URL or remove them by setting the parameter to `false`.
+     *   Ex. `'persist' => ['lang']`
      * - `_name` is used to define a specific name for routes. This can be used to optimize
      *   reverse routing lookups. If undefined a name will be generated for each
      *   connected route.

+ 1 - 1
src/Routing/RouteCollection.php

@@ -222,7 +222,7 @@ class RouteCollection
      *
      * @param array $url The url to match.
      * @param array $context The request context to use. Contains _base, _port,
-     *    _host, and _scheme keys.
+     *    _host, _scheme and params keys.
      * @return string|false Either a string on match, or false on failure.
      * @throws \Cake\Routing\Exception\MissingRouteException when a route cannot be matched.
      */

+ 1 - 1
src/Routing/Router.php

@@ -612,7 +612,7 @@ class Router
             }
 
             $url = static::_applyUrlFilters($url);
-            $output = static::$_collection->match($url, static::$_requestContext);
+            $output = static::$_collection->match($url, static::$_requestContext + ['params' => $params]);
         } else {
             $plainString = (
                 strpos($url, 'javascript:') === 0 ||

+ 18 - 0
tests/TestCase/Routing/Route/RouteTest.php

@@ -349,6 +349,24 @@ class RouteTest extends TestCase
     }
 
     /**
+     * Test match() with persist option
+     *
+     * @return void
+     */
+    public function testMatchWithPersistOption()
+    {
+        $context = [
+            'params' => ['lang' => 'en']
+        ];
+        $route = new Route('/:lang/:controller/:action', [], ['persist' => ['lang']]);
+        $result = $route->match(
+            ['controller' => 'tasks', 'action' => 'add'],
+            $context
+        );
+        $this->assertEquals('/en/tasks/add', $result);
+    }
+
+    /**
      * Test match() with _host and other keys.
      */
     public function testMatchWithHostKeys()

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

@@ -1198,6 +1198,29 @@ class RouterTest extends TestCase
     }
 
     /**
+     * Test url param persistence.
+     *
+     * @return void
+     */
+    public function testUrlParamPersistence()
+    {
+        Router::connect('/:lang/:controller/:action/*', [], ['persist' => ['lang']]);
+        $request = new Request();
+        $request->addParams([
+            'lang' => 'en',
+            'controller' => 'posts',
+            'action' => 'index'
+        ])->addPaths([
+            'base' => '',
+            'here' => '/'
+        ]);
+        Router::pushRequest($request);
+
+        $result = Router::url(['controller' => 'tasks', 'action' => 'edit', '1234']);
+        $this->assertEquals('/en/tasks/edit/1234', $result);
+    }
+
+    /**
      * Test that plain strings urls work
      *
      * @return void