Представления JSON и XML

JsonView и XmlView позволяют вам создавать ответы JSON и XML, и интегрировать их с Cake\Controller\Component\RequestHandlerComponent.

Активируя RequestHandlerComponent в вашем приложении, а также поддержку расширений json и/или xml, вы можете автоматически использовать новые классы представлений. JsonView и XmlView будут далее именоваться просто как представления данных в этом разделе.

Существует два способа, с помощью которых вы можете создать представления данных. Первый - используя ключ _serialize, и второй - создав обычные файлы шаблонов.

Активация представлений данных в вашем приложении

Прежде чем вы сможете использовать классы представлений данных, вам нужно сначала загрузить Cake\Controller\Component\RequestHandlerComponent в вашем контроллере:

public function initialize()
{
    ...
    $this->loadComponent('RequestHandler');
}

Это может быть сделано в вашем AppController, и активирует автоматическое переключение классов представлений, в зависимости от типа содержимого. Вы также можете настроить компонент с помощью опции viewClassMap, чтобы сопоставить типы вашим кастомным классам и/или добавить сопоставления также и для других типов данных (отличных от JSON и XML).

Вы опционально можете включить поддержку расширений json и/или xml, используя маршрутизацию по расширениям файлов. Это позволит вам получать доступ к данным в определенном формате, будь то JSON, XML или какой-либо другой формат, используя URL, оканчивающийся на имя типа ответа, как если бы это было расширением файла. К примеру http://example.com/articles.json.

По умолчанию, когда не включена маршрутизацию по расширениям файлов, запрос, для которого использовался заголовок Accept, определяет какого типа формат должен быть выведен пользователю. Например, формат Accept, используемый для вывода ответа в формате JSON - application/json.

Использование представлений данных с ключом Serialize

Ключ _serialize - это особая переменная представления, указывающая, какие другие переменные представления должны быть сериализованы при использовании представлений данных. Это позволяет вам избежать определение файлов шаблонов для экшенов ваших контроллеров, если вам не требуется какое-то особое форматирование перед тем, как ваши данные будут сконвертированы в json/xml.

Если вам необходимо совершить какие-либо манипуляции с вашими переменными представления перед генерированием ответа - используйте файлы шаблонов. Значением переменной _serialize может быть как строка, так и массив переменных представления для сериализации:

namespace App\Controller;

class ArticlesController extends AppController
{
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('RequestHandler');
    }

    public function index()
    {
        // Установить переменные представления, которые должны
        // быть сериализованы.
        $this->set('articles', $this->paginate());
        // Указываем, какие переменные представления JsonView
        // должен сериализовать.
        $this->set('_serialize', 'articles');
    }
}

Вы можете также определить _serialize как массив переменных представления, которые нам нужно совместить:

namespace App\Controller;

class ArticlesController extends AppController
{
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('RequestHandler');
    }

    public function index()
    {
        // Какой-то код, создавший $articles и $comments

        // Установливаем переменные представления, которые должны
        // быть сериализованы.
        $this->set(compact('articles', 'comments'));

        // Указываем, какие переменные представления JsonView
        // должен сериализовать.
        $this->set('_serialize', ['articles', 'comments']);
    }
}

Определяя _serialize как массив, мы получаем преимущество автоматического добавления элемента верхнего уровня <response> при использовании XmlView. Если вы используете строковое значение для _serialize и XmlView, убедитесь в том, что ваша переменная представления имеет единственный элемент верхнего уровня. Если элементов верхнего уровня будет больше одного, Xml не сможет сгенерироваться.

Использование представления данных с файлами шаблонов

Вы должны использовать файлы шаблонов, если вам нужно сделать какие-либо манипуляции с содержимым вашего представления перед созданием окончательного вывода. Например, если бы у нас были статьи, у которых было бы поле, содержащее сгенерированный HTML, мы, вероятно, хотели бы исключить это из ответа JSON. Это как раз та ситуация, когда файл представления будет полезен:

// Код контроллера
class ArticlesController extends AppController
{
    public function index()
    {
        $articles = $this->paginate('Articles');
        $this->set(compact('articles'));
    }
}

// Код представления - src/Template/Articles/json/index.ctp
foreach ($articles as &$article) {
    unset($article->generated_html);
}
echo json_encode(compact('articles'));

Вы можете выполнять более сложные манипуляции или использовать хелперы для форматирования. Классы представления данных не поддерживают макеты. Они предполагают, что в файле представлений выводится сериализованный контент.

Примечание

С версии 3.1.0 AppController в каркасе приложения автоматически добавляет '_serialize' => true ко всем запросам XML/JSON. Вам придется удалить этот код из коллбэк-метода beforeRender(), либо установить значение '_serialize' => false в экшенах вашего контроллера, если вы хотите использовать файлы представлений.

Создание XML-представлений

class XmlView

По умолчанию при использовании _serialize XmlView обернет ваши сериализованные переменные в узел <response>. Вы можете задать свое собственное имя для этого узла, используя переменную представления _rootNode.

Класс XmlView поддерживает переменную _xmlOptions, которая позволяет вам изменять опции, используемые при генерировании XML

The XmlView class supports the _xmlOptions variable that allows you to customize the options used to generate XML, например tags вместо attributes.

Создание JSON-представлений

class JsonView

Класс JsonView поддерживает переменную _jsonOptions, которая позволяет вам настроить битовую маску, используемую для генерирования JSON. См. json_encode для более полной информации о валидных значениях данной опции.

Например, чтобы сериализовать вывод ошибок валидации сущностей (entities) CakePHP в совместимой с JSON форме, сделайте следующее:

// Вэкшене вашего контроллера при ошибке сохранения
$this->set('errors', $articles->errors());
$this->set('_jsonOptions', JSON_FORCE_OBJECT);
$this->set('_serialize', ['errors']);

Ответы JSONP

При использовании JsonView вы можете использовать специальную переменную представления _jsonp для активации возможности получения ответа JSONP. Если установить значение true, класс представления проверяет, задан ли параметр строки запроса с именем «callback» и, если это так, следует обернуть ответ json в функцию с указанным именем. Если вы хотите использовать собственное имя параметра строки запроса вместо «callback», установите _jsonp на требуемое имя вместо true.

Пример использования

В то время, как RequestHandlerComponent может автоматически определять представление, основываясь на типе содержимого запроса или на расширении, вы также можете управлять сопоставлением представлений в вашем контроллере:

// src/Controller/VideosController.php
namespace App\Controller;

use App\Controller\AppController;
use Cake\Network\Exception\NotFoundException;

class VideosController extends AppController
{
    public function export($format = '')
    {
        $format = strtolower($format);

        // Формат сопоставления представлений
        $formats = [
          'xml' => 'Xml',
          'json' => 'Json',
        ];

        // Ошибка на неизвестных типах
        if (!isset($formats[$format])) {
            throw new NotFoundException(__('Unknown format.'));
        }

        // Установка формата вывода представления
        $this->viewBuilder()->className($formats[$format]);

        // Получение данных
        $videos = $this->Videos->find('latest');

        // Назначение представления данных
        $this->set(compact('videos'));
        $this->set('_serialize', ['videos']);

        // Принудительная загрузка
        // До версии 3.4.0
        // $this->response->download('report-' . date('YmdHis') . '.' . $format);
        return $this->response->withDownload('report-' . date('YmdHis') . '.' . $format);
    }
}