1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.controller.response">
4 <title>Объект ответа</title>
6 <sect2 id="zend.controller.response.usage">
7 <title>Использование</title>
10 Объект ответа представляет собой логическое продолжение к
11 <link linkend="zend.controller.request">объекту запроса</link>. Его
12 назначение — сбор содержимого ответа и/или его заголовков, таким
13 образом, они могут возвращаться как одно целое. Кроме этого,
14 фронт-контроллер будет передавать любые пойманные исключения объекту
15 ответа, позволяя разработчику должным образом обрабатывать
16 исключения. Эта возможность может быть отключена установкой
17 <code>Zend_Controller_Front::throwExceptions(true)</code>:
20 <programlisting language="php"><![CDATA[
21 $front->throwExceptions(true);
25 Для отправки выходных данных, включая заголовки, используйте
26 метод <code>sendResponse()</code>.
29 <programlisting language="php"><![CDATA[
30 $response->sendResponse();
35 По умолчанию фронт-контроллер вызывает
36 <code>sendResponse()</code>, когда завершает обработку запроса,
37 и, скорее всего, вам никогда не потребуется вызывать этот метод.
38 Тем не менее, если вы хотите производить манипуляции с ответом
39 или использовать его в тестировании, то вы можете отменить
40 это поведение посредством установки флага
41 <code>returnResponse</code> методом
42 <code>Zend_Controller_Front::returnResponse(true)</code>:
45 <programlisting language="php"><![CDATA[
46 $front->returnResponse(true);
47 $response = $front->dispatch();
49 // производим необходимые манипуляции с данными (например,
50 // журналирование), затем отправляем выходные данные:
51 $response->sendResponse();
56 Разработчики должны использовать объект ответа в своих контроллерах
57 действий. Вместо прямого вывода данных и отправки заголовков
58 помещайте их в объект ответа:
61 <programlisting language="php"><![CDATA[
62 // Внутри контроллера действий:
63 // Установка заголовка
65 ->setHeader('Content-Type', 'text/html')
66 ->appendBody($content);
70 Этим достигается то, что все заголовки будут отправлены
71 одновременно, непосредственно до того, как будет отображено
79 linkend="zend.controller.action.viewintegration">интеграция
80 вида</link>, то вам не нужно сохранять результат рендеринга
81 скрипта вида в объект ответа, поскольку
82 <code>Zend_Controller_Action::render()</code> делает это по
88 На тот случай, когда произошло исключение в приложении, проверяйте
89 флаг <code>isException()</code> в объекте ответа и
90 извлекайте исключение, используя <code>getException()</code>. Кроме
91 этого, можно создать собственные объекты ответа, которые производят
92 перенаправление на страницу ошибки, журналируют сообщения
93 исключений, должным образом оформляют сообщения исключений
94 для среды разработки и т.д.
98 Вы можете извлекать объект ответа после вызова метода dispatch()
99 фронт-контроллера или указать фронт-контроллеру, чтобы он возвращал
100 объект ответа вместо его вывода.
103 <programlisting language="php"><![CDATA[
104 // Получение объекта ответа после диспетчеризации:
106 $response = $front->getResponse();
107 if ($response->isException()) {
108 // Журналирование, отправка сообщений и т.д
111 // Либо метод dispatch() фронт-контроллера возвращает его
112 $front->returnResponse(true);
113 $response = $front->dispatch();
115 // Производим какие-либо манипуляции...
117 // В конце выводим ответ
118 $response->sendResponse();
122 По умолчанию сообщения исключений не отображаются. Это поведение
123 может быть отменено вызовом метода <code>renderExceptions()</code>
124 или включением через метод <code>throwExceptions()</code>
125 возможности генерации исключений фронт-контроллером, как показано
129 <programlisting language="php"><![CDATA[
130 $response->renderExceptions(true);
131 $front->dispatch($request, $response);
134 $front->returnResponse(true);
135 $response = $front->dispatch();
136 $response->renderExceptions();
137 $response->sendResponse();
140 $front->throwExceptions(true);
145 <sect2 id="zend.controller.response.headers">
146 <title>Управление заголовками</title>
149 Как было замечено ранее, одной из обязанностей объекта ответа
150 является сбор и отправка заголовков ответа HTTP. Для этого есть
157 <code>canSendHeaders()</code> используется для определения
158 того, были ли заголовки отправлены ранее. Опционально он
159 принимает флаг, указывающий, бросать или нет исключение,
160 если заголовки были уже отправлены. Генерация таких
161 исключений может быть отменена посредством установки
162 свойства <code>headersSentThrowsException</code> в
163 <constant>FALSE</constant>.
169 <code>setHeader($name, $value, $replace = false)</code>
170 используется для установки отдельного заголовка. По
171 умолчанию он не замещает в объекте существующие под тем же
172 именем заголовки. Но установкой
173 <varname>$replace</varname> в <constant>TRUE</constant> можно произвести
174 принудительную замену заголовка.
178 До установки заголовка он вызывает другой метод
179 <code>canSendHeaders()</code> для проверки того, можно ли
180 выполнить данную операцию, и прверяет, было ли брошено
187 <code>setRedirect($url, $code = 302)</code> устанавливает
188 HTTP-заголовок "Location" для перенаправления.
189 Если был передан код статуса HTTP, то он будет
190 использоваться при перенаправлении.
194 Внутри себя он вызывает <code>setHeader()</code> со
195 флагом <varname>$replace</varname> для обеспечения гарантии того,
196 что отправляется только один такой заголовок.
202 <code>getHeaders()</code> возвращает массив всех заголовков.
203 Каждый элемент массива является массивом со ключами 'name' и
210 <code>clearHeaders()</code> удаляет все зарегистрированные
217 <code>setRawHeader()</code> может использоваться для
218 установки заголовков, которые не являются парами
219 ключ/значение, например, заголовок статуса HTTP.
225 <code>getRawHeaders()</code> возвращает все
226 зарегистрированные через <code>setRawHeader()</code>
233 <code>clearRawHeaders()</code> удаляет все
234 зарегистрированные через <code>setRawHeader()</code>
241 <code>clearAllHeaders()</code> удаляет как обычные
242 заголовки из пар ключ/значение, так и
243 "необработанные" (raw).
249 Кроме перечисленных выше методов, есть аксессоры для установки и
250 получения кода ответа для текущего запроса,
251 <code>setHttpResponseCode()</code> и
252 <code>getHttpResponseCode()</code>.
256 <sect2 id="zend.controller.response.namedsegments">
257 <title>Именованные сегменты</title>
260 Объект ответа поддерживает именованные сегменты. Это позволяет
261 делить содержимое ответа на различные сегменты и упорядочивать эти
262 сегменты так, что вывод будет возвращаться в определенном порядке.
263 Внутри содержимое тела ответа сохраняется в массиве, и могут
264 использоваться различные методы-аксессоры для указания размещения и
269 Например, вы можете использовать перехватчик
270 <code>preDispatch()</code> для добавления верха страницы в
271 объект ответа, затем метод действия должен добавить тело
272 страницы, а перехватчик <code>postDispatch()</code> добавляет низ
276 <programlisting language="php"><![CDATA[
277 // Предполагается, что класс плагина зарегистрирован во фронт-контроллере
278 class MyPlugin extends Zend_Controller_Plugin_Abstract
280 public function preDispatch(Zend_Controller_Request_Abstract $request)
282 $response = $this->getResponse();
283 $view = new Zend_View();
284 $view->setBasePath('../views/scripts');
286 $response->prepend('header', $view->render('header.phtml'));
289 public function postDispatch(Zend_Controller_Request_Abstract $request)
291 $response = $this->getResponse();
292 $view = new Zend_View();
293 $view->setBasePath('../views/scripts');
295 $response->append('footer', $view->render('footer.phtml'));
299 // Пример контроллера действий
300 class MyController extends Zend_Controller_Action
302 public function fooAction()
310 В примере выше вызов <code>/my/foo</code> приведет к тому, что
311 конечное содержимое тела объекта ответа будет иметь следующую
315 <programlisting language="php"><![CDATA[
317 'header' => ..., // содержимое верха страницы
318 'default' => ..., // содержимое тела страницы из MyController::fooAction()
319 'footer' => ... // содержимое низа страницы
324 Рендеринг производится в том порядке, в котором элементы
325 представлены в массиве.
329 Для управления именованными сегментами могут использоваться
336 <code>setBody()</code> и <code>appendBody()</code> позволяют
337 передавать второе значение, <varname>$name</varname>, обозначающее
338 именованный сегмент. В любом случае, если вы передаете его,
339 он перепишет этот именованный сегмент или создаст его, если
340 он не существует (по умолчанию добавляя в конец массива).
341 Если методу <code>setBody()</code> не был передан
342 именованный сегмент, то будет сброшен весь массив
343 содержимого тела. Если методу <code>appendBody()</code> не
344 было передано имя сегмента, то содержимое будет добавлено в
345 конец сегмента с именем 'default'.
351 <code>prepend($name, $content)</code> будет создавать
352 сегмент с именем <varname>$name</varname> и помещать его в начало
353 массива. Если сегмент уже существует, то он будет удален до
354 операции добавления (т.е. перезаписан).
360 <code>append($name, $content)</code> будет создавать сегмент
361 с именем <varname>$name</varname> и помещать его в конец массива.
362 Если сегмент уже существует, то он будет удален до операции
369 <code>insert($name, $content, $parent = null, $before = false)</code>
370 будет создавать сегмент с именем <varname>$name</varname>. Если
371 был передано имя сегмента <varname>$parent</varname> (родитель),
372 то новый сегмент будет помещен до или после этого сегмента
373 (основываясь на значениии <varname>$before</varname>) в массиве.
374 Если сегмент уже существует, то он будет удален до операции
381 <code>clearBody($name = null)</code> удалит один
382 сегмент, если был передано его имя <varname>$name</varname>,
383 иначе будет удален весь массив.
389 <code>getBody($spec = false)</code> может использоваться для
390 получения массива сегментов, если <varname>$spec</varname> - имя
391 именованного сегмента. Если равен false, то будет возвращена
392 строка, сформированная посредством объединения всех
393 сегментов в порядке следования. Если <varname>$spec</varname>
394 равен true, то он вернет массив содержимого тела.
400 <sect2 id="zend.controller.response.exceptions">
401 <title>Проверка на исключения в объекте ответа</title>
404 Как было отмечено ранее, по умолчанию исключения, пойманные во время
405 диспетчеризации, регистрируются в объекте ответа. Исключения
406 регистрируются в стеке, что позволяет вам хранить все брошенные
407 исключения - исключения приложения, диспетчера, плагинов и т.д.
408 Если нужно производить проверку на определенные исключения или
409 журналировать их, то используйте следующее API объекта ответа для
416 <code>setException(Exception $e)</code> позволяет
417 произвести регистрацию исключения.
423 <code>isException()</code> позволяет определить, было ли
424 зарегистрировано какое-либо исключение.
430 <code>getException()</code> возвращает весь стек
437 <code>hasExceptionOfType($type)</code> позволяет определить
438 наличие в стеке исключения определенного класса.
444 <code>hasExceptionOfMessage($message)</code> позволяет
445 определить наличие в стеке исключения с заданным
452 <code>hasExceptionOfCode($code)</code> позволяет определить
453 наличие в стеке исключения с определенным кодом.
459 <code>getExceptionByType($type)</code> позволяет извлечь все
460 исключения определенного класса из стека.
461 Возвращает false, если не был найдено ни одно
462 исключение, иначе - массив исключений.
468 <code>getExceptionByMessage($message)</code> позволяет
469 извлекать все исключения с заданным сообщением из стека.
470 Возвращает false, если не был найдено ни одно
471 исключение, иначе - массив исключений.
477 <code>getExceptionByCode($code)</code> позволяет извлекать
478 все исключения с определенным кодом из стека.
479 Возвращает false, если не был найдено ни одно
480 исключение, иначе - массив исключений.
486 <code>renderExceptions($flag)</code> позволяет установить
487 флаг, указывающий, должны или нет отправляться исключения
494 <sect2 id="zend.controller.response.subclassing">
495 <title>Создание подклассов объекта ответа</title>
498 Назначением объекта ответа является сбор заголовков и содержимого из
499 различных действий и плагинов, и возврат их клиенту. Кроме этого, он
500 собирает все возникающие ошибки (исключения) для того, чтобы
501 обрабатывать их, возвращать или прятать от конечного пользователя.
505 Базовым классом ответа является
506 <classname>Zend_Controller_Response_Abstract</classname>, все
507 создаваемые вами подклассы должны наследовать от него или одного из
508 его потомков. Доступные методы были перечислены в предыдущих
513 Цели, преследуемые при создании подклассов объекта ответа, включают
514 в себя изменение способа вывода, основанное на
515 окружении запроса (например, не отправлять заголовки для запросов
516 CLI или PHP-GTK), добавление функционала для возвращения конечного
517 вида, основанного на содержимом, сохраненном в именованном сегменте,