Skip to content

Commit b7df5c0

Browse files
committed
Add automatic query string support.
Any url keys that are not in the defaults or route keys are now treated as query string parameters.
1 parent 98b3bfe commit b7df5c0

File tree

2 files changed

+55
-27
lines changed

2 files changed

+55
-27
lines changed

lib/Cake/Routing/Route/Route.php

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ public function match($url, $context = array()) {
369369
unset($hostOptions['_port']);
370370
}
371371
}
372-
372+
373373
// If no base is set, copy one in.
374374
if (!isset($hostOptions['_base']) && isset($context['_base'])) {
375375
$hostOptions['_base'] = $context['_base'];
@@ -390,17 +390,19 @@ public function match($url, $context = array()) {
390390
if (array_diff_key($defaults, $url) !== array()) {
391391
return false;
392392
}
393+
394+
// Defaults with different values are a fail.
395+
if (array_intersect_key($url, $defaults) !== $defaults) {
396+
return false;
397+
}
398+
393399
$prefixes = Router::prefixes();
394400
$pass = array();
401+
$query = array();
395402

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

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

420422
// keys that don't exist are different.
421-
if (!$defaultExists && !empty($value)) {
422-
return false;
423+
if (!$defaultExists && ($value !== null && $value !== false && $value !== '')) {
424+
$query[$key] = $value;
425+
unset($url[$key]);
423426
}
424427
}
425428

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

431434
//check patterns for routed params
432435
if (!empty($this->options)) {
433436
foreach ($this->options as $key => $pattern) {
434-
if (array_key_exists($key, $url) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
437+
if (isset($url[$key]) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
435438
return false;
436439
}
437440
}
438441
}
439-
return $this->_writeUrl($url, $pass, $hostOptions);
442+
return $this->_writeUrl($url, $pass, $hostOptions, $query);
440443
}
441444

442445
/**
@@ -447,7 +450,7 @@ public function match($url, $context = array()) {
447450
* @param array $pass The additional passed arguments.
448451
* @return string Composed route string.
449452
*/
450-
protected function _writeUrl($params, $pass = array(), $hostOptions = array()) {
453+
protected function _writeUrl($params, $pass = array(), $hostOptions = array(), $query = array()) {
451454
if (isset($params['prefix'], $params['action'])) {
452455
$params['action'] = str_replace($params['prefix'] . '_', '', $params['action']);
453456
unset($params['prefix']);
@@ -495,6 +498,10 @@ protected function _writeUrl($params, $pass = array(), $hostOptions = array()) {
495498
$out
496499
);
497500
}
501+
if (!empty($query)) {
502+
$out = rtrim($out, '/');
503+
$out .= '?' . http_build_query($query);
504+
}
498505
return $out;
499506
}
500507

lib/Cake/Test/TestCase/Routing/Route/RouteTest.php

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,15 @@ public function testMatchBasic() {
269269
$result = $route->match(array('controller' => 'posts', 'action' => 'view'));
270270
$this->assertEquals('/blog/view', $result);
271271

272+
$result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 2));
273+
$this->assertEquals('/blog/view?id=2', $result);
274+
272275
$result = $route->match(array('controller' => 'nodes', 'action' => 'view'));
273276
$this->assertFalse($result);
274277

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

278-
$result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 2));
279-
$this->assertFalse($result);
280-
281281
$route = new Route('/foo/:controller/:action', array('action' => 'index'));
282282
$result = $route->match(array('controller' => 'posts', 'action' => 'view'));
283283
$this->assertEquals('/foo/posts/view', $result);
@@ -348,7 +348,7 @@ public function testMatchWithHostKeys() {
348348
array('controller' => 'posts', 'action' => 'index', '_base' => '/dir'),
349349
$context
350350
);
351-
$this->assertEquals('http://foo.com/dir/posts/index', $result);
351+
$this->assertEquals('/dir/posts/index', $result);
352352

353353
$result = $route->match(
354354
array(
@@ -379,17 +379,6 @@ public function testGreedyRouteFailurePassedArg() {
379379
$this->assertFalse($result);
380380
}
381381

382-
/**
383-
* test that non-greedy routes fail with extra passed args
384-
*
385-
* @return void
386-
*/
387-
public function testGreedyRouteFailureNamedParam() {
388-
$route = new Route('/:controller/:action', array('plugin' => null));
389-
$result = $route->match(array('controller' => 'posts', 'action' => 'view', 'page' => 1));
390-
$this->assertFalse($result);
391-
}
392-
393382
/**
394383
* test that falsey values do not interrupt a match.
395384
*
@@ -454,6 +443,38 @@ public function testMatchWithPatterns() {
454443
$this->assertFalse($result);
455444
}
456445

446+
/**
447+
* Test that match() pulls out extra arguments as query string params.
448+
*
449+
* @return void
450+
*/
451+
public function testMatchExtractQueryStringArgs() {
452+
$route = new Route('/:controller/:action/*');
453+
$result = $route->match(array(
454+
'controller' => 'posts',
455+
'action' => 'index',
456+
'page' => 1
457+
));
458+
$this->assertEquals('/posts/index?page=1', $result);
459+
460+
$result = $route->match(array(
461+
'controller' => 'posts',
462+
'action' => 'index',
463+
'page' => 0
464+
));
465+
$this->assertEquals('/posts/index?page=0', $result);
466+
467+
$result = $route->match(array(
468+
'controller' => 'posts',
469+
'action' => 'index',
470+
1,
471+
'page' => 1,
472+
'dir' => 'desc',
473+
'order' => 'title'
474+
));
475+
$this->assertEquals('/posts/index/1?page=1&dir=desc&order=title', $result);
476+
}
477+
457478
/**
458479
* test persistParams ability to persist parameters from $params and remove params.
459480
*

0 commit comments

Comments
 (0)