Skip to content

Commit

Permalink
Add automatic query string support.
Browse files Browse the repository at this point in the history
Any url keys that are not in the defaults or route
keys are now treated as query string parameters.
  • Loading branch information
markstory committed Jul 4, 2012
1 parent 98b3bfe commit b7df5c0
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 27 deletions.
31 changes: 19 additions & 12 deletions lib/Cake/Routing/Route/Route.php
Expand Up @@ -369,7 +369,7 @@ public function match($url, $context = array()) {
unset($hostOptions['_port']);
}
}

// If no base is set, copy one in.
if (!isset($hostOptions['_base']) && isset($context['_base'])) {
$hostOptions['_base'] = $context['_base'];
Expand All @@ -390,17 +390,19 @@ public function match($url, $context = array()) {
if (array_diff_key($defaults, $url) !== array()) {
return false;
}

// Defaults with different values are a fail.
if (array_intersect_key($url, $defaults) !== $defaults) {
return false;
}

$prefixes = Router::prefixes();
$pass = array();
$query = array();

foreach ($url as $key => $value) {
// keys that exist in the defaults and have different values is a match failure.
$defaultExists = array_key_exists($key, $defaults);
if ($defaultExists && $defaults[$key] != $value) {
return false;
} elseif ($defaultExists) {
continue;
}

// If the key is a routed key, its not different yet.
if (array_key_exists($key, $keyNames)) {
Expand All @@ -418,25 +420,26 @@ public function match($url, $context = array()) {
}

// keys that don't exist are different.
if (!$defaultExists && !empty($value)) {
return false;
if (!$defaultExists && ($value !== null && $value !== false && $value !== '')) {
$query[$key] = $value;
unset($url[$key]);
}
}

//if a not a greedy route, no extra params are allowed.
// if not a greedy route, no extra params are allowed.
if (!$this->_greedy && !empty($pass)) {
return false;
}

//check patterns for routed params
if (!empty($this->options)) {
foreach ($this->options as $key => $pattern) {
if (array_key_exists($key, $url) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
if (isset($url[$key]) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
return false;
}
}
}
return $this->_writeUrl($url, $pass, $hostOptions);
return $this->_writeUrl($url, $pass, $hostOptions, $query);
}

/**
Expand All @@ -447,7 +450,7 @@ public function match($url, $context = array()) {
* @param array $pass The additional passed arguments.
* @return string Composed route string.
*/
protected function _writeUrl($params, $pass = array(), $hostOptions = array()) {
protected function _writeUrl($params, $pass = array(), $hostOptions = array(), $query = array()) {
if (isset($params['prefix'], $params['action'])) {
$params['action'] = str_replace($params['prefix'] . '_', '', $params['action']);
unset($params['prefix']);
Expand Down Expand Up @@ -495,6 +498,10 @@ protected function _writeUrl($params, $pass = array(), $hostOptions = array()) {
$out
);
}
if (!empty($query)) {
$out = rtrim($out, '/');
$out .= '?' . http_build_query($query);
}
return $out;
}

Expand Down
51 changes: 36 additions & 15 deletions lib/Cake/Test/TestCase/Routing/Route/RouteTest.php
Expand Up @@ -269,15 +269,15 @@ public function testMatchBasic() {
$result = $route->match(array('controller' => 'posts', 'action' => 'view'));
$this->assertEquals('/blog/view', $result);

$result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 2));
$this->assertEquals('/blog/view?id=2', $result);

$result = $route->match(array('controller' => 'nodes', 'action' => 'view'));
$this->assertFalse($result);

$result = $route->match(array('controller' => 'posts', 'action' => 'view', 1));
$this->assertFalse($result);

$result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 2));
$this->assertFalse($result);

$route = new Route('/foo/:controller/:action', array('action' => 'index'));
$result = $route->match(array('controller' => 'posts', 'action' => 'view'));
$this->assertEquals('/foo/posts/view', $result);
Expand Down Expand Up @@ -348,7 +348,7 @@ public function testMatchWithHostKeys() {
array('controller' => 'posts', 'action' => 'index', '_base' => '/dir'),
$context
);
$this->assertEquals('http://foo.com/dir/posts/index', $result);
$this->assertEquals('/dir/posts/index', $result);

$result = $route->match(
array(
Expand Down Expand Up @@ -379,17 +379,6 @@ public function testGreedyRouteFailurePassedArg() {
$this->assertFalse($result);
}

/**
* test that non-greedy routes fail with extra passed args
*
* @return void
*/
public function testGreedyRouteFailureNamedParam() {
$route = new Route('/:controller/:action', array('plugin' => null));
$result = $route->match(array('controller' => 'posts', 'action' => 'view', 'page' => 1));
$this->assertFalse($result);
}

/**
* test that falsey values do not interrupt a match.
*
Expand Down Expand Up @@ -454,6 +443,38 @@ public function testMatchWithPatterns() {
$this->assertFalse($result);
}

/**
* Test that match() pulls out extra arguments as query string params.
*
* @return void
*/
public function testMatchExtractQueryStringArgs() {
$route = new Route('/:controller/:action/*');
$result = $route->match(array(
'controller' => 'posts',
'action' => 'index',
'page' => 1
));
$this->assertEquals('/posts/index?page=1', $result);

$result = $route->match(array(
'controller' => 'posts',
'action' => 'index',
'page' => 0
));
$this->assertEquals('/posts/index?page=0', $result);

$result = $route->match(array(
'controller' => 'posts',
'action' => 'index',
1,
'page' => 1,
'dir' => 'desc',
'order' => 'title'
));
$this->assertEquals('/posts/index/1?page=1&dir=desc&order=title', $result);
}

/**
* test persistParams ability to persist parameters from $params and remove params.
*
Expand Down

0 comments on commit b7df5c0

Please sign in to comment.