From afb62959effde647c18ac03f0afb4a60de133e01 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 2 Feb 2013 13:25:27 +0530 Subject: [PATCH] Added JSONP support for JsonView --- lib/Cake/Test/Case/View/JsonViewTest.php | 44 ++++++++++++++++++++++-- lib/Cake/View/JsonView.php | 34 ++++++++++++++---- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/View/JsonViewTest.php b/lib/Cake/Test/Case/View/JsonViewTest.php index ed2b04e4e..d87cadb26 100644 --- a/lib/Cake/Test/Case/View/JsonViewTest.php +++ b/lib/Cake/Test/Case/View/JsonViewTest.php @@ -66,6 +66,36 @@ class JsonViewTest extends CakeTestCase { $this->assertSame('application/json', $Response->type()); } +/** + * testJsonpResponse method + * + * @return void + */ + public function testJsonpResponse() { + $Request = new CakeRequest(); + $Response = new CakeResponse(); + $Controller = new Controller($Request, $Response); + $data = array('user' => 'fake', 'list' => array('item1', 'item2')); + $Controller->set(array('data' => $data, '_serialize' => 'data', '_jsonp' => true)); + $View = new JsonView($Controller); + $output = $View->render(false); + + $this->assertSame(json_encode($data), $output); + $this->assertSame('application/json', $Response->type()); + + $View->request->query = array('callback' => 'jfunc'); + $output = $View->render(false); + $expected = 'jfunc(' . json_encode($data) . ')'; + $this->assertSame($expected, $output); + $this->assertSame('application/javascript', $Response->type()); + + $View->request->query = array('jsonCallback' => 'jfunc'); + $View->viewVars['_jsonp'] = 'jsonCallback'; + $output = $View->render(false); + $expected = 'jfunc(' . json_encode($data) . ')'; + $this->assertSame($expected, $output); + } + /** * testRenderWithView method * @@ -95,9 +125,19 @@ class JsonViewTest extends CakeTestCase { $View->helpers = array('Paginator'); $output = $View->render('index'); - $expected = json_encode(array('user' => 'fake', 'list' => array('item1', 'item2'), 'paging' => array('page' => 2))); - $this->assertSame($expected, $output); + $expected = array('user' => 'fake', 'list' => array('item1', 'item2'), 'paging' => array('page' => 2)); + $this->assertSame(json_encode($expected), $output); $this->assertSame('application/json', $Response->type()); + + $View->request->query = array('jsonCallback' => 'jfunc'); + $Controller->set('_jsonp', 'jsonCallback'); + $View = new JsonView($Controller); + $View->helpers = array('Paginator'); + $output = $View->render('index'); + $expected['paging']['?']['jsonCallback'] = 'jfunc'; + $expected = 'jfunc(' . json_encode($expected) . ')'; + $this->assertSame($expected, $output); + $this->assertSame('application/javascript', $Response->type()); } } diff --git a/lib/Cake/View/JsonView.php b/lib/Cake/View/JsonView.php index c0818351e..1f27c44fe 100644 --- a/lib/Cake/View/JsonView.php +++ b/lib/Cake/View/JsonView.php @@ -43,6 +43,9 @@ App::uses('View', 'View'); * If you don't use the `_serialize` key, you will need a view. You can use extended * views to provide layout like functionality. * + * You can also enable JSONP support by setting parameter `_jsonp` to true or a string to specify + * custom query string paramater name which will contain the callback function name. + * * @package Cake.View * @since CakePHP(tm) v 2.1.0 */ @@ -71,22 +74,39 @@ class JsonView extends View { /** * Render a JSON view. * - * Uses the special '_serialize' parameter to convert a set of - * view variables into a JSON response. Makes generating simple - * JSON responses very easy. You can omit the '_serialize' parameter, - * and use a normal view + layout as well. + * ### Special parameters + * `_serialize` To convert a set of view variables into a JSON response. + * It's value can be a string for single variable name or array for multiple names. + * You can omit the`_serialize` parameter, and use a normal view + layout as well. + * `_jsonp` Enables JSONP support and wraps response in callback function provided in query string. + * - Setting it to true enables the default query string parameter "callback". + * - Setting it to a string value, uses the provided query string parameter for finding the + * JSONP callback name. * * @param string $view The view being rendered. * @param string $layout The layout being rendered. * @return string The rendered view. */ public function render($view = null, $layout = null) { + $return = null; if (isset($this->viewVars['_serialize'])) { - return $this->_serialize($this->viewVars['_serialize']); + $return = $this->_serialize($this->viewVars['_serialize']); + } elseif ($view !== false && $this->_getViewFileName($view)) { + $return = parent::render($view, false); } - if ($view !== false && $this->_getViewFileName($view)) { - return parent::render($view, false); + + if (!empty($this->viewVars['_jsonp'])) { + $jsonpParam = $this->viewVars['_jsonp']; + if ($this->viewVars['_jsonp'] === true) { + $jsonpParam = 'callback'; + } + if (isset($this->request->query[$jsonpParam])) { + $return = sprintf('%s(%s)', h($this->request->query[$jsonpParam]), $return); + $this->response->type('js'); + } } + + return $return; } /**