JSON and XML views

The JsonView and XmlViewlet you create JSON and XML responses, and integrate with theCake\Controller\Component\RequestHandlerComponent.

By enabling RequestHandlerComponent in your application, and enablingsupport for the json and/or xml extensions, you can automaticallyleverage the new view classes. JsonView and XmlView will be referred toas data views for the rest of this page.

There are two ways you can generate data views. The first is by using theserialize option, and the second is by creating normal template files.

Enabling Data Views in Your Application

Before you can use the data view classes, you’ll first need to load theCake\Controller\Component\RequestHandlerComponent in yourcontroller:

  1. public function initialize(): void
  2. {
  3. ...
  4. $this->loadComponent('RequestHandler');
  5. }

This can be done in your AppController and will enable automatic view classswitching on content types. You can also set the component up with theviewClassMap setting, to map types to your custom classes and/or map otherdata types.

You can optionally enable the json and/or xml extensions withRouting File Extensions. This will allow you to access the JSON, XML orany other special format views by using a custom URL ending with the name of theresponse type as a file extension such as http://example.com/articles.json.

By default, when not enabling Routing File Extensions, the request, the Acceptheader is used for, selecting which type of format should be rendered to theuser. An example Accept format that is used to render JSON responses isapplication/json.

Using Data Views with the Serialize Key

The serialize option indicates which view variable(s) should beserialized when using a data view. This lets you skip defining template filesfor your controller actions if you don’t need to do any custom formatting beforeyour data is converted into json/xml.

If you need to do any formatting or manipulation of your view variables beforegenerating the response, you should use template files. The value ofserialize can be either a string or an array of view variables toserialize:

  1. namespace App\Controller;
  2.  
  3. class ArticlesController extends AppController
  4. {
  5. public function initialize(): void
  6. {
  7. parent::initialize();
  8. $this->loadComponent('RequestHandler');
  9. }
  10.  
  11. public function index()
  12. {
  13. // Set the view vars that have to be serialized.
  14. $this->set('articles', $this->paginate());
  15. // Specify which view vars JsonView should serialize.
  16. $this->viewBuilder()->setOption('serialize', 'articles');
  17. }
  18. }

You can also define serialize as an array of view variables to combine:

  1. namespace App\Controller;
  2.  
  3. class ArticlesController extends AppController
  4. {
  5. public function initialize(): void
  6. {
  7. parent::initialize();
  8. $this->loadComponent('RequestHandler');
  9. }
  10.  
  11. public function index()
  12. {
  13. // Some code that created $articles and $comments
  14.  
  15. // Set the view vars that have to be serialized.
  16. $this->set(compact('articles', 'comments'));
  17.  
  18. // Specify which view vars JsonView should serialize.
  19. $this->viewBuilder()->setOption('serialize', ['articles', 'comments']);
  20. }
  21. }

Defining serialize as an array has added the benefit of automaticallyappending a top-level <response> element when using XmlView.If you use a string value for serialize and XmlView, make sure that yourview variable has a single top-level element. Without a single top-levelelement the Xml will fail to generate.

Using a Data View with Template Files

You should use template files if you need to do some manipulation of your viewcontent before creating the final output. For example if we had articles, that hada field containing generated HTML, we would probably want to omit that from aJSON response. This is a situation where a view file would be useful:

  1. // Controller code
  2. class ArticlesController extends AppController
  3. {
  4. public function index()
  5. {
  6. $articles = $this->paginate('Articles');
  7. $this->set(compact('articles'));
  8. }
  9. }
  10.  
  11. // View code - templates/Articles/json/index.php
  12. foreach ($articles as &$article) {
  13. unset($article->generated_html);
  14. }
  15. echo json_encode(compact('articles'));

You can do more complex manipulations, or use helpers to do formatting as well.The data view classes don’t support layouts. They assume that the view file willoutput the serialized content.

Creating XML Views

  • class XmlView

By default when using serialize the XmlView will wrap your serializedview variables with a <response> node. You can set a custom name forthis node using the rootNode option.

The XmlView class supports the xmlOptions option that allows you tocustomize the options used to generate XML, e.g. tags vs attributes.

An example of using XmlView would be to generate a sitemap.xml. This document type requires that youchange _rootNode and set attributes. Attributes are defined using the @prefix:

  1. public function sitemap()
  2. {
  3. $pages = $this->Pages->find();
  4. $urls = [];
  5. foreach ($pages as $page) {
  6. $urls[] = [
  7. 'loc' => Router::url(['controller' => 'Pages', 'action' => 'view', $page->slug, '_full' => true]),
  8. 'lastmod' => $page->modified->format('Y-m-d'),
  9. 'changefreq' => 'daily',
  10. 'priority' => '0.5'
  11. ];
  12. }
  13.  
  14. // Define a custom root node in the generated document.
  15. $this->viewBuilder()
  16. ->setOption('rootNode', 'urlset')
  17. ->setOption('serialize', ['@xmlns', 'url']);
  18. $this->set([
  19. // Define an attribute on the root node.
  20. '@xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9',
  21. 'url' => $urls
  22. ]);
  23. }

Creating JSON Views

  • class JsonView

The JsonView class supports the _jsonOptions variable that allows you tocustomize the bit-mask used to generate JSON. See thejson_encode documentation for the validvalues of this option.

For example, to serialize validation error output of CakePHP entities in a consistent form of JSON do:

  1. // In your controller's action when saving failed
  2. $this->set('errors', $articles->errors());
  3. $this->viewBuilder()
  4. ->setOption('serialize', ['errors'])
  5. ->setOption('jsonOptions', JSON_FORCE_OBJECT);

JSONP Responses

When using JsonView you can use the special view variable _jsonp toenable returning a JSONP response. Setting it to true makes the view classcheck if query string parameter named “callback” is set and if so wrap the jsonresponse in the function name provided. If you want to use a custom query stringparameter name instead of “callback” set _jsonp to required name instead oftrue.

Example Usage

While the RequestHandlerComponent can automatically set the view basedon the request content-type or extension, you could also handle viewmappings in your controller:

  1. // src/Controller/VideosController.php
  2. namespace App\Controller;
  3.  
  4. use App\Controller\AppController;
  5. use Cake\Http\Exception\NotFoundException;
  6.  
  7. class VideosController extends AppController
  8. {
  9. public function export($format = '')
  10. {
  11. $format = strtolower($format);
  12.  
  13. // Format to view mapping
  14. $formats = [
  15. 'xml' => 'Xml',
  16. 'json' => 'Json',
  17. ];
  18.  
  19. // Error on unknown type
  20. if (!isset($formats[$format])) {
  21. throw new NotFoundException(__('Unknown format.'));
  22. }
  23.  
  24. // Set Out Format View
  25. $this->viewBuilder()->className($formats[$format]);
  26.  
  27. // Get data
  28. $videos = $this->Videos->find('latest');
  29.  
  30. // Set Data View
  31. $this->set(compact('videos'));
  32. $this->viewBuilder()->setOption('serialize', ['videos']);
  33.  
  34. // Set Force Download
  35. return $this->response->withDownload('report-' . date('YmdHis') . '.' . $format);
  36. }
  37. }