Making RequestHandler able to use the accept header to detect and switch layout/view paths. Fixes #729

This commit is contained in:
mark_story 2010-07-01 12:01:46 -04:00
parent 81d03857d7
commit a8e5e587c6
2 changed files with 57 additions and 19 deletions

View file

@ -121,9 +121,9 @@ class RequestHandlerComponent extends Object {
/**
* Initializes the component, gets a reference to Controller::$parameters, and
* checks to see if a file extension has been parsed by the Router. If yes, the
* corresponding content-type is pushed onto the list of accepted content-types
* as the first item.
* checks to see if a file extension has been parsed by the Router. Or if the
* HTTP_ACCEPT_TYPE is set to a single value that is a supported extension and mapped type.
* If yes, RequestHandler::$ext is set to that value
*
* @param object $controller A reference to the controller
* @param array $settings Array of settings to _set().
@ -131,10 +131,20 @@ class RequestHandlerComponent extends Object {
* @see Router::parseExtensions()
*/
public function initialize(&$controller, $settings = array()) {
$this->request = $controller->request;
if (isset($controller->params['url']['ext'])) {
$this->ext = $controller->params['url']['ext'];
}
$this->request = $controller->request;
if (empty($this->ext)) {
$accepts = $this->request->accepts();
$extensions = Router::extensions();
if (count($accepts) == 1) {
$mapped = $this->mapType($accepts[0]);
if (in_array($mapped, $extensions)) {
$this->ext = $mapped;
}
}
}
$this->_set($settings);
}
@ -144,8 +154,10 @@ class RequestHandlerComponent extends Object {
*
* - 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. For example, if controller/action.xml
* is requested, the view path becomes <i>app/views/controller/xml/action.ctp</i>.
* switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml`
* is requested, the view path becomes `app/views/controller/xml/action.ctp`. Also if
* `controller/action` is requested with `Accept-Type: application/xml` in the headers
* the view path will become `app/views/controller/xml/action.ctp`.
* - If a helper with the same name as the extension exists, it is added to the controller.
* - If the extension is of a type that RequestHandler understands, it will set that
* Content-type in the response header.

View file

@ -202,8 +202,6 @@ class RequestHandlerComponentTest extends CakeTestCase {
*/
function testInitializeCallback() {
$this->assertNull($this->RequestHandler->ext);
$this->_init();
$this->Controller->request->params['url']['ext'] = 'rss';
$this->RequestHandler->initialize($this->Controller);
$this->assertEqual($this->RequestHandler->ext, 'rss');
@ -215,6 +213,45 @@ class RequestHandlerComponentTest extends CakeTestCase {
$this->assertEqual($this->RequestHandler->ajaxLayout, 'test_ajax');
}
/**
* test that a mapped Accept-type header will set $this->ext correctly.
*
* @return void
*/
function testInitializeContentTypeSettingExt() {
$this->assertNull($this->RequestHandler->ext);
$extensions = Router::extensions();
Router::parseExtensions('json');
$this->Controller->request = $this->getMock('CakeRequest');
$this->Controller->request->expects($this->any())->method('accepts')
->will($this->returnValue(array('application/json')));
$this->RequestHandler->initialize($this->Controller);
$this->assertEquals('json', $this->RequestHandler->ext);
call_user_func_array(array('Router', 'parseExtensions'), $extensions);
}
/**
* Test that a type mismatch doesn't incorrectly set the ext
*
* @return void
*/
function testInitializeContentTypeAndExtensionMismatch() {
$this->assertNull($this->RequestHandler->ext);
$extensions = Router::extensions();
Router::parseExtensions('xml');
$this->Controller->request = $this->getMock('CakeRequest');
$this->Controller->request->expects($this->any())->method('accepts')
->will($this->returnValue(array('application/json')));
$this->RequestHandler->initialize($this->Controller);
$this->assertNull($this->RequestHandler->ext);
call_user_func_array(array('Router', 'parseExtensions'), $extensions);
}
/**
* testDisabling method
*
@ -414,24 +451,20 @@ class RequestHandlerComponentTest extends CakeTestCase {
$this->assertFalse($result);
$_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
$this->_init();
$this->assertTrue($this->RequestHandler->isXml());
$this->assertFalse($this->RequestHandler->isAtom());
$this->assertFalse($this->RequestHandler->isRSS());
$_SERVER['HTTP_ACCEPT'] = 'application/atom+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
$this->_init();
$this->assertTrue($this->RequestHandler->isAtom());
$this->assertFalse($this->RequestHandler->isRSS());
$_SERVER['HTTP_ACCEPT'] = 'application/rss+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
$this->_init();
$this->assertFalse($this->RequestHandler->isAtom());
$this->assertTrue($this->RequestHandler->isRSS());
$this->assertFalse($this->RequestHandler->isWap());
$_SERVER['HTTP_ACCEPT'] = 'text/vnd.wap.wml,text/html,text/plain,image/png,*/*';
$this->_init();
$this->assertTrue($this->RequestHandler->isWap());
$_SERVER['HTTP_ACCEPT'] = 'application/rss+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
@ -539,12 +572,10 @@ class RequestHandlerComponentTest extends CakeTestCase {
*/
function testAccepts() {
$_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
$this->_init();
$this->assertEqual($this->RequestHandler->accepts(array('js', 'xml', 'html')), 'xml');
$this->assertFalse($this->RequestHandler->accepts(array('gif', 'jpeg', 'foo')));
$_SERVER['HTTP_ACCEPT'] = '*/*;q=0.5';
$this->_init();
$this->assertFalse($this->RequestHandler->accepts('rss'));
}
@ -556,7 +587,6 @@ class RequestHandlerComponentTest extends CakeTestCase {
*/
function testPrefers() {
$_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
$this->_init();
$this->assertNotEqual($this->RequestHandler->prefers(), 'rss');
$this->RequestHandler->ext = 'rss';
$this->assertEqual($this->RequestHandler->prefers(), 'rss');
@ -570,7 +600,6 @@ class RequestHandlerComponentTest extends CakeTestCase {
$this->assertEqual($this->RequestHandler->prefers(), 'xml');
$_SERVER['HTTP_ACCEPT'] = '*/*;q=0.5';
$this->_init();
$this->assertEqual($this->RequestHandler->prefers(), 'html');
$this->assertFalse($this->RequestHandler->prefers('rss'));
}
@ -583,7 +612,6 @@ class RequestHandlerComponentTest extends CakeTestCase {
*/
function testCustomContent() {
$_SERVER['HTTP_ACCEPT'] = 'text/x-mobile,text/html;q=0.9,text/plain;q=0.8,*/*;q=0.5';
$this->_init();
$this->RequestHandler->setContent('mobile', 'text/x-mobile');
$this->RequestHandler->startup($this->Controller);
$this->assertEqual($this->RequestHandler->prefers(), 'mobile');
@ -612,7 +640,6 @@ class RequestHandlerComponentTest extends CakeTestCase {
* @return void
*/
function testAjaxRedirectAsRequestAction() {
$this->_init();
App::build(array(
'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS)
), true);
@ -641,7 +668,6 @@ class RequestHandlerComponentTest extends CakeTestCase {
* @return void
*/
function testAjaxRedirectAsRequestActionStillRenderingLayout() {
$this->_init();
App::build(array(
'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS)
), true);