ソースを参照

Use the `pass` option when matching routes.

Routes are much easier to refactor if the `pass` option is honoured
when matching routes. When the pass option is defined, positional
arguments will be rekeyed to their matching route element should the
route element be undefined.

Fixes #4359
mark_story 11 年 前
コミット
82a94ab10a
2 ファイル変更92 行追加1 行削除
  1. 11 0
      src/Routing/Route/Route.php
  2. 81 1
      tests/TestCase/Routing/Route/RouteTest.php

+ 11 - 0
src/Routing/Route/Route.php

@@ -430,6 +430,17 @@ class Route {
 			return false;
 		}
 
+		// If this route uses pass option, and the passed elements are
+		// not set, rekey elements.
+		if (isset($this->options['pass'])) {
+			foreach ($this->options['pass'] as $i => $name) {
+				if (isset($url[$i]) && !isset($url[$name])) {
+					$url[$name] = $url[$i];
+					unset($url[$i]);
+				}
+			}
+		}
+
 		// check that all the key names are in the url
 		$keyNames = array_flip($this->keys);
 		if (array_intersect_key($keyNames, $url) !== $keyNames) {

+ 81 - 1
tests/TestCase/Routing/Route/RouteTest.php

@@ -393,7 +393,7 @@ class RouteTest extends TestCase {
  *
  * @return void
  */
-	public function testGreedyRouteFailurePassedArg() {
+	public function testMatchGreedyRouteFailurePassedArg() {
 		$route = new Route('/:controller/:action', array('plugin' => null));
 		$result = $route->match(array('controller' => 'posts', 'action' => 'view', '0'));
 		$this->assertFalse($result);
@@ -448,6 +448,86 @@ class RouteTest extends TestCase {
 	}
 
 /**
+ * Test that the pass option lets you use positional arguments for the
+ * route elements that were named.
+ *
+ * @return void
+ */
+	public function testMatchWithPassOption() {
+		$route = new Route(
+			'/blog/:id-:slug',
+			['controller' => 'Blog', 'action' => 'view'],
+			['pass' => ['id', 'slug']]
+		);
+		$result = $route->match([
+			'controller' => 'Blog',
+			'action' => 'view',
+			'id' => 1,
+			'slug' => 'second'
+		]);
+		$this->assertEquals('/blog/1-second', $result);
+
+		$result = $route->match([
+			'controller' => 'Blog',
+			'action' => 'view',
+			1,
+			'second'
+		]);
+		$this->assertEquals('/blog/1-second', $result);
+
+		$result = $route->match([
+			'controller' => 'Blog',
+			'action' => 'view',
+			1,
+			'second',
+			'query' => 'string'
+		]);
+		$this->assertEquals('/blog/1-second?query=string', $result);
+
+		$result = $route->match([
+			'controller' => 'Blog',
+			'action' => 'view',
+			1 => 2,
+			2 => 'second'
+		]);
+		$this->assertFalse($result, 'Positional args must match exactly.');
+	}
+
+/**
+ * Test that match() with pass and greedy routes.
+ *
+ * @return void
+ */
+	public function testMatchWithPassOptionGreedy() {
+		$route = new Route(
+			'/blog/:id-:slug/*',
+			['controller' => 'Blog', 'action' => 'view'],
+			['pass' => ['id', 'slug']]
+		);
+		$result = $route->match([
+			'controller' => 'Blog',
+			'action' => 'view',
+			'id' => 1,
+			'slug' => 'second',
+			'third',
+			'fourth',
+			'query' => 'string'
+		]);
+		$this->assertEquals('/blog/1-second/third/fourth?query=string', $result);
+
+		$result = $route->match([
+			'controller' => 'Blog',
+			'action' => 'view',
+			1,
+			'second',
+			'third',
+			'fourth',
+			'query' => 'string'
+		]);
+		$this->assertEquals('/blog/1-second/third/fourth?query=string', $result);
+	}
+
+/**
  * Test that extensions work.
  *
  * @return void