| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.response">
- <title>Объект ответа</title>
- <sect2 id="zend.controller.response.usage">
- <title>Использование</title>
- <para>
- Объект ответа представляет собой логическое продолжение к
- <link linkend="zend.controller.request">объекту запроса</link>. Его
- назначение — сбор содержимого ответа и/или его заголовков, таким
- образом, они могут возвращаться как одно целое. Кроме этого,
- фронт-контроллер будет передавать любые пойманные исключения объекту
- ответа, позволяя разработчику должным образом обрабатывать
- исключения. Эта возможность может быть отключена установкой
- <code>Zend_Controller_Front::throwExceptions(true)</code>:
- </para>
- <programlisting language="php"><![CDATA[
- $front->throwExceptions(true);
- ]]></programlisting>
- <para>
- Для отправки выходных данных, включая заголовки, используйте
- метод <code>sendResponse()</code>.
- </para>
- <programlisting language="php"><![CDATA[
- $response->sendResponse();
- ]]></programlisting>
- <note>
- <para>
- По умолчанию фронт-контроллер вызывает
- <code>sendResponse()</code>, когда завершает обработку запроса,
- и, скорее всего, вам никогда не потребуется вызывать этот метод.
- Тем не менее, если вы хотите производить манипуляции с ответом
- или использовать его в тестировании, то вы можете отменить
- это поведение посредством установки флага
- <code>returnResponse</code> методом
- <code>Zend_Controller_Front::returnResponse(true)</code>:
- </para>
- <programlisting language="php"><![CDATA[
- $front->returnResponse(true);
- $response = $front->dispatch();
- // производим необходимые манипуляции с данными (например,
- // журналирование), затем отправляем выходные данные:
- $response->sendResponse();
- ]]></programlisting>
- </note>
- <para>
- Разработчики должны использовать объект ответа в своих контроллерах
- действий. Вместо прямого вывода данных и отправки заголовков
- помещайте их в объект ответа:
- </para>
- <programlisting language="php"><![CDATA[
- // Внутри контроллера действий:
- // Установка заголовка
- $this->getResponse()
- ->setHeader('Content-Type', 'text/html')
- ->appendBody($content);
- ]]></programlisting>
- <para>
- Этим достигается то, что все заголовки будут отправлены
- одновременно, непосредственно до того, как будет отображено
- содержимое ответа.
- </para>
- <note>
- <para>
- Если используется
- <link
- linkend="zend.controller.action.viewintegration">интеграция
- вида</link>, то вам не нужно сохранять результат рендеринга
- скрипта вида в объект ответа, поскольку
- <code>Zend_Controller_Action::render()</code> делает это по
- умолчанию.
- </para>
- </note>
- <para>
- На тот случай, когда произошло исключение в приложении, проверяйте
- флаг <code>isException()</code> в объекте ответа и
- извлекайте исключение, используя <code>getException()</code>. Кроме
- этого, можно создать собственные объекты ответа, которые производят
- перенаправление на страницу ошибки, журналируют сообщения
- исключений, должным образом оформляют сообщения исключений
- для среды разработки и т.д.
- </para>
- <para>
- Вы можете извлекать объект ответа после вызова метода dispatch()
- фронт-контроллера или указать фронт-контроллеру, чтобы он возвращал
- объект ответа вместо его вывода.
- </para>
- <programlisting language="php"><![CDATA[
- // Получение объекта ответа после диспетчеризации:
- $front->dispatch();
- $response = $front->getResponse();
- if ($response->isException()) {
- // Журналирование, отправка сообщений и т.д
- }
- // Либо метод dispatch() фронт-контроллера возвращает его
- $front->returnResponse(true);
- $response = $front->dispatch();
- // Производим какие-либо манипуляции...
- // В конце выводим ответ
- $response->sendResponse();
- ]]></programlisting>
- <para>
- По умолчанию сообщения исключений не отображаются. Это поведение
- может быть отменено вызовом метода <code>renderExceptions()</code>
- или включением через метод <code>throwExceptions()</code>
- возможности генерации исключений фронт-контроллером, как показано
- ниже:
- </para>
- <programlisting language="php"><![CDATA[
- $response->renderExceptions(true);
- $front->dispatch($request, $response);
- // или:
- $front->returnResponse(true);
- $response = $front->dispatch();
- $response->renderExceptions();
- $response->sendResponse();
- // или:
- $front->throwExceptions(true);
- $front->dispatch();
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.response.headers">
- <title>Управление заголовками</title>
- <para>
- Как было замечено ранее, одной из обязанностей объекта ответа
- является сбор и отправка заголовков ответа HTTP. Для этого есть
- различные методы:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>canSendHeaders()</code> используется для определения
- того, были ли заголовки отправлены ранее. Опционально он
- принимает флаг, указывающий, бросать или нет исключение,
- если заголовки были уже отправлены. Генерация таких
- исключений может быть отменена посредством установки
- свойства <code>headersSentThrowsException</code> в
- <constant>FALSE</constant>.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>setHeader($name, $value, $replace = false)</code>
- используется для установки отдельного заголовка. По
- умолчанию он не замещает в объекте существующие под тем же
- именем заголовки. Но установкой
- <varname>$replace</varname> в <constant>TRUE</constant> можно произвести
- принудительную замену заголовка.
- </para>
- <para>
- До установки заголовка он вызывает другой метод
- <code>canSendHeaders()</code> для проверки того, можно ли
- выполнить данную операцию, и прверяет, было ли брошено
- исключение.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>setRedirect($url, $code = 302)</code> устанавливает
- HTTP-заголовок "Location" для перенаправления.
- Если был передан код статуса HTTP, то он будет
- использоваться при перенаправлении.
- </para>
- <para>
- Внутри себя он вызывает <code>setHeader()</code> со
- флагом <varname>$replace</varname> для обеспечения гарантии того,
- что отправляется только один такой заголовок.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getHeaders()</code> возвращает массив всех заголовков.
- Каждый элемент массива является массивом со ключами 'name' и
- 'value'.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>clearHeaders()</code> удаляет все зарегистрированные
- ранее заголовки.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>setRawHeader()</code> может использоваться для
- установки заголовков, которые не являются парами
- ключ/значение, например, заголовок статуса HTTP.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getRawHeaders()</code> возвращает все
- зарегистрированные через <code>setRawHeader()</code>
- заголовки.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>clearRawHeaders()</code> удаляет все
- зарегистрированные через <code>setRawHeader()</code>
- заголовки.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>clearAllHeaders()</code> удаляет как обычные
- заголовки из пар ключ/значение, так и
- "необработанные" (raw).
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Кроме перечисленных выше методов, есть аксессоры для установки и
- получения кода ответа для текущего запроса,
- <code>setHttpResponseCode()</code> и
- <code>getHttpResponseCode()</code>.
- </para>
- </sect2>
- <sect2 id="zend.controller.response.namedsegments">
- <title>Именованные сегменты</title>
- <para>
- Объект ответа поддерживает именованные сегменты. Это позволяет
- делить содержимое ответа на различные сегменты и упорядочивать эти
- сегменты так, что вывод будет возвращаться в определенном порядке.
- Внутри содержимое тела ответа сохраняется в массиве, и могут
- использоваться различные методы-аксессоры для указания размещения и
- имен в этом массиве.
- </para>
- <para>
- Например, вы можете использовать перехватчик
- <code>preDispatch()</code> для добавления верха страницы в
- объект ответа, затем метод действия должен добавить тело
- страницы, а перехватчик <code>postDispatch()</code> добавляет низ
- страницы:
- </para>
- <programlisting language="php"><![CDATA[
- // Предполагается, что класс плагина зарегистрирован во фронт-контроллере
- class MyPlugin extends Zend_Controller_Plugin_Abstract
- {
- public function preDispatch(Zend_Controller_Request_Abstract $request)
- {
- $response = $this->getResponse();
- $view = new Zend_View();
- $view->setBasePath('../views/scripts');
- $response->prepend('header', $view->render('header.phtml'));
- }
- public function postDispatch(Zend_Controller_Request_Abstract $request)
- {
- $response = $this->getResponse();
- $view = new Zend_View();
- $view->setBasePath('../views/scripts');
- $response->append('footer', $view->render('footer.phtml'));
- }
- }
- // Пример контроллера действий
- class MyController extends Zend_Controller_Action
- {
- public function fooAction()
- {
- $this->render();
- }
- }
- ]]></programlisting>
- <para>
- В примере выше вызов <code>/my/foo</code> приведет к тому, что
- конечное содержимое тела объекта ответа будет иметь следующую
- структуру:
- </para>
- <programlisting language="php"><![CDATA[
- array(
- 'header' => ..., // содержимое верха страницы
- 'default' => ..., // содержимое тела страницы из MyController::fooAction()
- 'footer' => ... // содержимое низа страницы
- );
- ]]></programlisting>
- <para>
- Рендеринг производится в том порядке, в котором элементы
- представлены в массиве.
- </para>
- <para>
- Для управления именованными сегментами могут использоваться
- различные методы:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>setBody()</code> и <code>appendBody()</code> позволяют
- передавать второе значение, <varname>$name</varname>, обозначающее
- именованный сегмент. В любом случае, если вы передаете его,
- он перепишет этот именованный сегмент или создаст его, если
- он не существует (по умолчанию добавляя в конец массива).
- Если методу <code>setBody()</code> не был передан
- именованный сегмент, то будет сброшен весь массив
- содержимого тела. Если методу <code>appendBody()</code> не
- было передано имя сегмента, то содержимое будет добавлено в
- конец сегмента с именем 'default'.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>prepend($name, $content)</code> будет создавать
- сегмент с именем <varname>$name</varname> и помещать его в начало
- массива. Если сегмент уже существует, то он будет удален до
- операции добавления (т.е. перезаписан).
- </para>
- </listitem>
- <listitem>
- <para>
- <code>append($name, $content)</code> будет создавать сегмент
- с именем <varname>$name</varname> и помещать его в конец массива.
- Если сегмент уже существует, то он будет удален до операции
- добавления.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>insert($name, $content, $parent = null, $before = false)</code>
- будет создавать сегмент с именем <varname>$name</varname>. Если
- был передано имя сегмента <varname>$parent</varname> (родитель),
- то новый сегмент будет помещен до или после этого сегмента
- (основываясь на значениии <varname>$before</varname>) в массиве.
- Если сегмент уже существует, то он будет удален до операции
- добавления.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>clearBody($name = null)</code> удалит один
- сегмент, если был передано его имя <varname>$name</varname>,
- иначе будет удален весь массив.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getBody($spec = false)</code> может использоваться для
- получения массива сегментов, если <varname>$spec</varname> - имя
- именованного сегмента. Если равен false, то будет возвращена
- строка, сформированная посредством объединения всех
- сегментов в порядке следования. Если <varname>$spec</varname>
- равен true, то он вернет массив содержимого тела.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.response.exceptions">
- <title>Проверка на исключения в объекте ответа</title>
- <para>
- Как было отмечено ранее, по умолчанию исключения, пойманные во время
- диспетчеризации, регистрируются в объекте ответа. Исключения
- регистрируются в стеке, что позволяет вам хранить все брошенные
- исключения - исключения приложения, диспетчера, плагинов и т.д.
- Если нужно производить проверку на определенные исключения или
- журналировать их, то используйте следующее API объекта ответа для
- исключений:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>setException(Exception $e)</code> позволяет
- произвести регистрацию исключения.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>isException()</code> позволяет определить, было ли
- зарегистрировано какое-либо исключение.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getException()</code> возвращает весь стек
- исключений.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>hasExceptionOfType($type)</code> позволяет определить
- наличие в стеке исключения определенного класса.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>hasExceptionOfMessage($message)</code> позволяет
- определить наличие в стеке исключения с заданным
- сообщением.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>hasExceptionOfCode($code)</code> позволяет определить
- наличие в стеке исключения с определенным кодом.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getExceptionByType($type)</code> позволяет извлечь все
- исключения определенного класса из стека.
- Возвращает false, если не был найдено ни одно
- исключение, иначе - массив исключений.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getExceptionByMessage($message)</code> позволяет
- извлекать все исключения с заданным сообщением из стека.
- Возвращает false, если не был найдено ни одно
- исключение, иначе - массив исключений.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getExceptionByCode($code)</code> позволяет извлекать
- все исключения с определенным кодом из стека.
- Возвращает false, если не был найдено ни одно
- исключение, иначе - массив исключений.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>renderExceptions($flag)</code> позволяет установить
- флаг, указывающий, должны или нет отправляться исключения
- вместе с ответом.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.response.subclassing">
- <title>Создание подклассов объекта ответа</title>
- <para>
- Назначением объекта ответа является сбор заголовков и содержимого из
- различных действий и плагинов, и возврат их клиенту. Кроме этого, он
- собирает все возникающие ошибки (исключения) для того, чтобы
- обрабатывать их, возвращать или прятать от конечного пользователя.
- </para>
- <para>
- Базовым классом ответа является
- <classname>Zend_Controller_Response_Abstract</classname>, все
- создаваемые вами подклассы должны наследовать от него или одного из
- его потомков. Доступные методы были перечислены в предыдущих
- разделах.
- </para>
- <para>
- Цели, преследуемые при создании подклассов объекта ответа, включают
- в себя изменение способа вывода, основанное на
- окружении запроса (например, не отправлять заголовки для запросов
- CLI или PHP-GTK), добавление функционала для возвращения конечного
- вида, основанного на содержимом, сохраненном в именованном сегменте,
- и т.д.
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|