Merge branch 'no-shortcuts' into 1.3

This commit is contained in:
Mark Story 2010-04-08 00:03:58 -04:00
commit 0427fe9777
4 changed files with 206 additions and 133 deletions

View file

@ -366,29 +366,6 @@ class Dispatcher extends Object {
} }
return $base . $file; return $base . $file;
} }
/**
* Restructure params in case we're serving a plugin.
*
* @param array $params Array on where to re-set 'controller', 'action', and 'pass' indexes
* @param boolean $reverse If true all the params are shifted one forward, so plugin becomes
* controller, controller becomes action etc. If false, plugin is made equal to controller
* @return array Restructured array
* @access protected
*/
function _restructureParams($params, $reverse = false) {
if ($reverse === true) {
extract(Router::getArgs($params['action']));
$params = array_merge($params, array(
'controller'=> $params['plugin'],
'action'=> $params['controller'],
'pass' => array_merge($pass, $params['pass']),
'named' => array_merge($named, $params['named'])
));
} else {
$params['plugin'] = $params['controller'];
}
return $params;
}
/** /**
* Get controller to use, either plugin controller or application controller * Get controller to use, either plugin controller or application controller
@ -398,32 +375,14 @@ class Dispatcher extends Object {
* @access private * @access private
*/ */
function &__getController() { function &__getController() {
$original = $params = $this->params;
$controller = false; $controller = false;
$ctrlClass = $this->__loadController($params); $ctrlClass = $this->__loadController($this->params);
if (!$ctrlClass) { if (!$ctrlClass) {
if (!isset($params['plugin'])) { return $controller;
$params = $this->_restructureParams($params);
} else {
$params = $this->_restructureParams($params, true);
}
$ctrlClass = $this->__loadController($params);
if (!$ctrlClass) {
$this->params = $original;
return $controller;
}
} }
$name = $ctrlClass; $name = $ctrlClass;
$ctrlClass .= 'Controller'; $ctrlClass .= 'Controller';
if (class_exists($ctrlClass)) { if (class_exists($ctrlClass)) {
if (
empty($params['plugin']) &&
strtolower(get_parent_class($ctrlClass)) === strtolower($name . 'AppController')
) {
$params = $this->_restructureParams($params);
}
$this->params = $params;
$controller =& new $ctrlClass(); $controller =& new $ctrlClass();
} }
return $controller; return $controller;

View file

@ -540,17 +540,29 @@ class Router {
* Connects the default, built-in routes, including prefix and plugin routes. The following routes are created * Connects the default, built-in routes, including prefix and plugin routes. The following routes are created
* in the order below: * in the order below:
* *
* For each of the Routing.prefixes the following routes are created. Routes containing `:plugin` are only
* created when your application has one or more plugins.
*
* - `/:prefix/:plugin` a plugin shortcut route.
* - `/:prefix/:plugin/:action/*` a plugin shortcut route.
* - `/:prefix/:plugin/:controller` * - `/:prefix/:plugin/:controller`
* - `/:prefix/:plugin/:controller/:action/*` * - `/:prefix/:plugin/:controller/:action/*`
* - `/:prefix/:controller` * - `/:prefix/:controller`
* - `/:prefix/:controller/:action/*` * - `/:prefix/:controller/:action/*`
*
* If plugins are found in your application the following routes are created:
*
* - `/:plugin` a plugin shortcut route.
* - `/:plugin/:action/*` a plugin shortcut route.
* - `/:plugin/:controller` * - `/:plugin/:controller`
* - `/:plugin/:controller/:action/*` * - `/:plugin/:controller/:action/*`
*
* And lastly the following catch-all routes are connected.
*
* - `/:controller' * - `/:controller'
* - `/:controller/:action/*' * - `/:controller/:action/*'
* *
* A prefix route is generated for each Routing.prefixes declared in core.php. You can disable the * You can disable the connection of default routes with Router::defaults().
* connection of default routes with Router::defaults().
* *
* @return void * @return void
* @access private * @access private
@ -560,7 +572,8 @@ class Router {
foreach ($plugins as $key => $value) { foreach ($plugins as $key => $value) {
$plugins[$key] = Inflector::underscore($value); $plugins[$key] = Inflector::underscore($value);
} }
$match = array('plugin' => implode('|', $plugins)); $pluginPattern = implode('|', $plugins);
$match = array('plugin' => $pluginPattern);
foreach ($this->__prefixes as $prefix) { foreach ($this->__prefixes as $prefix) {
$params = array('prefix' => $prefix, $prefix => true); $params = array('prefix' => $prefix, $prefix => true);
@ -568,6 +581,8 @@ class Router {
$this->connect("/{$prefix}/:plugin/:controller", $indexParams, $match); $this->connect("/{$prefix}/:plugin/:controller", $indexParams, $match);
$this->connect("/{$prefix}/:plugin/:controller/:action/*", $params, $match); $this->connect("/{$prefix}/:plugin/:controller/:action/*", $params, $match);
} }
$shortParams = array('routeClass' => 'PluginShortRoute', 'plugin' => $pluginPattern);
$this->connect('/:plugin', array('action' => 'index'), $shortParams);
$this->connect('/:plugin/:controller', array('action' => 'index'), $match); $this->connect('/:plugin/:controller', array('action' => 'index'), $match);
$this->connect('/:plugin/:controller/:action/*', array(), $match); $this->connect('/:plugin/:controller/:action/*', array(), $match);
} }
@ -907,7 +922,7 @@ class Router {
$urlOut = array_filter(array($url['controller'], $url['action'])); $urlOut = array_filter(array($url['controller'], $url['action']));
if (isset($url['plugin']) && $url['plugin'] != $url['controller']) { if (isset($url['plugin'])) {
array_unshift($urlOut, $url['plugin']); array_unshift($urlOut, $url['plugin']);
} }
@ -1411,6 +1426,7 @@ class CakeRoute {
$route['pass'] = $route['named'] = array(); $route['pass'] = $route['named'] = array();
$route += $this->defaults; $route += $this->defaults;
//move numerically indexed elements from the defaults into pass.
foreach ($route as $key => $value) { foreach ($route as $key => $value) {
if (is_integer($key)) { if (is_integer($key)) {
$route['pass'][] = $value; $route['pass'][] = $value;
@ -1531,10 +1547,6 @@ class CakeRoute {
* @access protected * @access protected
*/ */
function _writeUrl($params) { function _writeUrl($params) {
if (isset($params['plugin'], $params['controller']) && $params['plugin'] === $params['controller']) {
unset($params['controller']);
}
if (isset($params['prefix'], $params['action'])) { if (isset($params['prefix'], $params['action'])) {
$params['action'] = str_replace($params['prefix'] . '_', '', $params['action']); $params['action'] = str_replace($params['prefix'] . '_', '', $params['action']);
unset($params['prefix']); unset($params['prefix']);
@ -1576,4 +1588,46 @@ class CakeRoute {
return $out; return $out;
} }
} }
/**
* Plugin short route, that copies the plugin param to the controller parameters
* It is used for supporting /:plugin routes.
*
* @package cake.libs
*/
class PluginShortRoute extends CakeRoute {
/**
* Parses a string url into an array. If a plugin key is found, it will be copied to the
* controller parameter
*
* @param string $url The url to parse
* @return mixed false on failure, or an array of request parameters
*/
function parse($url) {
$params = parent::parse($url);
if (!$params) {
return false;
}
$params['controller'] = $params['plugin'];
return $params;
}
/**
* Reverse route plugin shortcut urls. If the plugin and controller
* are not the same the match is an auto fail.
*
* @param array $url Array of parameters to convert to a string.
* @return mixed either false or a string url.
*/
function match($url) {
if (isset($url['controller']) && isset($url['plugin']) && $url['plugin'] != $url['controller']) {
return false;
}
$this->defaults['controller'] = $url['controller'];
$result = parent::match($url);
unset($this->defaults['controller']);
return $result;
}
}
?> ?>

View file

@ -340,6 +340,14 @@ class ArticlesTestController extends ArticlesTestAppController {
function admin_index() { function admin_index() {
return true; return true;
} }
/**
* fake index method.
*
* @return void
*/
function index() {
return true;
}
} }
/** /**
@ -1397,11 +1405,9 @@ class DispatcherTest extends CakeTestCase {
$Router =& Router::getInstance(); $Router =& Router::getInstance();
$controller = $Dispatcher->dispatch($url, array('return' => 1)); $controller = $Dispatcher->dispatch($url, array('return' => 1));
$expected = 'TestDispatchPages'; $this->assertEqual($controller->name, 'TestDispatchPages');
$this->assertEqual($expected, $controller->name);
$expected = array('param' => 'value', 'param2' => 'value2'); $this->assertIdentical($controller->passedArgs, array('param' => 'value', 'param2' => 'value2'));
$this->assertIdentical($expected, $controller->passedArgs);
$this->assertTrue($controller->params['admin']); $this->assertTrue($controller->params['admin']);
$expected = '/cake/repo/branches/1.2.x.x/index.php/admin/test_dispatch_pages/index/param:value/param2:value2'; $expected = '/cake/repo/branches/1.2.x.x/index.php/admin/test_dispatch_pages/index/param:value/param2:value2';
@ -1423,7 +1429,10 @@ class DispatcherTest extends CakeTestCase {
Router::reload(); Router::reload();
$Dispatcher =& new TestDispatcher(); $Dispatcher =& new TestDispatcher();
Router::connect('/my_plugin/:controller/*', array('plugin'=>'my_plugin', 'controller'=>'pages', 'action'=>'display')); Router::connect(
'/my_plugin/:controller/*',
array('plugin' => 'my_plugin', 'controller' => 'pages', 'action' => 'display')
);
$Dispatcher->base = false; $Dispatcher->base = false;
$url = 'my_plugin/some_pages/home/param:value/param2:value2'; $url = 'my_plugin/some_pages/home/param:value/param2:value2';
@ -1441,17 +1450,10 @@ class DispatcherTest extends CakeTestCase {
$this->assertEqual($expected, $result); $this->assertEqual($expected, $result);
$expected = 'my_plugin'; $this->assertIdentical($controller->plugin, 'my_plugin');
$this->assertIdentical($expected, $controller->plugin); $this->assertIdentical($controller->name, 'SomePages');
$this->assertIdentical($controller->params['controller'], 'some_pages');
$expected = 'SomePages'; $this->assertIdentical($controller->passedArgs, array('0' => 'home', 'param'=>'value', 'param2'=>'value2'));
$this->assertIdentical($expected, $controller->name);
$expected = 'some_pages';
$this->assertIdentical($expected, $controller->params['controller']);
$expected = array('0' => 'home', 'param'=>'value', 'param2'=>'value2');
$this->assertIdentical($expected, $controller->passedArgs);
$expected = '/cake/repo/branches/1.2.x.x/my_plugin/some_pages/home/param:value/param2:value2'; $expected = '/cake/repo/branches/1.2.x.x/my_plugin/some_pages/home/param:value/param2:value2';
$this->assertIdentical($expected, $controller->here); $this->assertIdentical($expected, $controller->here);
@ -1472,24 +1474,20 @@ class DispatcherTest extends CakeTestCase {
Router::reload(); Router::reload();
$Dispatcher =& new TestDispatcher(); $Dispatcher =& new TestDispatcher();
Router::connect('/my_plugin/:controller/:action/*', array('plugin'=>'my_plugin', 'controller'=>'pages', 'action'=>'display')); Router::connect(
'/my_plugin/:controller/:action/*',
array('plugin' => 'my_plugin', 'controller' => 'pages', 'action' => 'display')
);
$Dispatcher->base = false; $Dispatcher->base = false;
$url = 'my_plugin/other_pages/index/param:value/param2:value2'; $url = 'my_plugin/other_pages/index/param:value/param2:value2';
$controller = $Dispatcher->dispatch($url, array('return' => 1)); $controller = $Dispatcher->dispatch($url, array('return' => 1));
$expected = 'my_plugin'; $this->assertIdentical($controller->plugin, 'my_plugin');
$this->assertIdentical($expected, $controller->plugin); $this->assertIdentical($controller->name, 'OtherPages');
$this->assertIdentical($controller->action, 'index');
$expected = 'OtherPages'; $this->assertIdentical($controller->passedArgs, array('param' => 'value', 'param2' => 'value2'));
$this->assertIdentical($expected, $controller->name);
$expected = 'index';
$this->assertIdentical($expected, $controller->action);
$expected = array('param' => 'value', 'param2' => 'value2');
$this->assertIdentical($expected, $controller->passedArgs);
$expected = '/cake/repo/branches/1.2.x.x/my_plugin/other_pages/index/param:value/param2:value2'; $expected = '/cake/repo/branches/1.2.x.x/my_plugin/other_pages/index/param:value/param2:value2';
$this->assertIdentical($expected, $controller->here); $this->assertIdentical($expected, $controller->here);
@ -1508,6 +1506,13 @@ class DispatcherTest extends CakeTestCase {
$_POST = array(); $_POST = array();
$_SERVER['PHP_SELF'] = '/cake/repo/branches/1.2.x.x/index.php'; $_SERVER['PHP_SELF'] = '/cake/repo/branches/1.2.x.x/index.php';
$plugins = App::objects('plugin');
$plugins[] = 'MyPlugin';
$plugins[] = 'ArticlesTest';
$app = App::getInstance();
$app->__objects['plugin'] = $plugins;
Router::reload(); Router::reload();
$Dispatcher =& new TestDispatcher(); $Dispatcher =& new TestDispatcher();
$Dispatcher->base = false; $Dispatcher->base = false;
@ -1526,7 +1531,7 @@ class DispatcherTest extends CakeTestCase {
$Dispatcher =& new TestDispatcher(); $Dispatcher =& new TestDispatcher();
$Dispatcher->base = false; $Dispatcher->base = false;
/* Simulates the Route for a real plugin, installed in APP/plugins */ // Simulates the Route for a real plugin, installed in APP/plugins
Router::connect('/my_plugin/:controller/:action/*', array('plugin' => 'my_plugin')); Router::connect('/my_plugin/:controller/:action/*', array('plugin' => 'my_plugin'));
$plugin = 'MyPlugin'; $plugin = 'MyPlugin';
@ -1534,15 +1539,9 @@ class DispatcherTest extends CakeTestCase {
$url = $pluginUrl; $url = $pluginUrl;
$controller = $Dispatcher->dispatch($url, array('return' => 1)); $controller = $Dispatcher->dispatch($url, array('return' => 1));
$this->assertIdentical($controller->plugin, 'my_plugin');
$expected = $pluginUrl; $this->assertIdentical($controller->name, 'MyPlugin');
$this->assertIdentical($controller->plugin, $expected); $this->assertIdentical($controller->action, 'index');
$expected = $plugin;
$this->assertIdentical($controller->name, $expected);
$expected = 'index';
$this->assertIdentical($controller->action, $expected);
$expected = $pluginUrl; $expected = $pluginUrl;
$this->assertEqual($controller->params['controller'], $expected); $this->assertEqual($controller->params['controller'], $expected);
@ -1557,37 +1556,40 @@ class DispatcherTest extends CakeTestCase {
$url = 'admin/my_plugin/add/5/param:value/param2:value2'; $url = 'admin/my_plugin/add/5/param:value/param2:value2';
$controller = $Dispatcher->dispatch($url, array('return' => 1)); $controller = $Dispatcher->dispatch($url, array('return' => 1));
$expected = 'my_plugin'; $this->assertEqual($controller->params['plugin'], 'my_plugin');
$this->assertIdentical($controller->plugin, $expected); $this->assertEqual($controller->params['controller'], 'my_plugin');
$this->assertEqual($controller->params['action'], 'admin_add');
$expected = 'MyPlugin'; $this->assertEqual($controller->params['pass'], array(5));
$this->assertIdentical($controller->name, $expected); $this->assertEqual($controller->params['named'], array('param' => 'value', 'param2' => 'value2'));
$this->assertIdentical($controller->plugin, 'my_plugin');
$expected = 'admin_add'; $this->assertIdentical($controller->name, 'MyPlugin');
$this->assertIdentical($controller->action, $expected); $this->assertIdentical($controller->action, 'admin_add');
$expected = array(0 => 5, 'param'=>'value', 'param2'=>'value2'); $expected = array(0 => 5, 'param'=>'value', 'param2'=>'value2');
$this->assertEqual($controller->passedArgs, $expected); $this->assertEqual($controller->passedArgs, $expected);
Configure::write('Routing.prefixes', array('admin'));
Router::reload(); Router::reload();
$Dispatcher =& new TestDispatcher(); $Dispatcher =& new TestDispatcher();
$Dispatcher->base = false; $Dispatcher->base = false;
$controller = $Dispatcher->dispatch('admin/articles_test', array('return' => 1)); $controller = $Dispatcher->dispatch('admin/articles_test', array('return' => 1));
$this->assertIdentical($controller->plugin, 'articles_test');
$expected = 'articles_test'; $this->assertIdentical($controller->name, 'ArticlesTest');
$this->assertIdentical($controller->plugin, $expected); $this->assertIdentical($controller->action, 'admin_index');
$expected = 'ArticlesTest';
$this->assertIdentical($controller->name, $expected);
$expected = 'admin_index';
$this->assertIdentical($controller->action, $expected);
$expected = array( $expected = array(
'pass'=> array(), 'named' => array(), 'controller' => 'articles_test', 'plugin' => 'articles_test', 'action' => 'admin_index', 'pass'=> array(),
'prefix' => 'admin', 'admin' => true, 'form' => array(), 'url' => array('url' => 'admin/articles_test'), 'return' => 1 'named' => array(),
'controller' => 'articles_test',
'plugin' => 'articles_test',
'action' => 'admin_index',
'prefix' => 'admin',
'admin' => true,
'form' => array(),
'url' => array('url' => 'admin/articles_test'),
'return' => 1
); );
$this->assertEqual($controller->params, $expected); $this->assertEqual($controller->params, $expected);
} }
@ -1602,9 +1604,13 @@ class DispatcherTest extends CakeTestCase {
function testAutomaticPluginDispatchWithShortAccess() { function testAutomaticPluginDispatchWithShortAccess() {
$_POST = array(); $_POST = array();
$_SERVER['PHP_SELF'] = '/cake/repo/branches/1.2.x.x/index.php'; $_SERVER['PHP_SELF'] = '/cake/repo/branches/1.2.x.x/index.php';
$plugins = App::objects('plugin');
$plugins[] = 'MyPlugin';
$app = App::getInstance();
$app->__objects['plugin'] = $plugins;
Router::reload(); Router::reload();
Router::connect('/my_plugin/:controller/:action/*', array('plugin' => 'my_plugin'));
$Dispatcher =& new TestDispatcher(); $Dispatcher =& new TestDispatcher();
$Dispatcher->base = false; $Dispatcher->base = false;
@ -1633,6 +1639,9 @@ class DispatcherTest extends CakeTestCase {
$url = 'my_plugin/add'; $url = 'my_plugin/add';
$controller = $Dispatcher->dispatch($url, array('return' => 1)); $controller = $Dispatcher->dispatch($url, array('return' => 1));
$this->assertFalse(isset($controller->params['pass'][0])); $this->assertFalse(isset($controller->params['pass'][0]));
$this->assertEqual($controller->params['controller'], 'my_plugin');
$this->assertEqual($controller->params['action'], 'add');
$this->assertEqual($controller->params['plugin'], 'my_plugin');
$Dispatcher =& new TestDispatcher(); $Dispatcher =& new TestDispatcher();
$Dispatcher->base = false; $Dispatcher->base = false;

View file

@ -17,7 +17,7 @@
* @since CakePHP(tm) v 1.2.0.4206 * @since CakePHP(tm) v 1.2.0.4206
* @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
*/ */
App::import('Core', array('Router', 'Debugger')); App::import('Core', array('Router'));
if (!defined('FULL_BASE_URL')) { if (!defined('FULL_BASE_URL')) {
define('FULL_BASE_URL', 'http://cakephp.org'); define('FULL_BASE_URL', 'http://cakephp.org');
@ -741,31 +741,10 @@ class RouterTest extends CakeTestCase {
'lang' => 'en', 'lang' => 'en',
'controller' => 'shows', 'action' => 'index', 'page' => '1', 'controller' => 'shows', 'action' => 'index', 'page' => '1',
)); ));
$expected = '/en/shows/page:1'; $expected = '/en/shows/shows/page:1';
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
} }
/**
* test that plugin short cut routes behave properly. Parse and reverse route correctly.
*
* @return void
*/
function testPluginShortcutRoutes() {
$result = Router::url(array('plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index'));
$this->assertEqual($result, '/test_plugin', 'Plugin shortcut index action failed.');
$result = Router::url(array('plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'view', 1));
$this->assertEqual($result, '/test_plugin/view/1', 'Plugin shortcut with passed args failed.');
$result = Router::url(array(
'plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'view',
1, 'sort' => 'title', 'dir' => 'asc'
));
$this->assertEqual(
$result, '/test_plugin/view/1/sort:title/dir:asc', 'Plugin shortcut with passed + named args failed.'
);
}
/** /**
* test that you can leave active plugin routes with plugin = null * test that you can leave active plugin routes with plugin = null
* *
@ -1146,7 +1125,7 @@ class RouterTest extends CakeTestCase {
Router::parse('/'); Router::parse('/');
$result = Router::url(array('plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index')); $result = Router::url(array('plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index'));
$expected = '/admin/test_plugin'; $expected = '/admin/test_plugin/test_plugin';
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
Router::reload(); Router::reload();
@ -1964,6 +1943,7 @@ class RouterTest extends CakeTestCase {
) )
), true); ), true);
App::objects('plugin', null, false); App::objects('plugin', null, false);
Router::reload();
$plugins = App::objects('plugin'); $plugins = App::objects('plugin');
$plugin = Inflector::underscore($plugins[0]); $plugin = Inflector::underscore($plugins[0]);
@ -1976,6 +1956,17 @@ class RouterTest extends CakeTestCase {
'named' => array(), 'pass' => array() 'named' => array(), 'pass' => array()
); );
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
$result = Router::url(array('plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index'));
$this->assertEqual($result, '/test_plugin');
$result = Router::parse('/test_plugin');
$expected = array(
'plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index',
'named' => array(), 'pass' => array()
);
$this->assertEqual($result, $expected, 'Plugin shortcut route broken. %s');
} }
/** /**
@ -2437,4 +2428,64 @@ class CakeRouteTestCase extends CakeTestCase {
} }
} }
/**
* test case for PluginShortRoute
*
* @package cake.tests.libs
*/
class PluginShortRouteTestCase extends CakeTestCase {
/**
* startTest method
*
* @access public
* @return void
*/
function startTest() {
$this->_routing = Configure::read('Routing');
Configure::write('Routing', array('admin' => null, 'prefixes' => array()));
Router::reload();
}
/**
* end the test and reset the environment
*
* @return void
**/
function endTest() {
Configure::write('Routing', $this->_routing);
}
/**
* test the parsing of routes.
*
* @return void
*/
function testParsing() {
$route =& new PluginShortRoute('/:plugin', array('action' => 'index'), array('plugin' => 'foo|bar'));
$result = $route->parse('/foo');
$this->assertEqual($result['plugin'], 'foo');
$this->assertEqual($result['controller'], 'foo');
$this->assertEqual($result['action'], 'index');
$result = $route->parse('/wrong');
$this->assertFalse($result, 'Wrong plugin name matched %s');
}
/**
* test the reverse routing of the plugin shortcut urls.
*
* @return void
*/
function testMatch() {
$route =& new PluginShortRoute('/:plugin', array('action' => 'index'), array('plugin' => 'foo|bar'));
$result = $route->match(array('plugin' => 'foo', 'controller' => 'posts', 'action' => 'index'));
$this->assertFalse($result, 'plugin controller mismatch was converted. %s');
$result = $route->match(array('plugin' => 'foo', 'controller' => 'foo', 'action' => 'index'));
$this->assertEqual($result, '/foo');
}
}
?> ?>