From eb9fe07472bb35c98b0186e94776a9d9e7330387 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 18 Dec 2010 16:44:21 -0500 Subject: [PATCH] Adding query string generation into CakeRoute. This removes one more task from Router. Tests added Adding constants for the named param and querystring param sigils. --- cake/libs/route/cake_route.php | 53 ++++++++++++++----- .../cases/libs/route/cake_route.test.php | 24 +++++++++ 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/cake/libs/route/cake_route.php b/cake/libs/route/cake_route.php index bbe70bc63..7e4af3384 100644 --- a/cake/libs/route/cake_route.php +++ b/cake/libs/route/cake_route.php @@ -73,6 +73,16 @@ class CakeRoute { */ protected $_compiledRoute = null; +/** + * Constant for the sigil that indicates a route param is a named parameter. + */ + const SIGIL_NAMED = ':'; + +/** + * Constant for the sigil that indicates a route param is a query string parameter. + */ + const SIGIL_QUERYSTRING = '?'; + /** * HTTP header shortcut map. Used for evaluating header-based route expressions. * @@ -274,22 +284,27 @@ class CakeRoute { return false; } - $named = $pass = $diff = array(); + $named = $pass = $_query = array(); foreach ($url as $key => $value) { // pull out named params so comparisons later on are faster. - if ($key[0] === ':' && ($value !== false && $value !== null)) { + if ($key[0] === CakeRoute::SIGIL_NAMED && ($value !== false && $value !== null)) { $named[substr($key, 1)] = $value; unset($url[$key]); continue; } + + // pull out querystring params + if ($key[0] === CakeRoute::SIGIL_QUERYSTRING && ($value !== false && $value !== null)) { + $_query[substr($key, 1)] = $value; + unset($url[$key]); + continue; + } // keys that exist in the defaults and have different values cause match failures. $keyExists = array_key_exists($key, $defaults); if ($keyExists && $defaults[$key] != $value) { return false; - $diff[$key] = $value; - continue; } // If the key is a routed key, its not different yet. @@ -310,17 +325,11 @@ class CakeRoute { // keys that don't exist are different. if (!$keyExists && !empty($value)) { return false; - $diff[$key] = $value; } } //if a not a greedy route, no extra params are allowed. - if (!$this->_greedy && ( (!empty($pass) || !empty($named)) || array_diff_key($diff, $keyNames) != array()) ) { - return false; - } - - //still some left over parameters that weren't named or passed args, bail. - if (!empty($diff)) { + if (!$this->_greedy && (!empty($pass) || !empty($named))) { return false; } @@ -332,7 +341,7 @@ class CakeRoute { } } } - return $this->_writeUrl(array_merge($url, compact('pass', 'named'))); + return $this->_writeUrl(array_merge($url, compact('pass', 'named', '_query'))); } /** @@ -385,7 +394,27 @@ class CakeRoute { if (strpos($this->template, '*')) { $out = str_replace('*', $params['pass'], $out); } + if (!empty($params['_query'])) { + $out .= $this->queryString($params['_query']); + } $out = str_replace('//', '/', $out); return $out; } + +/** + * Generates a well-formed querystring from $q + * + * Will compose an array or nested array into a proper querystring. + * + * @param mixed $q An array of parameters to compose into a query string. + * @param bool $escape Whether or not to use escaped & + * @return string + */ + public function queryString($q, $escape = false) { + $join = '&'; + if ($escape === true) { + $join = '&'; + } + return '?' . http_build_query($q, null, $join); + } } \ No newline at end of file diff --git a/cake/tests/cases/libs/route/cake_route.test.php b/cake/tests/cases/libs/route/cake_route.test.php index 279e305f1..5e6860fba 100644 --- a/cake/tests/cases/libs/route/cake_route.test.php +++ b/cake/tests/cases/libs/route/cake_route.test.php @@ -472,4 +472,28 @@ class CakeRouteTestCase extends CakeTestCase { $result = $route->parse('/blog/foobar'); $this->assertFalse($result); } + +/** + * test sigil based query string params + * + * @return void + */ + function testQueryStringParams() { + $route = new CakeRoute('/:controller/:action/*'); + $result = $route->match(array('controller' => 'posts', 'action' => 'index', '?test' => 'value')); + $expected = '/posts/index/?test=value'; + $this->assertEquals($expected, $result); + + $result = $route->match(array( + 'controller' => 'posts', 'action' => 'index', '?test' => array(1, 2, 3) + )); + $expected = '/posts/index/?test%5B0%5D=1&test%5B1%5D=2&test%5B2%5D=3'; + $this->assertEquals($expected, $result); + + $result = $route->match(array( + 'controller' => 'posts', 'action' => 'index', '?test' => 'value', '?other' => 'value' + )); + $expected = '/posts/index/?test=value&other=value'; + $this->assertEquals($expected, $result); + } } \ No newline at end of file