Merge branch '2.2-middleware' into 2.2

This commit is contained in:
Jose Lorenzo Rodriguez 2012-04-22 17:17:36 -04:30
commit 8465538800
15 changed files with 993 additions and 321 deletions

View file

@ -122,3 +122,25 @@ Cache::config('default', array('engine' => 'File'));
* CakePlugin::load('DebugKit'); //Loads a single plugin named DebugKit
*
*/
/**
* You can attach event listeners to the request lifecyle as Dispatcher Filter . By Default CakePHP bundles two filters:
*
* - AssetDispatcher filter will serve your asset files (css, images, js, etc) from your themes and plugins
* - CacheDispatcher filter will read the Cache.check configure variable and try to serve cached content generated from controllers
*
* Feel free to remove or add filters as you see fit for your application. A few examples:
*
* Configure::write('Dispatcher.filters', array(
* 'MyCacheFilter', // will use MyCacheFilter class from the Routing/Filter package in your app.
* 'MyPlugin.MyFilter', // will use MyFilter class from the Routing/Filter package in MyPlugin plugin.
* array('callable' => $aFunction, 'on' => 'before', 'priority' => 9), // A valid PHP callback type to be called on beforeDispatch
* array('callable' => $anotherMethod, 'on' => 'after'), // A valid PHP callback type to be called on afterDispatch
*
* ));
*/
Configure::write('Dispatcher.filters', array(
'AssetDispatcher',
'CacheDispatcher'
));

View file

@ -63,3 +63,24 @@ Cache::config('default', array('engine' => 'File'));
* CakePlugin::load('DebugKit'); //Loads a single plugin named DebugKit
*
*/
/**
* You can attach event listeners to the request lifecyle as Dispatcher Filter . By Default CakePHP bundles two filters:
*
* - AssetDispatcher filter will serve your asset files (css, images, js, etc) from your themes and plugins
* - CacheDispatcher filter will read the Cache.check configure variable and try to serve cached content generated from controllers
*
* Feel free to remove or add filters as you see fit for your application. A few examples:
*
* Configure::write('Dispatcher.filters', array(
* 'MyCacheFilter', // will use MyCacheFilter class from the Routing/Filter package in your app.
* 'MyPlugin.MyFilter', // will use MyFilter class from the Routing/Filter package in MyPlugin plugin.
* array('callbale' => $aFunction, 'on' => 'before', 'priority' => 9), // A valid PHP callback type to be called on beforeDispatch
* array('callbale' => $anotherMethod, 'on' => 'after'), // A valid PHP callback type to be called on afterDispatch
*
* ));
*/
Configure::write('Dispatcher.filters', array(
'AssetDispatcher',
'CacheDispatcher'
));

View file

@ -438,6 +438,17 @@ class MissingPluginException extends CakeException {
}
/**
* Exception raised when a Dispatcher filter could not be found
*
* @package Cake.Error
*/
class MissingDispatcherFilterException extends CakeException {
protected $_messageTemplate = 'Dispatcher filter %s could not be found.';
}
/**
* Exception class for AclComponent and Interface implementations.
*

View file

@ -27,6 +27,9 @@ App::uses('Controller', 'Controller');
App::uses('Scaffold', 'Controller');
App::uses('View', 'View');
App::uses('Debugger', 'Utility');
App::uses('CakeEvent', 'Event');
App::uses('CakeEventManager', 'Event');
App::uses('CakeEventListener', 'Event');
/**
* Dispatcher converts Requests into controller actions. It uses the dispatched Request
@ -35,7 +38,14 @@ App::uses('Debugger', 'Utility');
*
* @package Cake.Routing
*/
class Dispatcher {
class Dispatcher implements CakeEventListener {
/**
* Event manager, used to handle dispatcher filters
*
* @var CakeEventMaanger
**/
protected $_eventManager;
/**
* Constructor.
@ -48,6 +58,65 @@ class Dispatcher {
}
}
/**
* Returns the CakeEventManager instance or creates one if none was
* creted. Attaches the default listeners and filters
*
* @return CakeEventmanger
**/
public function getEventManager() {
if (!$this->_eventManager) {
$this->_eventManager = new CakeEventManager();
$this->_eventManager->attach($this);
$this->_attachFilters($this->_eventManager);
}
return $this->_eventManager;
}
/**
* Returns the list of events this object listents to.
*
* @return array
**/
public function implementedEvents() {
return array('Dispatcher.beforeDispatch' => 'parseParams');
}
/**
* Attaches all event listeners for this dispatcher instance. Loads the
* dispatcher filters from the configured locations.
*
* @param CakeEventManager $manager
* @return void
**/
protected function _attachFilters($manager) {
$filters = Configure::read('Dispatcher.filters');
if (empty($filters)) {
return;
}
foreach ($filters as $filter) {
if (is_string($filter)) {
$filter = array('callable' => $filter);
}
if (is_string($filter['callable'])) {
list($plugin, $callable) = pluginSplit($filter['callable'], true);
App::uses($callable, $plugin . 'Routing/Filter');
if (!class_exists($callable)) {
throw new MissingDispatcherFilterException($callable);
}
$manager->attach(new $callable);
} else {
$on = strtolower($filter['on']);
$options = array();
if (isset($filter['priority'])) {
$options = array('priority' => $filter['priority']);
}
$manager->attach($filter['callable'], 'Dispatcher.' . $on . 'Dispatch', $options);
}
}
}
/**
* Dispatches and invokes given Request, handing over control to the involved controller. If the controller is set
* to autoRender, via Controller::$autoRender, then Dispatcher will render the view.
@ -63,16 +132,23 @@ class Dispatcher {
* @param CakeRequest $request Request object to dispatch.
* @param CakeResponse $response Response object to put the results of the dispatch into.
* @param array $additionalParams Settings array ("bare", "return") which is melded with the GET and POST params
* @return boolean Success
* @return string|void if `$request['return']` is set then it returns response body, null otherwise
* @throws MissingControllerException When the controller is missing.
*/
public function dispatch(CakeRequest $request, CakeResponse $response, $additionalParams = array()) {
if ($this->asset($request->url, $response) || $this->cached($request->here())) {
$beforeEvent = new CakeEvent('Dispatcher.beforeDispatch', $this, compact('request', 'response', 'additionalParams'));
$this->getEventManager()->dispatch($beforeEvent);
$request = $beforeEvent->data['request'];
if ($beforeEvent->result instanceof CakeResponse) {
if (isset($request->params['return'])) {
return $response->body();
}
$response->send();
return;
}
Router::setRequestInfo($request);
$request = $this->parseParams($request, $additionalParams);
$controller = $this->_getController($request, $response);
if (!($controller instanceof Controller)) {
@ -82,7 +158,14 @@ class Dispatcher {
));
}
return $this->_invoke($controller, $request, $response);
$response = $this->_invoke($controller, $request, $response);
if (isset($request->params['return'])) {
return $response->body();
}
$afterEvent = new CakeEvent('Dispatcher.afterDispatch', $this, compact('request', 'response'));
$this->getEventManager()->dispatch($afterEvent);
$afterEvent->data['response']->send();
}
/**
@ -93,7 +176,7 @@ class Dispatcher {
* @param Controller $controller Controller to invoke
* @param CakeRequest $request The request object to invoke the controller for.
* @param CakeResponse $response The response object to receive the output
* @return void
* @return CakeResponse te resulting response object
*/
protected function _invoke(Controller $controller, CakeRequest $request, CakeResponse $response) {
$controller->constructClasses();
@ -113,22 +196,18 @@ class Dispatcher {
}
$controller->shutdownProcess();
if (isset($request->params['return'])) {
return $response->body();
}
$response->send();
return $response;
}
/**
* Applies Routing and additionalParameters to the request to be dispatched.
* If Routes have not been loaded they will be loaded, and app/Config/routes.php will be run.
*
* @param CakeRequest $request CakeRequest object to mine for parameter information.
* @param array $additionalParams An array of additional parameters to set to the request.
* Useful when Object::requestAction() is involved
* @return CakeRequest The request object with routing params set.
* @param CakeEvent $event containing the request, response and additional params
* @return void
*/
public function parseParams(CakeRequest $request, $additionalParams = array()) {
public function parseParams($event) {
$request = $event->data['request'];
if (count(Router::$routes) == 0) {
$namedExpressions = Router::getNamedExpressions();
extract($namedExpressions);
@ -138,10 +217,9 @@ class Dispatcher {
$params = Router::parse($request->url);
$request->addParams($params);
if (!empty($additionalParams)) {
$request->addParams($additionalParams);
if (!empty($event->data['additionalParams'])) {
$request->addParams($event->data['additionalParams']);
}
return $request;
}
/**
@ -199,130 +277,4 @@ class Dispatcher {
include APP . 'Config' . DS . 'routes.php';
}
/**
* Outputs cached dispatch view cache
*
* @param string $path Requested URL path with any query string parameters
* @return string|boolean False if is not cached or output
*/
public function cached($path) {
if (Configure::read('Cache.check') === true) {
if ($path == '/') {
$path = 'home';
}
$path = strtolower(Inflector::slug($path));
$filename = CACHE . 'views' . DS . $path . '.php';
if (!file_exists($filename)) {
$filename = CACHE . 'views' . DS . $path . '_index.php';
}
if (file_exists($filename)) {
$controller = null;
$view = new View($controller);
return $view->renderCache($filename, microtime(true));
}
}
return false;
}
/**
* Checks if a requested asset exists and sends it to the browser
*
* @param string $url Requested URL
* @param CakeResponse $response The response object to put the file contents in.
* @return boolean True on success if the asset file was found and sent
*/
public function asset($url, CakeResponse $response) {
if (strpos($url, '..') !== false || strpos($url, '.') === false) {
return false;
}
$filters = Configure::read('Asset.filter');
$isCss = (
strpos($url, 'ccss/') === 0 ||
preg_match('#^(theme/([^/]+)/ccss/)|(([^/]+)(?<!css)/ccss)/#i', $url)
);
$isJs = (
strpos($url, 'cjs/') === 0 ||
preg_match('#^/((theme/[^/]+)/cjs/)|(([^/]+)(?<!js)/cjs)/#i', $url)
);
if (($isCss && empty($filters['css'])) || ($isJs && empty($filters['js']))) {
$response->statusCode(404);
$response->send();
return true;
} elseif ($isCss) {
include WWW_ROOT . DS . $filters['css'];
return true;
} elseif ($isJs) {
include WWW_ROOT . DS . $filters['js'];
return true;
}
$pathSegments = explode('.', $url);
$ext = array_pop($pathSegments);
$parts = explode('/', $url);
$assetFile = null;
if ($parts[0] === 'theme') {
$themeName = $parts[1];
unset($parts[0], $parts[1]);
$fileFragment = urldecode(implode(DS, $parts));
$path = App::themePath($themeName) . 'webroot' . DS;
if (file_exists($path . $fileFragment)) {
$assetFile = $path . $fileFragment;
}
} else {
$plugin = Inflector::camelize($parts[0]);
if (CakePlugin::loaded($plugin)) {
unset($parts[0]);
$fileFragment = urldecode(implode(DS, $parts));
$pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
if (file_exists($pluginWebroot . $fileFragment)) {
$assetFile = $pluginWebroot . $fileFragment;
}
}
}
if ($assetFile !== null) {
$this->_deliverAsset($response, $assetFile, $ext);
return true;
}
return false;
}
/**
* Sends an asset file to the client
*
* @param CakeResponse $response The response object to use.
* @param string $assetFile Path to the asset file in the file system
* @param string $ext The extension of the file to determine its mime type
* @return void
*/
protected function _deliverAsset(CakeResponse $response, $assetFile, $ext) {
ob_start();
$compressionEnabled = Configure::read('Asset.compress') && $response->compress();
if ($response->type($ext) == $ext) {
$contentType = 'application/octet-stream';
$agent = env('HTTP_USER_AGENT');
if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent) || preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
$contentType = 'application/octetstream';
}
$response->type($contentType);
}
if (!$compressionEnabled) {
$response->header('Content-Length', filesize($assetFile));
}
$response->cache(filemtime($assetFile));
$response->send();
ob_clean();
if ($ext === 'css' || $ext === 'js') {
include $assetFile;
} else {
readfile($assetFile);
}
if ($compressionEnabled) {
ob_end_flush();
}
}
}

View file

@ -0,0 +1,85 @@
<?php
/**
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Routing
* @since CakePHP(tm) v 2.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('CakeEventListener', 'Event');
/**
* This abstract class represents a filter to be applied to a dispatcher cycle. It acts as as
* event listener with the ability to alter the request or response as needed before it is handled
* by a controller or after the response body has already been built.
*
* @package Cake.Routing
*/
abstract class DispatcherFilter implements CakeEventListener {
/**
* Default priority for all methods in this filter
*
* @var int
**/
public $priority = 10;
/**
* Returns the list of events this filter listens to.
* Dispatcher notifies 2 different events `Dispatcher.before` and `Dispatcher.after`.
* By default this class will attach `preDispatch` and `postDispatch` method respectively.
*
* Override this method at will to only listen to the events you are interested in.
*
* @return array
**/
public function implementedEvents() {
return array(
'Dispatcher.beforeDispatch' => array('callable' => 'beforeDispatch', 'priority' => $this->priority),
'Dispatcher.afterDispatch' => array('callable' => 'afterDispatch', 'priority' => $this->priority),
);
}
/**
* Method called before the controller is instantiated and called to ser a request.
* If used with default priority, it will be called after the Router has parsed the
* url and set the routing params into the request object.
*
* If a CakeResponse object instance is returned, it will be served at the end of the
* event cycle, not calling any controller as a result. This will also have the effect of
* not calling the after event in the dispatcher.
*
* If false is returned, the event will be stopped and no more listeners will be notified.
* Alternatively you can call `$event->stopPropagation()` to acheive the same result.
*
* @param CakeEvent $event container object having the `request`, `response` and `additionalParams`
* keys in the data property.
* @return CakeResponse|boolean
**/
public function beforeDispatch($event) {
}
/**
* Method called after the controller served a request and generated a response.
* It is posible to alter the response object at this point as it is not sent to the
* client yet.
*
* If false is returned, the event will be stopped and no more listeners will be notified.
* Alternatively you can call `$event->stopPropagation()` to acheive the same result.
*
* @param CakeEvent $event container object having the `request` and `response`
* keys in the data property.
* @return mixed boolean to stop the event dispatching or null to continue
**/
public function afterDispatch($event) {}
}

View file

@ -0,0 +1,159 @@
<?php
/**
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Routing
* @since CakePHP(tm) v 2.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('DispatcherFilter', 'Routing');
/**
* Filters a request and tests whether it is a file in the webroot folder or not and
* serves the file to the client if appropriate.
*
* @package Cake.Routing.Filter
*/
class AssetDispatcher extends DispatcherFilter {
/**
* Default priority for all methods in this filter
* This filter should run before the request gets parsed by router
*
* @var int
**/
public $priority = 9;
/**
* Checks if a requested asset exists and sends it to the browser
*
* @param CakeEvent $event containing the request and response object
* @return CakeResponse if the client is requesting a recognized asset, null otherwise
*/
public function beforeDispatch($event) {
$url = $event->data['request']->url;
$response = $event->data['response'];
if (strpos($url, '..') !== false || strpos($url, '.') === false) {
return;
}
if ($result = $this->_filterAsset($event)) {
$event->stopPropagation();
return $result;
}
$pathSegments = explode('.', $url);
$ext = array_pop($pathSegments);
$parts = explode('/', $url);
$assetFile = null;
if ($parts[0] === 'theme') {
$themeName = $parts[1];
unset($parts[0], $parts[1]);
$fileFragment = urldecode(implode(DS, $parts));
$path = App::themePath($themeName) . 'webroot' . DS;
if (file_exists($path . $fileFragment)) {
$assetFile = $path . $fileFragment;
}
} else {
$plugin = Inflector::camelize($parts[0]);
if (CakePlugin::loaded($plugin)) {
unset($parts[0]);
$fileFragment = urldecode(implode(DS, $parts));
$pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
if (file_exists($pluginWebroot . $fileFragment)) {
$assetFile = $pluginWebroot . $fileFragment;
}
}
}
if ($assetFile !== null) {
$event->stopPropagation();
$response->modified(filemtime($assetFile));
if (!$response->checkNotModified($event->data['request'])) {
$this->_deliverAsset($response, $assetFile, $ext);
}
return $response;
}
}
/**
* Checks if the client is requeting a filtered asset and runs the corresponding
* filter if any is configured
*
* @param CakeEvent $event containing the request and response object
* @return CakeResponse if the client is requesting a recognized asset, null otherwise
*/
protected function _filterAsset($event) {
$url = $event->data['request']->url;
$response = $event->data['response'];
$filters = Configure::read('Asset.filter');
$isCss = (
strpos($url, 'ccss/') === 0 ||
preg_match('#^(theme/([^/]+)/ccss/)|(([^/]+)(?<!css)/ccss)/#i', $url)
);
$isJs = (
strpos($url, 'cjs/') === 0 ||
preg_match('#^/((theme/[^/]+)/cjs/)|(([^/]+)(?<!js)/cjs)/#i', $url)
);
if (($isCss && empty($filters['css'])) || ($isJs && empty($filters['js']))) {
$response->statusCode(404);
return $response;
} elseif ($isCss) {
include WWW_ROOT . DS . $filters['css'];
return $response;
} elseif ($isJs) {
include WWW_ROOT . DS . $filters['js'];
return $response;
}
}
/**
* Sends an asset file to the client
*
* @param CakeResponse $response The response object to use.
* @param string $assetFile Path to the asset file in the file system
* @param string $ext The extension of the file to determine its mime type
* @return void
*/
protected function _deliverAsset(CakeResponse $response, $assetFile, $ext) {
ob_start();
$compressionEnabled = Configure::read('Asset.compress') && $response->compress();
if ($response->type($ext) == $ext) {
$contentType = 'application/octet-stream';
$agent = env('HTTP_USER_AGENT');
if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent) || preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
$contentType = 'application/octetstream';
}
$response->type($contentType);
}
if (!$compressionEnabled) {
$response->header('Content-Length', filesize($assetFile));
}
$response->cache(filemtime($assetFile));
$response->send();
ob_clean();
if ($ext === 'css' || $ext === 'js') {
include $assetFile;
} else {
readfile($assetFile);
}
if ($compressionEnabled) {
ob_end_flush();
}
}
}

View file

@ -0,0 +1,71 @@
<?php
/**
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Routing
* @since CakePHP(tm) v 2.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('DispatcherFilter', 'Routing');
/**
* This filter will check wheter the response was previously cached in the file system
* and served it back to the client if appropriate.
*
* @package Cake.Routing.Filter
*/
class CacheDispatcher extends DispatcherFilter {
/**
* Default priority for all methods in this filter
* This filter should run before the request gets parsed by router
*
* @var int
**/
public $priority = 9;
/**
* Checks whether the response was cached and set the body accordingly.
*
* @param CakeEvent $event containing the request and response object
* @return CakeResponse with cached content if found, null otherwise
*/
public function beforeDispatch($event) {
if (Configure::read('Cache.check') !== true) {
return;
}
$path = $event->data['request']->here();
if ($path == '/') {
$path = 'home';
}
$path = strtolower(Inflector::slug($path));
$filename = CACHE . 'views' . DS . $path . '.php';
if (!file_exists($filename)) {
$filename = CACHE . 'views' . DS . $path . '_index.php';
}
if (file_exists($filename)) {
$controller = null;
$view = new View($controller);
$result = $view->renderCache($filename, microtime(true));
if ($result !== false) {
$event->stopPropagation();
$event->data['response']->body($result);
return $event->data['response'];
}
}
}
}

View file

@ -38,6 +38,7 @@ class AllRoutingTest extends PHPUnit_Framework_TestSuite {
$suite->addTestDirectory($libs . 'Routing');
$suite->addTestDirectory($libs . 'Routing' . DS . 'Route');
$suite->addTestDirectory($libs . 'Routing' . DS . 'Filter');
return $suite;
}
}

View file

@ -44,6 +44,13 @@ class DispatcherMockCakeResponse extends CakeResponse {
*/
class TestDispatcher extends Dispatcher {
/**
* Controller instance, made publicly available for testing
*
* @var Controller
**/
public $controller;
/**
* invoke method
*
@ -52,8 +59,29 @@ class TestDispatcher extends Dispatcher {
* @return void
*/
protected function _invoke(Controller $controller, CakeRequest $request, CakeResponse $response) {
$result = parent::_invoke($controller, $request, $response);
return $controller;
$this->controller = $controller;
return parent::_invoke($controller, $request, $response);
}
/**
* Helper function to test single method attaching for dispatcher filters
*
* @param CakeEvent
* @return void
**/
public function filterTest($event) {
$event->data['request']->params['eventName'] = $event->name();
}
/**
* Helper function to test single method attaching for dispatcher filters
*
* @param CakeEvent
* @return void
**/
public function filterTest2($event) {
$event->stopPropagation();
return $event->data['response'];
}
}
@ -556,6 +584,7 @@ class DispatcherTest extends CakeTestCase {
Configure::write('App', $this->_app);
Configure::write('Cache', $this->_cache);
Configure::write('debug', $this->_debug);
Configure::write('Dispatcher.filters', array());
}
/**
@ -565,14 +594,15 @@ class DispatcherTest extends CakeTestCase {
*/
public function testParseParamsWithoutZerosAndEmptyPost() {
$Dispatcher = new Dispatcher();
$test = $Dispatcher->parseParams(new CakeRequest("/testcontroller/testaction/params1/params2/params3"));
$this->assertSame($test['controller'], 'testcontroller');
$this->assertSame($test['action'], 'testaction');
$this->assertSame($test['pass'][0], 'params1');
$this->assertSame($test['pass'][1], 'params2');
$this->assertSame($test['pass'][2], 'params3');
$this->assertFalse(!empty($test['form']));
$request = new CakeRequest("/testcontroller/testaction/params1/params2/params3");
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $request));
$Dispatcher->parseParams($event);
$this->assertSame($request['controller'], 'testcontroller');
$this->assertSame($request['action'], 'testaction');
$this->assertSame($request['pass'][0], 'params1');
$this->assertSame($request['pass'][1], 'params2');
$this->assertSame($request['pass'][2], 'params3');
$this->assertFalse(!empty($request['form']));
}
/**
@ -583,9 +613,11 @@ class DispatcherTest extends CakeTestCase {
public function testParseParamsReturnsPostedData() {
$_POST['testdata'] = "My Posted Content";
$Dispatcher = new Dispatcher();
$test = $Dispatcher->parseParams(new CakeRequest("/"));
$this->assertEquals("My Posted Content", $test['data']['testdata']);
$request = new CakeRequest("/");
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $request));
$Dispatcher->parseParams($event);
$test = $Dispatcher->parseParams($event);
$this->assertEquals("My Posted Content", $request['data']['testdata']);
}
/**
@ -595,7 +627,10 @@ class DispatcherTest extends CakeTestCase {
*/
public function testParseParamsWithSingleZero() {
$Dispatcher = new Dispatcher();
$test = $Dispatcher->parseParams(new CakeRequest("/testcontroller/testaction/1/0/23"));
$test = new CakeRequest("/testcontroller/testaction/1/0/23");
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $test));
$Dispatcher->parseParams($event);
$this->assertSame($test['controller'], 'testcontroller');
$this->assertSame($test['action'], 'testaction');
$this->assertSame($test['pass'][0], '1');
@ -610,7 +645,10 @@ class DispatcherTest extends CakeTestCase {
*/
public function testParseParamsWithManySingleZeros() {
$Dispatcher = new Dispatcher();
$test = $Dispatcher->parseParams(new CakeRequest("/testcontroller/testaction/0/0/0/0/0/0"));
$test = new CakeRequest("/testcontroller/testaction/0/0/0/0/0/0");
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $test));
$Dispatcher->parseParams($event);
$this->assertRegExp('/\\A(?:0)\\z/', $test['pass'][0]);
$this->assertRegExp('/\\A(?:0)\\z/', $test['pass'][1]);
$this->assertRegExp('/\\A(?:0)\\z/', $test['pass'][2]);
@ -626,8 +664,10 @@ class DispatcherTest extends CakeTestCase {
*/
public function testParseParamsWithManyZerosInEachSectionOfUrl() {
$Dispatcher = new Dispatcher();
$request = new CakeRequest("/testcontroller/testaction/000/0000/00000/000000/000000/0000000");
$test = $Dispatcher->parseParams($request);
$test = new CakeRequest("/testcontroller/testaction/000/0000/00000/000000/000000/0000000");
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $test));
$Dispatcher->parseParams($event);
$this->assertRegExp('/\\A(?:000)\\z/', $test['pass'][0]);
$this->assertRegExp('/\\A(?:0000)\\z/', $test['pass'][1]);
$this->assertRegExp('/\\A(?:00000)\\z/', $test['pass'][2]);
@ -643,9 +683,10 @@ class DispatcherTest extends CakeTestCase {
*/
public function testParseParamsWithMixedOneToManyZerosInEachSectionOfUrl() {
$Dispatcher = new Dispatcher();
$test = new CakeRequest("/testcontroller/testaction/01/0403/04010/000002/000030/0000400");
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $test));
$Dispatcher->parseParams($event);
$request = new CakeRequest("/testcontroller/testaction/01/0403/04010/000002/000030/0000400");
$test = $Dispatcher->parseParams($request);
$this->assertRegExp('/\\A(?:01)\\z/', $test['pass'][0]);
$this->assertRegExp('/\\A(?:0403)\\z/', $test['pass'][1]);
$this->assertRegExp('/\\A(?:04010)\\z/', $test['pass'][2]);
@ -667,22 +708,25 @@ class DispatcherTest extends CakeTestCase {
$_GET = array('coffee' => 'life', 'sleep' => 'sissies');
$Dispatcher = new Dispatcher();
$uri = new CakeRequest('posts/home/?coffee=life&sleep=sissies');
$result = $Dispatcher->parseParams($uri);
$this->assertRegExp('/posts/', $result['controller']);
$this->assertRegExp('/home/', $result['action']);
$this->assertTrue(isset($result['url']['sleep']));
$this->assertTrue(isset($result['url']['coffee']));
$request = new CakeRequest('posts/home/?coffee=life&sleep=sissies');
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $request));
$Dispatcher->parseParams($event);
$this->assertRegExp('/posts/', $request['controller']);
$this->assertRegExp('/home/', $request['action']);
$this->assertTrue(isset($request['url']['sleep']));
$this->assertTrue(isset($request['url']['coffee']));
$Dispatcher = new Dispatcher();
$uri = new CakeRequest('/?coffee=life&sleep=sissy');
$request = new CakeRequest('/?coffee=life&sleep=sissy');
$result = $Dispatcher->parseParams($uri);
$this->assertRegExp('/pages/', $result['controller']);
$this->assertRegExp('/display/', $result['action']);
$this->assertTrue(isset($result['url']['sleep']));
$this->assertTrue(isset($result['url']['coffee']));
$this->assertEquals('life', $result['url']['coffee']);
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $request));
$Dispatcher->parseParams($event);
$this->assertRegExp('/pages/', $request['controller']);
$this->assertRegExp('/display/', $request['action']);
$this->assertTrue(isset($request['url']['sleep']));
$this->assertTrue(isset($request['url']['coffee']));
$this->assertEquals('life', $request['url']['coffee']);
}
/**
@ -700,7 +744,7 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('some_controller/home/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
}
/**
@ -718,7 +762,7 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('dispatcher_test_interface/index');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
}
/**
@ -736,9 +780,10 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('dispatcher_test_abstract/index');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
}
/**
* testDispatch method
*
@ -753,27 +798,27 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('pages/home/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$expected = 'Pages';
$this->assertEquals($expected, $controller->name);
$this->assertEquals($expected, $Dispatcher->controller->name);
$expected = array('0' => 'home', 'param' => 'value', 'param2' => 'value2');
$this->assertSame($expected, $controller->passedArgs);
$this->assertSame($expected, $Dispatcher->controller->passedArgs);
Configure::write('App.baseUrl','/pages/index.php');
Configure::write('App.baseUrl', '/pages/index.php');
$url = new CakeRequest('pages/home');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$expected = 'Pages';
$this->assertEquals($expected, $controller->name);
$this->assertEquals($expected, $Dispatcher->controller->name);
$url = new CakeRequest('pages/home/');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertNull($controller->plugin);
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertNull($Dispatcher->controller->plugin);
$expected = 'Pages';
$this->assertEquals($expected, $controller->name);
$this->assertEquals($expected, $Dispatcher->controller->name);
unset($Dispatcher);
@ -782,24 +827,24 @@ class DispatcherTest extends CakeTestCase {
Configure::write('App.baseUrl', '/timesheets/index.php');
$url = new CakeRequest('timesheets');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$expected = 'Timesheets';
$this->assertEquals($expected, $controller->name);
$this->assertEquals($expected, $Dispatcher->controller->name);
$url = new CakeRequest('timesheets/');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('Timesheets', $controller->name);
$this->assertEquals('Timesheets', $Dispatcher->controller->name);
$this->assertEquals('/timesheets/index.php', $url->base);
$url = new CakeRequest('test_dispatch_pages/camelCased');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('TestDispatchPages', $controller->name);
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('TestDispatchPages', $Dispatcher->controller->name);
$url = new CakeRequest('test_dispatch_pages/camelCased/something. .');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('something. .', $controller->params['pass'][0], 'Period was chopped off. %s');
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('something. .', $Dispatcher->controller->params['pass'][0], 'Period was chopped off. %s');
}
/**
@ -834,18 +879,18 @@ class DispatcherTest extends CakeTestCase {
$response = $this->getMock('CakeResponse');
Router::reload();
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('TestDispatchPages', $controller->name);
$this->assertEquals('TestDispatchPages', $Dispatcher->controller->name);
$this->assertSame($controller->passedArgs, array('param' => 'value', 'param2' => 'value2'));
$this->assertTrue($controller->params['admin']);
$this->assertSame($Dispatcher->controller->passedArgs, array('param' => 'value', 'param2' => 'value2'));
$this->assertTrue($Dispatcher->controller->params['admin']);
$expected = '/cake/repo/branches/1.2.x.x/index.php/admin/test_dispatch_pages/index/param:value/param2:value2';
$this->assertSame($expected, $controller->here);
$this->assertSame($expected, $Dispatcher->controller->here);
$expected = '/cake/repo/branches/1.2.x.x/index.php';
$this->assertSame($expected, $controller->base);
$this->assertSame($expected, $Dispatcher->controller->base);
}
/**
@ -865,22 +910,23 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('my_plugin/some_pages/home/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$result = $Dispatcher->parseParams($url);
$event = new CakeEvent('DispatcherTest', $Dispatcher, array('request' => $url));
$Dispatcher->parseParams($event);
$expected = array(
'pass' => array('home'),
'named' => array('param' => 'value', 'param2' => 'value2'), 'plugin' => 'my_plugin',
'controller' => 'some_pages', 'action' => 'display'
);
foreach ($expected as $key => $value) {
$this->assertEquals($value, $result[$key], 'Value mismatch ' . $key . ' %');
$this->assertEquals($value, $url[$key], 'Value mismatch ' . $key . ' %');
}
$this->assertSame($controller->plugin, 'MyPlugin');
$this->assertSame($controller->name, 'SomePages');
$this->assertSame($controller->params['controller'], 'some_pages');
$this->assertSame($controller->passedArgs, array('0' => 'home', 'param' => 'value', 'param2' => 'value2'));
$this->assertSame($Dispatcher->controller->plugin, 'MyPlugin');
$this->assertSame($Dispatcher->controller->name, 'SomePages');
$this->assertSame($Dispatcher->controller->params['controller'], 'some_pages');
$this->assertSame($Dispatcher->controller->passedArgs, array('0' => 'home', 'param' => 'value', 'param2' => 'value2'));
}
/**
@ -903,12 +949,12 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('my_plugin/other_pages/index/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertSame($controller->plugin, 'MyPlugin');
$this->assertSame($controller->name, 'OtherPages');
$this->assertSame($controller->action, 'index');
$this->assertSame($controller->passedArgs, array('param' => 'value', 'param2' => 'value2'));
$this->assertSame($Dispatcher->controller->plugin, 'MyPlugin');
$this->assertSame($Dispatcher->controller->name, 'OtherPages');
$this->assertSame($Dispatcher->controller->action, 'index');
$this->assertSame($Dispatcher->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->assertSame($expected, $url->here);
@ -936,12 +982,12 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('my_plugin/my_plugin/add/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertSame($controller->plugin, 'MyPlugin');
$this->assertSame($controller->name, 'MyPlugin');
$this->assertSame($controller->action, 'add');
$this->assertEquals(array('param' => 'value', 'param2' => 'value2'), $controller->params['named']);
$this->assertSame($Dispatcher->controller->plugin, 'MyPlugin');
$this->assertSame($Dispatcher->controller->name, 'MyPlugin');
$this->assertSame($Dispatcher->controller->action, 'add');
$this->assertEquals(array('param' => 'value', 'param2' => 'value2'), $Dispatcher->controller->params['named']);
Router::reload();
require CAKE . 'Config' . DS . 'routes.php';
@ -955,13 +1001,13 @@ class DispatcherTest extends CakeTestCase {
$pluginUrl = Inflector::underscore($plugin);
$url = new CakeRequest($pluginUrl);
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertSame($controller->plugin, 'MyPlugin');
$this->assertSame($controller->name, 'MyPlugin');
$this->assertSame($controller->action, 'index');
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertSame($Dispatcher->controller->plugin, 'MyPlugin');
$this->assertSame($Dispatcher->controller->name, 'MyPlugin');
$this->assertSame($Dispatcher->controller->action, 'index');
$expected = $pluginUrl;
$this->assertEquals($expected, $controller->params['controller']);
$this->assertEquals($expected, $Dispatcher->controller->params['controller']);
Configure::write('Routing.prefixes', array('admin'));
@ -972,19 +1018,19 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('admin/my_plugin/my_plugin/add/5/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('my_plugin', $controller->params['plugin']);
$this->assertEquals('my_plugin', $controller->params['controller']);
$this->assertEquals('admin_add', $controller->params['action']);
$this->assertEquals(array(5), $controller->params['pass']);
$this->assertEquals(array('param' => 'value', 'param2' => 'value2'), $controller->params['named']);
$this->assertSame($controller->plugin, 'MyPlugin');
$this->assertSame($controller->name, 'MyPlugin');
$this->assertSame($controller->action, 'admin_add');
$this->assertEquals('my_plugin', $Dispatcher->controller->params['plugin']);
$this->assertEquals('my_plugin', $Dispatcher->controller->params['controller']);
$this->assertEquals('admin_add', $Dispatcher->controller->params['action']);
$this->assertEquals(array(5), $Dispatcher->controller->params['pass']);
$this->assertEquals(array('param' => 'value', 'param2' => 'value2'), $Dispatcher->controller->params['named']);
$this->assertSame($Dispatcher->controller->plugin, 'MyPlugin');
$this->assertSame($Dispatcher->controller->name, 'MyPlugin');
$this->assertSame($Dispatcher->controller->action, 'admin_add');
$expected = array(0 => 5, 'param' => 'value', 'param2' => 'value2');
$this->assertEquals($expected, $controller->passedArgs);
$this->assertEquals($expected, $Dispatcher->controller->passedArgs);
Configure::write('Routing.prefixes', array('admin'));
CakePlugin::load('ArticlesTest', array('path' => '/fake/path'));
@ -993,10 +1039,10 @@ class DispatcherTest extends CakeTestCase {
$Dispatcher = new TestDispatcher();
$controller = $Dispatcher->dispatch(new CakeRequest('admin/articles_test'), $response, array('return' => 1));
$this->assertSame($controller->plugin, 'ArticlesTest');
$this->assertSame($controller->name, 'ArticlesTest');
$this->assertSame($controller->action, 'admin_index');
$Dispatcher->dispatch(new CakeRequest('admin/articles_test'), $response, array('return' => 1));
$this->assertSame($Dispatcher->controller->plugin, 'ArticlesTest');
$this->assertSame($Dispatcher->controller->name, 'ArticlesTest');
$this->assertSame($Dispatcher->controller->action, 'admin_index');
$expected = array(
'pass' => array(),
@ -1009,7 +1055,7 @@ class DispatcherTest extends CakeTestCase {
'return' => 1
);
foreach ($expected as $key => $value) {
$this->assertEquals($expected[$key], $controller->request[$key], 'Value mismatch ' . $key);
$this->assertEquals($expected[$key], $Dispatcher->controller->request[$key], 'Value mismatch ' . $key);
}
}
@ -1029,11 +1075,11 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('my_plugin/');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('my_plugin', $controller->params['controller']);
$this->assertEquals('my_plugin', $controller->params['plugin']);
$this->assertEquals('index', $controller->params['action']);
$this->assertFalse(isset($controller->params['pass'][0]));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('my_plugin', $Dispatcher->controller->params['controller']);
$this->assertEquals('my_plugin', $Dispatcher->controller->params['plugin']);
$this->assertEquals('index', $Dispatcher->controller->params['action']);
$this->assertFalse(isset($Dispatcher->controller->params['pass'][0]));
}
/**
@ -1058,25 +1104,25 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('test_plugin/');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('test_plugin', $controller->params['controller']);
$this->assertEquals('test_plugin', $controller->params['plugin']);
$this->assertEquals('index', $controller->params['action']);
$this->assertFalse(isset($controller->params['pass'][0]));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('test_plugin', $Dispatcher->controller->params['controller']);
$this->assertEquals('test_plugin', $Dispatcher->controller->params['plugin']);
$this->assertEquals('index', $Dispatcher->controller->params['action']);
$this->assertFalse(isset($Dispatcher->controller->params['pass'][0]));
$url = new CakeRequest('/test_plugin/tests/index');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('tests', $controller->params['controller']);
$this->assertEquals('test_plugin', $controller->params['plugin']);
$this->assertEquals('index', $controller->params['action']);
$this->assertFalse(isset($controller->params['pass'][0]));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('tests', $Dispatcher->controller->params['controller']);
$this->assertEquals('test_plugin', $Dispatcher->controller->params['plugin']);
$this->assertEquals('index', $Dispatcher->controller->params['action']);
$this->assertFalse(isset($Dispatcher->controller->params['pass'][0]));
$url = new CakeRequest('/test_plugin/tests/index/some_param');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('tests', $controller->params['controller']);
$this->assertEquals('test_plugin', $controller->params['plugin']);
$this->assertEquals('index', $controller->params['action']);
$this->assertEquals('some_param', $controller->params['pass'][0]);
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertEquals('tests', $Dispatcher->controller->params['controller']);
$this->assertEquals('test_plugin', $Dispatcher->controller->params['plugin']);
$this->assertEquals('index', $Dispatcher->controller->params['action']);
$this->assertEquals('some_param', $Dispatcher->controller->params['pass'][0]);
App::build();
}
@ -1095,7 +1141,7 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('my_plugin/not_here/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
}
/**
@ -1113,7 +1159,7 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('my_plugin/param:value/param2:value2');
$response = $this->getMock('CakeResponse');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
}
/**
@ -1132,18 +1178,141 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('/test_plugin/tests/index');
$response = $this->getMock('CakeResponse');
$result = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->assertTrue(class_exists('TestsController'));
$this->assertTrue(class_exists('TestPluginAppController'));
$this->assertTrue(class_exists('PluginsComponent'));
$this->assertEquals('tests', $result->params['controller']);
$this->assertEquals('test_plugin', $result->params['plugin']);
$this->assertEquals('index', $result->params['action']);
$this->assertEquals('tests', $Dispatcher->controller->params['controller']);
$this->assertEquals('test_plugin', $Dispatcher->controller->params['plugin']);
$this->assertEquals('index', $Dispatcher->controller->params['action']);
App::build();
}
/**
* Tests that it is possible to attach filter classes to the dispatch cycle
*
* @return void
**/
public function testDispatcherFilterSuscriber() {
App::build(array(
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS),
'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
), App::RESET);
CakePlugin::load('TestPlugin');
Configure::write('Dispatcher.filters', array(
array('callable' => 'TestPlugin.TestDispatcherFilter')
));
$dispatcher = new TestDispatcher();
$request = new CakeRequest('/');
$request->params['altered'] = false;
$response = $this->getMock('CakeResponse', array('send'));
$dispatcher->dispatch($request, $response);
$this->assertTrue($request->params['altered']);
$this->assertEquals(304, $response->statusCode());
Configure::write('Dispatcher.filters', array(
'TestPlugin.Test2DispatcherFilter',
'TestPlugin.TestDispatcherFilter'
));
$dispatcher = new TestDispatcher();
$request = new CakeRequest('/');
$request->params['altered'] = false;
$response = $this->getMock('CakeResponse', array('send'));
$dispatcher->dispatch($request, $response);
$this->assertFalse($request->params['altered']);
$this->assertEquals(500, $response->statusCode());
$this->assertNull($dispatcher->controller);
}
/**
* Tests that attaching an inexistent class as filter will throw an exception
*
* @expectedException MissingDispatcherFilterException
* @return void
**/
public function testDispatcherFilterSuscriberMissing() {
App::build(array(
'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
), App::RESET);
CakePlugin::load('TestPlugin');
Configure::write('Dispatcher.filters', array(
array('callable' => 'TestPlugin.NotAFilter')
));
$dispatcher = new TestDispatcher();
$request = new CakeRequest('/');
$response = $this->getMock('CakeResponse', array('send'));
$dispatcher->dispatch($request, $response);
}
/**
* Tests it is possible to attach single callables as filters
*
* @return void
**/
public function testDispatcherFilterCallable() {
App::build(array(
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
), App::RESET);
$dispatcher = new TestDispatcher();
Configure::write('Dispatcher.filters', array(
array('callable' => array($dispatcher, 'filterTest'), 'on' => 'before')
));
$request = new CakeRequest('/');
$response = $this->getMock('CakeResponse', array('send'));
$dispatcher->dispatch($request, $response);
$this->assertEquals('Dispatcher.beforeDispatch', $request->params['eventName']);
$dispatcher = new TestDispatcher();
Configure::write('Dispatcher.filters', array(
array('callable' => array($dispatcher, 'filterTest'), 'on' => 'after')
));
$request = new CakeRequest('/');
$response = $this->getMock('CakeResponse', array('send'));
$dispatcher->dispatch($request, $response);
$this->assertEquals('Dispatcher.afterDispatch', $request->params['eventName']);
// Test that it is possible to skip the route connection process
$dispatcher = new TestDispatcher();
Configure::write('Dispatcher.filters', array(
array('callable' => array($dispatcher, 'filterTest2'), 'on' => 'before', 'priority' => 1)
));
$request = new CakeRequest('/');
$response = $this->getMock('CakeResponse', array('send'));
$dispatcher->dispatch($request, $response);
$this->assertEmpty($dispatcher->controller);
$this->assertEquals(array('controller' => null, 'action' => null, 'plugin' => null), $request->params);
$dispatcher = new TestDispatcher();
Configure::write('Dispatcher.filters', array(
array('callable' => array($dispatcher, 'filterTest2'), 'on' => 'before', 'priority' => 1)
));
$request = new CakeRequest('/');
$request->params['return'] = true;
$response = $this->getMock('CakeResponse', array('send'));
$response->body('this is a body');
$result = $dispatcher->dispatch($request, $response);
$this->assertEquals('this is a body', $result);
$request = new CakeRequest('/');
$response = $this->getMock('CakeResponse', array('send'));
$response->expects($this->once())->method('send');
$response->body('this is a body');
$result = $dispatcher->dispatch($request, $response);
$this->assertNull($result);
}
/**
* testChangingParamsFromBeforeFilter method
*
@ -1155,23 +1324,23 @@ class DispatcherTest extends CakeTestCase {
$url = new CakeRequest('some_posts/index/param:value/param2:value2');
try {
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$this->fail('No exception.');
} catch (MissingActionException $e) {
$this->assertEquals('Action SomePostsController::view() could not be found.', $e->getMessage());
}
$url = new CakeRequest('some_posts/something_else/param:value/param2:value2');
$controller = $Dispatcher->dispatch($url, $response, array('return' => 1));
$Dispatcher->dispatch($url, $response, array('return' => 1));
$expected = 'SomePosts';
$this->assertEquals($expected, $controller->name);
$this->assertEquals($expected, $Dispatcher->controller->name);
$expected = 'change';
$this->assertEquals($expected, $controller->action);
$this->assertEquals($expected, $Dispatcher->controller->action);
$expected = array('changed');
$this->assertSame($expected, $controller->params['pass']);
$this->assertSame($expected, $Dispatcher->controller->params['pass']);
}
/**
@ -1188,6 +1357,7 @@ class DispatcherTest extends CakeTestCase {
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
));
CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
Configure::write('Dispatcher.filters', array('AssetDispatcher'));
$Dispatcher = new TestDispatcher();
$response = $this->getMock('CakeResponse', array('_sendHeader'));
@ -1208,7 +1378,7 @@ class DispatcherTest extends CakeTestCase {
}
/**
* Data provider for asset()
* Data provider for asset filter
*
* - theme assets.
* - plugin assets.
@ -1306,6 +1476,7 @@ class DispatcherTest extends CakeTestCase {
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
));
CakePlugin::load(array('TestPlugin', 'PluginJs'));
Configure::write('Dispatcher.filters', array('AssetDispatcher'));
$Dispatcher = new TestDispatcher();
$response = $this->getMock('CakeResponse', array('_sendHeader'));
@ -1328,42 +1499,19 @@ class DispatcherTest extends CakeTestCase {
* @return void
*/
public function testMissingAssetProcessor404() {
$response = $this->getMock('CakeResponse', array('_sendHeader'));
$response = $this->getMock('CakeResponse', array('send'));
$Dispatcher = new TestDispatcher();
Configure::write('Asset.filter', array(
'js' => '',
'css' => null
));
Configure::write('Dispatcher.filters', array('AssetDispatcher'));
ob_start();
$this->assertTrue($Dispatcher->asset('ccss/cake.generic.css', $response));
$result = ob_get_clean();
$request = new CakeRequest('ccss/cake.generic.css');
$Dispatcher->dispatch($request, $response);
$this->assertEquals('404', $response->statusCode());
}
/**
* test that asset filters work for theme and plugin assets
*
* @return void
*/
public function testAssetFilterForThemeAndPlugins() {
$Dispatcher = new TestDispatcher();
$response = $this->getMock('CakeResponse', array('_sendHeader'));
Configure::write('Asset.filter', array(
'js' => '',
'css' => ''
));
$this->assertTrue($Dispatcher->asset('theme/test_theme/ccss/cake.generic.css', $response));
$this->assertTrue($Dispatcher->asset('theme/test_theme/cjs/debug_kit.js', $response));
$this->assertTrue($Dispatcher->asset('test_plugin/ccss/cake.generic.css', $response));
$this->assertTrue($Dispatcher->asset('test_plugin/cjs/debug_kit.js', $response));
$this->assertFalse($Dispatcher->asset('css/ccss/debug_kit.css', $response));
$this->assertFalse($Dispatcher->asset('js/cjs/debug_kit.js', $response));
}
/**
* Data provider for cached actions.
@ -1411,15 +1559,17 @@ class DispatcherTest extends CakeTestCase {
$dispatcher = new TestDispatcher();
$request = new CakeRequest($url);
$response = new CakeResponse();
$response = $this->getMock('CakeResponse', array('send'));
ob_start();
$dispatcher->dispatch($request, $response);
$out = ob_get_clean();
$out = $response->body();
ob_start();
$dispatcher->cached($request->here());
$cached = ob_get_clean();
Configure::write('Dispatcher.filters', array('CacheDispatcher'));
$request = new CakeRequest($url);
$response = $this->getMock('CakeResponse', array('send'));
$dispatcher = new TestDispatcher();
$dispatcher->dispatch($request, $response);
$cached = $response->body();
$cached = preg_replace('/<!--+[^<>]+-->/', '', $cached);
@ -1441,16 +1591,20 @@ class DispatcherTest extends CakeTestCase {
$_SERVER['REQUEST_METHOD'] = 'POST';
$dispatcher = new Dispatcher();
$result = $dispatcher->parseParams(new CakeRequest('/posts'));
$request = new CakeRequest('/posts');
$event = new CakeEvent('DispatcherTest', $dispatcher, array('request' => $request));
$dispatcher->parseParams($event);
$expected = array('pass' => array(), 'named' => array(), 'plugin' => null, 'controller' => 'posts', 'action' => 'add', '[method]' => 'POST');
foreach ($expected as $key => $value) {
$this->assertEquals($value, $result[$key], 'Value mismatch for ' . $key . ' %s');
$this->assertEquals($value, $request[$key], 'Value mismatch for ' . $key . ' %s');
}
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT';
$result = $dispatcher->parseParams(new CakeRequest('/posts/5'));
$request = new CakeRequest('/posts/5');
$event = new CakeEvent('DispatcherTest', $dispatcher, array('request' => $request));
$dispatcher->parseParams($event);
$expected = array(
'pass' => array('5'),
'named' => array(),
@ -1461,24 +1615,28 @@ class DispatcherTest extends CakeTestCase {
'[method]' => 'PUT'
);
foreach ($expected as $key => $value) {
$this->assertEquals($value, $result[$key], 'Value mismatch for ' . $key . ' %s');
$this->assertEquals($value, $request[$key], 'Value mismatch for ' . $key . ' %s');
}
unset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
$_SERVER['REQUEST_METHOD'] = 'GET';
$result = $dispatcher->parseParams(new CakeRequest('/posts/5'));
$request = new CakeRequest('/posts/5');
$event = new CakeEvent('DispatcherTest', $dispatcher, array('request' => $request));
$dispatcher->parseParams($event);
$expected = array('pass' => array('5'), 'named' => array(), 'id' => '5', 'plugin' => null, 'controller' => 'posts', 'action' => 'view', '[method]' => 'GET');
foreach ($expected as $key => $value) {
$this->assertEquals($value, $result[$key], 'Value mismatch for ' . $key . ' %s');
$this->assertEquals($value, $request[$key], 'Value mismatch for ' . $key . ' %s');
}
$_POST['_method'] = 'PUT';
$result = $dispatcher->parseParams(new CakeRequest('/posts/5'));
$request = new CakeRequest('/posts/5');
$event = new CakeEvent('DispatcherTest', $dispatcher, array('request' => $request));
$dispatcher->parseParams($event);
$expected = array('pass' => array('5'), 'named' => array(), 'id' => '5', 'plugin' => null, 'controller' => 'posts', 'action' => 'edit', '[method]' => 'PUT');
foreach ($expected as $key => $value) {
$this->assertEquals($value, $result[$key], 'Value mismatch for ' . $key . ' %s');
$this->assertEquals($value, $request[$key], 'Value mismatch for ' . $key . ' %s');
}
$_POST['_method'] = 'POST';
@ -1486,13 +1644,15 @@ class DispatcherTest extends CakeTestCase {
$_POST['extra'] = 'data';
$_SERVER = array();
$result = $dispatcher->parseParams(new CakeRequest('/posts'));
$request = new CakeRequest('/posts');
$event = new CakeEvent('DispatcherTest', $dispatcher, array('request' => $request));
$dispatcher->parseParams($event);
$expected = array(
'pass' => array(), 'named' => array(), 'plugin' => null, 'controller' => 'posts', 'action' => 'add',
'[method]' => 'POST', 'data' => array('extra' => 'data', 'Post' => array('title' => 'New Post')),
);
foreach ($expected as $key => $value) {
$this->assertEquals($value, $result[$key], 'Value mismatch for ' . $key . ' %s');
$this->assertEquals($value, $request[$key], 'Value mismatch for ' . $key . ' %s');
}
unset($_POST['_method']);

View file

@ -0,0 +1,128 @@
<?php
/**
* RouterTest file
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The Open Group Test Suite License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
* @package Cake.Test.Case.Routing.Filter
* @since CakePHP(tm) v 2.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('AssetDispatcher', 'Routing/Filter');
App::uses('CakeEvent', 'Event');
App::uses('CakeResponse', 'Network');
class AssetDispatcherTest extends CakeTestCase {
/**
* tearDown method
*
* @return void
*/
public function tearDown() {
Configure::write('Dispatcher.filters', array());
}
/**
* test that asset filters work for theme and plugin assets
*
* @return void
*/
public function testAssetFilterForThemeAndPlugins() {
$filter = new AssetDispatcher();
$response = $this->getMock('CakeResponse', array('_sendHeader'));
Configure::write('Asset.filter', array(
'js' => '',
'css' => ''
));
App::build(array(
'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
), APP::RESET);
$request = new CakeRequest('theme/test_theme/ccss/cake.generic.css');
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
$this->assertSame($response, $filter->beforeDispatch($event));
$this->assertTrue($event->isStopped());
$request = new CakeRequest('theme/test_theme/cjs/debug_kit.js');
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
$this->assertSame($response, $filter->beforeDispatch($event));
$this->assertTrue($event->isStopped());
$request = new CakeRequest('test_plugin/ccss/cake.generic.css');
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
$this->assertSame($response, $filter->beforeDispatch($event));
$this->assertTrue($event->isStopped());
$request = new CakeRequest('test_plugin/cjs/debug_kit.js');
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
$this->assertSame($response, $filter->beforeDispatch($event));
$this->assertTrue($event->isStopped());
$request = new CakeRequest('css/ccss/debug_kit.css');
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
$this->assertNull($filter->beforeDispatch($event));
$this->assertFalse($event->isStopped());
$request = new CakeRequest('js/cjs/debug_kit.js');
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
$this->assertNull($filter->beforeDispatch($event));
$this->assertFalse($event->isStopped());
}
/**
* Tests that $response->checkNotModified() is called and bypasses
* file dispatching
*
* @return void
**/
public function testNotModified() {
$filter = new AssetDispatcher();
Configure::write('Asset.filter', array(
'js' => '',
'css' => ''
));
App::build(array(
'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
));
$time = filemtime(App::themePath('TestTheme') . 'webroot' . DS . 'img' . DS . 'cake.power.gif');
$time = new DateTime(date('Y-m-d H:i:s', $time), new DateTimeZone('UTC'));
$response = $this->getMock('CakeResponse', array('send', 'checkNotModified'));
$request = new CakeRequest('theme/test_theme/img/cake.power.gif');
$response->expects($this->once())->method('checkNotModified')
->with($request)
->will($this->returnValue(true));
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
ob_start();
$this->assertSame($response, $filter->beforeDispatch($event));
ob_end_clean();
$this->assertEquals(200, $response->statusCode());
$this->assertEquals($time->format('D, j M Y H:i:s') . ' GMT', $response->modified());
$response = $this->getMock('CakeResponse', array('_sendHeader', 'checkNotModified'));
$request = new CakeRequest('theme/test_theme/img/cake.power.gif');
$response->expects($this->once())->method('checkNotModified')
->with($request)
->will($this->returnValue(true));
$response->expects($this->never())->method('send');
$event = new CakeEvent('DispatcherTest', $this, compact('request', 'response'));
$this->assertSame($response, $filter->beforeDispatch($event));
$this->assertEquals($time->format('D, j M Y H:i:s') . ' GMT', $response->modified());
}
}

View file

@ -1083,9 +1083,7 @@ class ViewTest extends CakeTestCase {
$f = fopen($path, 'w+');
fwrite($f, $cacheText);
fclose($f);
ob_start();
$View->renderCache($path, '+1 second');
$result = ob_get_clean();
$result = $View->renderCache($path, '+1 second');
$this->assertRegExp('/^some cacheText/', $result);

View file

@ -0,0 +1,33 @@
<?php
/**
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Test.test_app.Routing.Filter
* @since CakePHP(tm) v 2.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('DispatcherFilter', 'Routing');
class Test2DispatcherFilter extends DispatcherFilter {
public function beforeDispatch($event) {
$event->data['response']->statusCode(500);
$event->stopPropagation();
return $event->data['response'];
}
public function afterDispatch($event) {
$event->data['response']->statusCode(200);
}
}

View file

@ -0,0 +1,31 @@
<?php
/**
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Test.test_app.Routing.Filter
* @since CakePHP(tm) v 2.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('DispatcherFilter', 'Routing');
class TestDispatcherFilter extends DispatcherFilter {
public function beforeDispatch($event) {
$event->data['request']->params['altered'] = true;
}
public function afterDispatch($event) {
$event->data['response']->statusCode(304);
}
}

View file

@ -23,6 +23,7 @@ App::uses('Router', 'Routing');
App::uses('CakeRequest', 'Network');
App::uses('CakeResponse', 'Network');
App::uses('Helper', 'View');
App::uses('CakeEvent', 'Event');
/**
* ControllerTestDispatcher class
@ -242,7 +243,7 @@ abstract class ControllerTestCase extends CakeTestCase {
}
}
$Dispatch->loadRoutes = $this->loadRoutes;
$request = $Dispatch->parseParams($request);
$Dispatch->parseParams(new CakeEvent('ControllerTestCase', $Dispatch, array('request' => $request)));
if (!isset($request->params['controller'])) {
$this->headers = Router::currentRoute()->response->header();
return;

View file

@ -557,8 +557,7 @@ class View extends Object {
header('Content-type: text/xml');
}
$commentLength = strlen('<!--cachetime:' . $match['1'] . '-->');
echo substr($out, $commentLength);
return true;
return substr($out, $commentLength);
}
}
}