From ad75ecea81edfa633124476d8f0f3ab8e5c2484b Mon Sep 17 00:00:00 2001 From: nate Date: Wed, 15 Aug 2007 14:18:39 +0000 Subject: [PATCH] Fixing and refactoring reverse routing, and adding URL generation fixes (Ticket #3034) git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@5523 3807eeeb-6ff5-0310-8944-8be069107fe0 --- cake/libs/router.php | 67 +++++++++---------- cake/tests/cases/libs/router.test.php | 61 +++++++++++++---- .../cases/libs/view/helpers/form.test.php | 8 +++ 3 files changed, 85 insertions(+), 51 deletions(-) diff --git a/cake/libs/router.php b/cake/libs/router.php index 8aa9bac57..98f5c7ab9 100644 --- a/cake/libs/router.php +++ b/cake/libs/router.php @@ -204,7 +204,7 @@ class Router extends Object { $_this->routes[] = $_this->__admin; $_this->__admin = null; } - $default = am(array('plugin' => null, 'controller' => null), $default); + $default = am(array('plugin' => null, 'controller' => null, 'action' => null), $default); if (!empty($default) && empty($default['action'])) { $default['action'] = 'index'; @@ -262,10 +262,6 @@ class Router extends Object { $names = array(); $elements = Set::filter(array_map('trim', explode('/', $route))); - if (!count($elements)) { - return false; - } - foreach ($elements as $element) { $q = null; @@ -422,11 +418,6 @@ class Router extends Object { */ function __connectDefaultRoutes() { $_this =& Router::getInstance(); - $default_route = array( - '/:controller/:action/*', - '/^(?:\/(?:([a-zA-Z0-9_\\-\\.\\;\\:]+)(?:\\/([a-zA-Z0-9_\\-\\.\\;\\:]+)(?:[\\/\\?](.*))?)?))[\\/]*$/', - array('controller', 'action'), array() - ); if (defined('CAKE_ADMIN') && $_this->__admin != null) { $_this->routes[] = $_this->__admin; @@ -444,20 +435,15 @@ class Router extends Object { $_this->connect('/xml/:controller/:action/*', array('webservices' => 'Xml')); $_this->connect('/xmlrpc/:controller/:action/*', array('webservices' => 'XmlRpc')); } - $_this->routes[] = $default_route; - //$_this->connect('/:controller/:action/*'); - //pr($this->routes[count($_this->routes) - 1]); - //pr($default_route); - //die(); + $_this->connect('/:controller/:action/*'); $Inflector =& Inflector::getInstance(); $plugins = array_map(array(&$Inflector, 'underscore'), Configure::listObjects('plugin')); + if(!empty($plugins)) { - array_unshift($_this->routes, array( - "/:plugin/:controller/:action/*", - '/^(?:\/(?:(' . implode('|', $plugins) . ')(?:\\/([a-zA-Z0-9_\\-\\.\\;\\:]+)(?:\\/([a-zA-Z0-9_\\-\\.\\;\\:]+)(?:[\\/\\?](.*))?)?)?))[\/]*$/', - array('plugin', 'controller', 'action'), array() - )); + $_this->connect('/:plugin/:controller/:action/*', array('action' => 'index'), array('plugin' => implode('|', $plugins))); + array_unshift($_this->routes, $_this->routes[count($_this->routes) - 1]); + unset($_this->routes[count($_this->routes) - 1]); } } /** @@ -564,13 +550,11 @@ class Router extends Object { $params = end($_this->__params); } } - $path = array('base' => null); + $path = array('base' => null, 'argSeparator' => ':'); if (!empty($_this->__paths)) { if (isset($this) && !isset($this->params['requested'])) { $path = $_this->__paths[0]; - } elseif (isset($this) && isset($this->params['requested'])) { - $path = end($_this->__paths); } else { $path = end($_this->__paths); } @@ -709,14 +693,14 @@ class Router extends Object { */ function mapRouteElements($route, $url) { $_this =& Router::getInstance(); - $defaults = am(array('plugin' => null, 'controller' => null, 'action' => 'index'), $route[3]); + $defaults = $route[3]; $params = Set::diff($url, $defaults); $routeParams = $route[2]; $pass = array(); foreach ($params as $key => $value) { - if (is_numeric($key)) { - $pass[$key] = $value; + if (is_int($key)) { + $pass[] = $value; unset($params[$key]); } } @@ -727,6 +711,9 @@ class Router extends Object { if (defined('CAKE_ADMIN') && isset($params[CAKE_ADMIN])) { return false; } + if (!empty($params)) { + $required = array_diff(array_keys($defaults), array_keys($url)); + } krsort($defaults); krsort($url); @@ -734,31 +721,36 @@ class Router extends Object { if (empty($params)) { return array(Router::__mapRoute($route, am($url, compact('pass'))), array()); } elseif (!empty($routeParams) && !empty($route[3])) { - $required = array_diff(array_keys($defaults), array_keys($url)); - if (!empty($required)) { return false; } - $filled = array_intersect_key($url, array_combine($routeParams, array_keys($routeParams))); - $keysFilled = array_keys($filled); - sort($routeParams); - sort($keysFilled); - if ($keysFilled != $routeParams) { - return false; + if (isset($_this->testing)) { + pr($defaults); + pr($url); + pr($params); + pr($required); } - if (Set::diff($keysFilled, $routeParams) != array()) { + + foreach ($defaults as $key => $val) { + if ($url[$key] != $val && !in_array($key, $routeParams)) { + return false; + } + } + + $filled = array_intersect_key($url, array_combine($routeParams, array_keys($routeParams))); + + if (array_keys($filled) != $routeParams) { return false; } } else { - $required = array_diff(array_keys($defaults), array_keys($url)); if (empty($required) && $defaults['plugin'] == $url['plugin'] && $defaults['controller'] == $url['controller'] && $defaults['action'] == $url['action']) { return array(Router::__mapRoute($route, am($url, compact('pass'))), $url); } return false; } - if (isset($route[3]['controller']) && !empty($route[3]['controller']) && $url['controller'] != $route[3]['controller']) { + if (!empty($route[3]['controller']) && $url['controller'] != $route[3]['controller']) { return false; } @@ -769,6 +761,7 @@ class Router extends Object { } } } + return array(Router::__mapRoute($route, am($url, compact('pass'))), $url); } /** diff --git a/cake/tests/cases/libs/router.test.php b/cake/tests/cases/libs/router.test.php index 9c2a0a0b2..e85e70e3a 100644 --- a/cake/tests/cases/libs/router.test.php +++ b/cake/tests/cases/libs/router.test.php @@ -39,6 +39,11 @@ if (!defined('CAKE_ADMIN')) { */ class RouterTest extends UnitTestCase { + function RouterTest() { + parent::UnitTestCase(); + $this->startTime = getMicrotime(); + } + function setUp() { $this->router =& Router::getInstance(); //$this->router->reload(); @@ -57,7 +62,7 @@ class RouterTest extends UnitTestCase { $this->assertEqual($this->router->routes[0][1], '/^[\/]*$/'); $this->assertEqual($this->router->routes[0][2], array()); - $this->router->routes = array(); + $this->router->reload(); $this->router->connect('/', array('controller' => 'testing')); $this->assertTrue(is_array($this->router->routes[0][3]) && !empty($this->router->routes[0][3])); $this->assertEqual($this->router->routes[0][3]['controller'], 'testing'); @@ -126,10 +131,11 @@ class RouterTest extends UnitTestCase { } function testUrlGeneration() { + $this->router->reload(); extract($this->router->getNamedExpressions()); - $this->router->connect('/', array('controller'=>'pages', 'action'=>'display', 'home')); - $out = $this->router->url(array('controller'=>'pages', 'action'=>'display', 'home')); + $this->router->connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); + $out = $this->router->url(array('controller' => 'pages', 'action' => 'display', 'home')); $this->assertEqual($out, '/'); $this->router->connect('/pages/*', array('controller' => 'pages', 'action' => 'display')); @@ -219,7 +225,6 @@ class RouterTest extends UnitTestCase { $this->assertEqual($result, $expected); $this->router->reload(); - $this->router->testing = true; $this->router->connect( ':language/galleries', @@ -228,9 +233,9 @@ class RouterTest extends UnitTestCase { ); $this->router->connect( - '/:language/:'. CAKE_ADMIN .'/:controller/:action/*', - array(CAKE_ADMIN => CAKE_ADMIN), - array('language' => '[a-z]{3}', CAKE_ADMIN => CAKE_ADMIN) + '/:language/:admin/:controller/:action/*', + array('admin' => 'admin'), + array('language' => '[a-z]{3}', 'admin' => 'admin') ); $this->router->connect('/:language/:controller/:action/*', @@ -238,14 +243,38 @@ class RouterTest extends UnitTestCase { array('language' => '[a-z]{3}') ); - $result = $this->router->url(array(CAKE_ADMIN => false, 'language' => 'dan', 'action' => 'index', 'controller' => 'galleries')); - $expected = '/dan/galleries'; // Passes + $result = $this->router->url(array('admin' => false, 'language' => 'dan', 'action' => 'index', 'controller' => 'galleries')); + $expected = '/dan/galleries'; $this->assertEqual($result, $expected); - $result = $this->router->url(array(CAKE_ADMIN => false, 'language' => 'eng', 'action' => 'index', 'controller' => 'galleries')); - $expected = '/eng/galleries'; // Fails, actual result: /eng/galleries/index/ + $result = $this->router->url(array('admin' => false, 'language' => 'eng', 'action' => 'index', 'controller' => 'galleries')); + $expected = '/eng/galleries'; + $this->assertEqual($result, $expected); + + $this->router->reload(); + $this->router->connect('/:language/pages', + array( + 'controller' => 'pages', + 'action' => 'index' + ), + array('language' => '[a-z]{3}') + ); + + $this->router->connect('/:language/:controller/:action/*', + array(), + array('language' => '[a-z]{3}') + ); + + $result = $this->router->url(array('language' => 'eng', 'action' => 'index', 'controller' => 'pages')); + $expected = '/eng/pages'; // Passes as expected + $this->assertEqual($result, $expected); + + $result = $this->router->url(array('language' => 'eng', 'controller' => 'pages')); + $this->assertEqual($result, $expected); + + $result = $this->router->url(array('language' => 'eng', 'controller' => 'pages', 'action' => 'add')); + $expected = '/eng/pages/add/'; $this->assertEqual($result, $expected); - unset($this->router->testing); } function testUrlGenerationWithExtensions() { @@ -318,7 +347,7 @@ class RouterTest extends UnitTestCase { $this->router->routes = array(); $result = $this->router->parse('/pages/display/home'); - $expected = array('pass' => array ('home'), 'controller' => 'pages', 'action' => 'display'); + $expected = array('plugin' => null, 'pass' => array('home'), 'controller' => 'pages', 'action' => 'display'); $this->assertEqual($result, $expected); $result = $this->router->parse('pages/display/home/'); @@ -352,7 +381,7 @@ class RouterTest extends UnitTestCase { $this->assertEqual($result, $expected); $result = $this->router->parse('/posts/view/1.rss'); - $expected = array('controller' => 'posts', 'action' => 'view', 'pass' => array('1'), 'url' => array('ext' => 'rss')); + $expected = array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'pass' => array('1'), 'url' => array('ext' => 'rss')); $this->assertEqual($result, $expected); $result = $this->router->parse('/posts/view/1.rss?query=test'); @@ -435,6 +464,10 @@ class RouterTest extends UnitTestCase { $expected = array('pass'=>array('contact'), 'plugin'=> null, 'controller'=>'pages', 'action'=>'display'); $this->assertEqual($result, $expected); } + + function testEnd() { + pr(round(getMicrotime() - $this->startTime, 5)); + } } ?> \ No newline at end of file diff --git a/cake/tests/cases/libs/view/helpers/form.test.php b/cake/tests/cases/libs/view/helpers/form.test.php index d43bb2deb..2657cd9be 100644 --- a/cake/tests/cases/libs/view/helpers/form.test.php +++ b/cake/tests/cases/libs/view/helpers/form.test.php @@ -768,6 +768,14 @@ class FormHelperTest extends CakeTestCase { $result = $this->Form->create('Contact', array('id' => 'TestId')); $this->assertPattern('/id="TestId"/', $result); + + $result = $this->Form->create('User', array('url' => array('action' => 'login'))); + $this->assertPattern('/id="UserAddForm"/', $result); + $this->assertPattern('/action="\/users\/login[\/]"/', $result); + + $result = $this->Form->create('User', array('action' => 'login')); + $this->assertPattern('/id="UserLoginForm"/', $result); + $this->assertPattern('/action="\/users\/login[\/]"/', $result); } function testFormMagicInput() {