Browse Source

Dont special case AJAX in RequestHandlerComponent (much).

Adds a AjaxView view class and an additional default mapping from 'ajax' mim type alias to this class.
This means $RequestHandlerComponent::_defaultConfig['ajaxLayout'] is deprecated. Also added a MIME map for ajax in Response.php.
Updates to related tests.
Minor change to handle htm,html the same in RequestHandler _ext mangling.
Comments.
Sam 12 years ago
parent
commit
b49c32ee33

+ 16 - 21
src/Controller/Component/RequestHandlerComponent.php

@@ -82,15 +82,12 @@ class RequestHandlerComponent extends Component {
  *
  * - `checkHttpCache` - Whether to check for http cache.
  * - `viewClassMap` - Mapping between type and view class.
- * - `ajaxLayout` - The layout that will be switched to for Ajax requests.
- *   See RequestHandler::setAjax()
  *
  * @var array
  */
 	protected $_defaultConfig = [
 		'checkHttpCache' => true,
 		'viewClassMap' => '',
-		'ajaxLayout' => 'ajax'
 	];
 
 /**
@@ -105,13 +102,14 @@ class RequestHandlerComponent extends Component {
 
 /**
  * A mapping between type and viewClass
- * By default only JSON and XML are mapped, use RequestHandlerComponent::viewClassMap()
+ * By default only JSON, XML, and AJAX are mapped. Use RequestHandlerComponent::viewClassMap().
  *
  * @var array
  */
 	protected $_viewClassMap = array(
 		'json' => 'Json',
-		'xml' => 'Xml'
+		'xml' => 'Xml',
+		'ajax' => 'Ajax'
 	);
 
 /**
@@ -130,10 +128,10 @@ class RequestHandlerComponent extends Component {
 	}
 
 /**
- * Checks to see if a file extension has been parsed by the Router, or if the
- * HTTP_ACCEPT_TYPE has matches only one content type with the supported extensions.
- * If there is only one matching type between the supported content types & extensions,
- * and the requested mime-types, RequestHandler::$ext is set to that value.
+ * Checks to see if a specific content type has been requested and sets RequestHandler::$ext
+ * accordingly. Checks the following in order: 1. The '_ext' value parsed by the Router. 2. A specific
+ * AJAX type request indicated by the presence of a header. 3. The Accept header.
+ * With the exception of an ajax type request the type must have been configured in the Router.
  *
  * @param Event $event The initialize event that was fired.
  * @return void
@@ -143,7 +141,10 @@ class RequestHandlerComponent extends Component {
 		if (isset($this->request->params['_ext'])) {
 			$this->ext = $this->request->params['_ext'];
 		}
-		if (empty($this->ext) || $this->ext === 'html') {
+		if(empty($this->ext) && $this->request->is('ajax')) {
+			$this->ext = 'ajax';
+		}
+		if (empty($this->ext) || in_array($this->ext, array('html', 'htm'))) {
 			$this->_setExtension();
 		}
 
@@ -176,7 +177,7 @@ class RequestHandlerComponent extends Component {
 		$accepts = $this->response->mapType($accept);
 		$preferedTypes = current($accepts);
 		if (array_intersect($preferedTypes, array('html', 'xhtml'))) {
-			return null;
+			return;
 		}
 
 		$extensions = Router::extensions();
@@ -193,7 +194,6 @@ class RequestHandlerComponent extends Component {
  * The startup method of the RequestHandler enables several automatic behaviors
  * related to the detection of certain properties of the HTTP request, including:
  *
- * - Disabling layout rendering for Ajax requests (based on the HTTP_X_REQUESTED_WITH header)
  * - If Router::parseExtensions() is enabled, the layout and template type are
  *   switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml`
  *   is requested, the view path becomes `app/View/Controller/xml/action.ctp`. Also if
@@ -221,8 +221,6 @@ class RequestHandlerComponent extends Component {
 
 		if (!empty($this->ext) && $isRecognized) {
 			$this->renderAs($controller, $this->ext);
-		} elseif ($this->request->is('ajax')) {
-			$this->renderAs($controller, 'ajax');
 		} elseif (empty($this->ext) || in_array($this->ext, array('html', 'htm'))) {
 			$this->respondAs('html', array('charset' => Configure::read('App.encoding')));
 		}
@@ -481,7 +479,8 @@ class RequestHandlerComponent extends Component {
 	}
 
 /**
- * Sets the layout and template paths for the content type defined by $type.
+ * Sets either the view class if one exists or the layout and template path of the view.
+ * The names of these are derived from the $type input parameter.
  *
  * ### Usage:
  *
@@ -502,18 +501,14 @@ class RequestHandlerComponent extends Component {
  */
 	public function renderAs(Controller $controller, $type, array $options = array()) {
 		$defaults = array('charset' => 'UTF-8');
+		$view = null;
+		$viewClassMap = $this->viewClassMap();
 
 		if (Configure::read('App.encoding') !== null) {
 			$defaults['charset'] = Configure::read('App.encoding');
 		}
 		$options += $defaults;
 
-		if ($type === 'ajax') {
-			$controller->layout = $this->_config['ajaxLayout'];
-			return $this->respondAs('html', $options);
-		}
-
-		$viewClassMap = $this->viewClassMap();
 		if (array_key_exists($type, $viewClassMap)) {
 			$view = $viewClassMap[$type];
 		} else {

+ 3 - 2
src/Network/Response.php

@@ -78,7 +78,7 @@ class Response {
 	);
 
 /**
- * Holds known mime type mappings
+ * Holds type key to mime type mappings for known mime types.
  *
  * @var array
  */
@@ -300,7 +300,8 @@ class Response {
 		'vcf' => 'text/x-vcard',
 		'vtt' => 'text/vtt',
 		'mkv' => 'video/x-matroska',
-		'pkpass' => 'application/vnd.apple.pkpass'
+		'pkpass' => 'application/vnd.apple.pkpass',
+		'ajax' => 'text/html'
 	);
 
 /**

+ 2 - 2
src/Routing/Route/Route.php

@@ -337,8 +337,8 @@ class Route {
 	}
 
 /**
- * Removes the extension if the $url contains a known extension.
- * If there are no known extensions all extensions are supported.
+ * Removes the extension from $url if it contains a registered extension.
+ * If no registered extension is found, no extension is returned and the url is returned unmodified.
  *
  * @param string $url The url to parse.
  * @return array containing url, extension

+ 52 - 0
src/View/AjaxView.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         2.1.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\View;
+
+use Cake\Controller\Controller;
+use Cake\Core\Configure;
+use Cake\Event\EventManager;
+use Cake\Network\Request;
+use Cake\Network\Response;
+
+/**
+ * A view class that is used for AJAX responses.
+ * Currently only switches the default layout and sets the response type - which just maps to
+ * text/html by default.
+ */
+class AjaxView extends View {
+
+/**
+ *
+ * @var string
+ */
+	public $layout = 'ajax';
+
+/**
+ * Constructor
+ *
+ * @param Request $request
+ * @param Response $response
+ * @param EventManager $eventManager
+ * @param array $viewOptions
+ */
+	public function __construct(Request $request = null, Response $response = null,
+		EventManager $eventManager = null, array $viewOptions = []) {
+		parent::__construct($request, $response, $eventManager, $viewOptions);
+
+		if ($response && $response instanceof Response) {
+			$response->type('ajax');
+		}
+	}
+}

+ 7 - 6
tests/TestCase/Controller/Component/RequestHandlerComponentTest.php

@@ -93,13 +93,11 @@ class RequestHandlerComponentTest extends TestCase {
  */
 	public function testConstructorConfig() {
 		$config = array(
-			'ajaxLayout' => 'test_ajax',
 			'viewClassMap' => array('json' => 'MyPlugin.MyJson')
 		);
 		$controller = $this->getMock('Cake\Controller\Controller');
 		$collection = new ComponentRegistry($controller);
 		$requestHandler = new RequestHandlerComponent($collection, $config);
-		$this->assertEquals('test_ajax', $requestHandler->config('ajaxLayout'));
 		$this->assertEquals(array('json' => 'MyPlugin.MyJson'), $requestHandler->config('viewClassMap'));
 	}
 
@@ -295,7 +293,8 @@ class RequestHandlerComponentTest extends TestCase {
 		$result = $this->RequestHandler->viewClassMap();
 		$expected = array(
 			'json' => 'CustomJson',
-			'xml' => 'Xml'
+			'xml' => 'Xml',
+			'ajax' => 'Ajax'
 		);
 		$this->assertEquals($expected, $result);
 
@@ -303,6 +302,7 @@ class RequestHandlerComponentTest extends TestCase {
 		$expected = array(
 			'json' => 'CustomJson',
 			'xml' => 'Xml',
+			'ajax' => 'Ajax',
 			'xls' => 'Excel.Excel'
 		);
 		$this->assertEquals($expected, $result);
@@ -334,14 +334,15 @@ class RequestHandlerComponentTest extends TestCase {
 	public function testAutoAjaxLayout() {
 		$event = new Event('Controller.startup', $this->Controller);
 		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
+		$this->RequestHandler->initialize($event);
 		$this->RequestHandler->startup($event);
-		$this->assertEquals($this->Controller->layout, $this->RequestHandler->config('ajaxLayout'));
-
+		$this->assertEquals($this->Controller->viewClass, 'Cake\View\AjaxView');
+    
 		$this->_init();
 		$this->Controller->request->params['_ext'] = 'js';
 		$this->RequestHandler->initialize($event);
 		$this->RequestHandler->startup($event);
-		$this->assertNotEquals('ajax', $this->Controller->layout);
+		$this->assertNotEquals($this->Controller->viewClass, 'Cake\View\AjaxView');
 
 		unset($_SERVER['HTTP_X_REQUESTED_WITH']);
 	}