Merge branch '1.3' of git@github.com:cakephp/cakephp1x into 1.3

* '1.3' of git@github.com:cakephp/cakephp1x:
  Adding PluginShortRoute into default connected routes.  Fixes issues with the framework having built in 404s.
  Implementing PluginShortRoute and some tests for its methods.
  Fixing tests that started failing because of removal of short routes on reverse routing.
  Removing plugin shortcuts entirely.
  Adding additional test for plugin shortcut routes including prefixed shortcut routes.
  Updating doc block for Router::__connectDefaultRoutes()
  Removing Dispatcher::_restructureParams() as it is no longer used.
  Moving expectations inline.
  Fixing tests that should have never worked, and removing additional calls to _restructureParams.  Adding in prefixed plugin shortcuts as they were missing.
  Modifying Dispatcher tests to modify private variables (which is bad, but there is no way to change which plugins Router uses to create patterns).  This allows the removal of two calls to _restructureParams.
  Making PluginShortRoute check that the action exists before attempting to proceed. Updated tests.
  Adding doc blocks to PluginShortRoute.  Adding PluginShortRoute into Router.
  Shrinking number of lines in dispatcher test case.
  Adding PluginShortRoute, and a few test cases.
This commit is contained in:
José Lorenzo Rodríguez 2010-04-08 18:24:24 -04:30
commit 7eb3055720
4 changed files with 206 additions and 133 deletions

View file

@ -366,29 +366,6 @@ class Dispatcher extends Object {
}
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
@ -398,32 +375,14 @@ class Dispatcher extends Object {
* @access private
*/
function &__getController() {
$original = $params = $this->params;
$controller = false;
$ctrlClass = $this->__loadController($params);
$ctrlClass = $this->__loadController($this->params);
if (!$ctrlClass) {
if (!isset($params['plugin'])) {
$params = $this->_restructureParams($params);
} else {
$params = $this->_restructureParams($params, true);
}
$ctrlClass = $this->__loadController($params);
if (!$ctrlClass) {
$this->params = $original;
return $controller;
}
return $controller;
}
$name = $ctrlClass;
$ctrlClass .= 'Controller';
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();
}
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
* 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/:action/*`
* - `/:prefix/:controller`
* - `/: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/:action/*`
*
* And lastly the following catch-all routes are connected.
*
* - `/:controller'
* - `/:controller/:action/*'
*
* A prefix route is generated for each Routing.prefixes declared in core.php. You can disable the
* connection of default routes with Router::defaults().
* You can disable the connection of default routes with Router::defaults().
*
* @return void
* @access private
@ -560,7 +572,8 @@ class Router {
foreach ($plugins as $key => $value) {
$plugins[$key] = Inflector::underscore($value);
}
$match = array('plugin' => implode('|', $plugins));
$pluginPattern = implode('|', $plugins);
$match = array('plugin' => $pluginPattern);
foreach ($this->__prefixes as $prefix) {
$params = array('prefix' => $prefix, $prefix => true);
@ -568,6 +581,8 @@ class Router {
$this->connect("/{$prefix}/:plugin/:controller", $indexParams, $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/:action/*', array(), $match);
}
@ -907,7 +922,7 @@ class Router {
$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']);
}
@ -1411,6 +1426,7 @@ class CakeRoute {
$route['pass'] = $route['named'] = array();
$route += $this->defaults;
//move numerically indexed elements from the defaults into pass.
foreach ($route as $key => $value) {
if (is_integer($key)) {
$route['pass'][] = $value;
@ -1531,10 +1547,6 @@ class CakeRoute {
* @access protected
*/
function _writeUrl($params) {
if (isset($params['plugin'], $params['controller']) && $params['plugin'] === $params['controller']) {
unset($params['controller']);
}
if (isset($params['prefix'], $params['action'])) {
$params['action'] = str_replace($params['prefix'] . '_', '', $params['action']);
unset($params['prefix']);
@ -1576,4 +1588,46 @@ class CakeRoute {
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() {
return true;
}
/**
* fake index method.
*
* @return void
*/
function index() {
return true;
}
}
/**
@ -1397,11 +1405,9 @@ class DispatcherTest extends CakeTestCase {
$Router =& Router::getInstance();
$controller = $Dispatcher->dispatch($url, array('return' => 1));
$expected = 'TestDispatchPages';
$this->assertEqual($expected, $controller->name);
$this->assertEqual($controller->name, 'TestDispatchPages');
$expected = array('param' => 'value', 'param2' => 'value2');
$this->assertIdentical($expected, $controller->passedArgs);
$this->assertIdentical($controller->passedArgs, array('param' => 'value', 'param2' => 'value2'));
$this->assertTrue($controller->params['admin']);
$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();
$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;
$url = 'my_plugin/some_pages/home/param:value/param2:value2';
@ -1441,17 +1450,10 @@ class DispatcherTest extends CakeTestCase {
$this->assertEqual($expected, $result);
$expected = 'my_plugin';
$this->assertIdentical($expected, $controller->plugin);
$expected = 'SomePages';
$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);
$this->assertIdentical($controller->plugin, 'my_plugin');
$this->assertIdentical($controller->name, 'SomePages');
$this->assertIdentical($controller->params['controller'], 'some_pages');
$this->assertIdentical($controller->passedArgs, array('0' => '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);
@ -1472,24 +1474,20 @@ class DispatcherTest extends CakeTestCase {
Router::reload();
$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;
$url = 'my_plugin/other_pages/index/param:value/param2:value2';
$controller = $Dispatcher->dispatch($url, array('return' => 1));
$expected = 'my_plugin';
$this->assertIdentical($expected, $controller->plugin);
$expected = 'OtherPages';
$this->assertIdentical($expected, $controller->name);
$expected = 'index';
$this->assertIdentical($expected, $controller->action);
$expected = array('param' => 'value', 'param2' => 'value2');
$this->assertIdentical($expected, $controller->passedArgs);
$this->assertIdentical($controller->plugin, 'my_plugin');
$this->assertIdentical($controller->name, 'OtherPages');
$this->assertIdentical($controller->action, 'index');
$this->assertIdentical($controller->passedArgs, array('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);
@ -1508,6 +1506,13 @@ class DispatcherTest extends CakeTestCase {
$_POST = array();
$_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();
$Dispatcher =& new TestDispatcher();
$Dispatcher->base = false;
@ -1526,7 +1531,7 @@ class DispatcherTest extends CakeTestCase {
$Dispatcher =& new TestDispatcher();
$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'));
$plugin = 'MyPlugin';
@ -1534,15 +1539,9 @@ class DispatcherTest extends CakeTestCase {
$url = $pluginUrl;
$controller = $Dispatcher->dispatch($url, array('return' => 1));
$expected = $pluginUrl;
$this->assertIdentical($controller->plugin, $expected);
$expected = $plugin;
$this->assertIdentical($controller->name, $expected);
$expected = 'index';
$this->assertIdentical($controller->action, $expected);
$this->assertIdentical($controller->plugin, 'my_plugin');
$this->assertIdentical($controller->name, 'MyPlugin');
$this->assertIdentical($controller->action, 'index');
$expected = $pluginUrl;
$this->assertEqual($controller->params['controller'], $expected);
@ -1557,37 +1556,40 @@ class DispatcherTest extends CakeTestCase {
$url = 'admin/my_plugin/add/5/param:value/param2:value2';
$controller = $Dispatcher->dispatch($url, array('return' => 1));
$expected = 'my_plugin';
$this->assertIdentical($controller->plugin, $expected);
$expected = 'MyPlugin';
$this->assertIdentical($controller->name, $expected);
$expected = 'admin_add';
$this->assertIdentical($controller->action, $expected);
$this->assertEqual($controller->params['plugin'], 'my_plugin');
$this->assertEqual($controller->params['controller'], 'my_plugin');
$this->assertEqual($controller->params['action'], 'admin_add');
$this->assertEqual($controller->params['pass'], array(5));
$this->assertEqual($controller->params['named'], array('param' => 'value', 'param2' => 'value2'));
$this->assertIdentical($controller->plugin, 'my_plugin');
$this->assertIdentical($controller->name, 'MyPlugin');
$this->assertIdentical($controller->action, 'admin_add');
$expected = array(0 => 5, 'param'=>'value', 'param2'=>'value2');
$this->assertEqual($controller->passedArgs, $expected);
Configure::write('Routing.prefixes', array('admin'));
Router::reload();
$Dispatcher =& new TestDispatcher();
$Dispatcher->base = false;
$controller = $Dispatcher->dispatch('admin/articles_test', array('return' => 1));
$expected = 'articles_test';
$this->assertIdentical($controller->plugin, $expected);
$expected = 'ArticlesTest';
$this->assertIdentical($controller->name, $expected);
$expected = 'admin_index';
$this->assertIdentical($controller->action, $expected);
$this->assertIdentical($controller->plugin, 'articles_test');
$this->assertIdentical($controller->name, 'ArticlesTest');
$this->assertIdentical($controller->action, 'admin_index');
$expected = array(
'pass'=> array(), '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
'pass'=> array(),
'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);
}
@ -1602,9 +1604,13 @@ class DispatcherTest extends CakeTestCase {
function testAutomaticPluginDispatchWithShortAccess() {
$_POST = array();
$_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::connect('/my_plugin/:controller/:action/*', array('plugin' => 'my_plugin'));
$Dispatcher =& new TestDispatcher();
$Dispatcher->base = false;
@ -1633,6 +1639,9 @@ class DispatcherTest extends CakeTestCase {
$url = 'my_plugin/add';
$controller = $Dispatcher->dispatch($url, array('return' => 1));
$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->base = false;

View file

@ -17,7 +17,7 @@
* @since CakePHP(tm) v 1.2.0.4206
* @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')) {
define('FULL_BASE_URL', 'http://cakephp.org');
@ -741,31 +741,10 @@ class RouterTest extends CakeTestCase {
'lang' => 'en',
'controller' => 'shows', 'action' => 'index', 'page' => '1',
));
$expected = '/en/shows/page:1';
$expected = '/en/shows/shows/page:1';
$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
*
@ -1146,7 +1125,7 @@ class RouterTest extends CakeTestCase {
Router::parse('/');
$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);
Router::reload();
@ -1964,6 +1943,7 @@ class RouterTest extends CakeTestCase {
)
), true);
App::objects('plugin', null, false);
Router::reload();
$plugins = App::objects('plugin');
$plugin = Inflector::underscore($plugins[0]);
@ -1976,6 +1956,17 @@ class RouterTest extends CakeTestCase {
'named' => array(), 'pass' => array()
);
$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');
}
}
?>