| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- <?xml version="1.0" encoding="utf-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.response">
- <title>Objet de réponse</title>
- <sect2 id="zend.controller.response.usage">
- <title>Utilisation</title>
- <para>
- L'objet de réponse équilibre la balance du modèle <acronym>MVC</acronym> avec
- <link linkend="zend.controller.request">l'objet de requête</link>. Son but est de
- collecter du contenu et des en-têtes, afin d'être rendue. De plus, le contrôleur
- frontal passe les exceptions qu'il a rencontré à l'objet de réponse, vous offrant une
- possibilité élégante de les gérer. Ce comportement peut être changé avec
- <methodname>Zend_Controller_Front::throwExceptions(true)</methodname> :
- </para>
- <programlisting language="php"><![CDATA[
- $front->throwExceptions(true);
- ]]></programlisting>
- <para>
- Pour rendre toute la réponse : corps et en-têtes, utilisez
- <methodname>sendResponse()</methodname>.
- </para>
- <programlisting language="php"><![CDATA[
- $response->sendResponse();
- ]]></programlisting>
- <note>
- <para>
- Par défaut le contrôleur frontal appelle <methodname>sendResponse()</methodname> lorsque
- la distribution est terminée. Vous pouvez changer ce comportement avec
- <methodname>Zend_Controller_Front::returnResponse(true)</methodname> :
- </para>
- <programlisting language="php"><![CDATA[
- $front->returnResponse(true);
- $response = $front->dispatch();
- // opérations, comme une historisation...
- // et rendu de la réponse:
- $response->sendResponse();
- ]]></programlisting>
- </note>
- <para>
- Vous ne devriez pas afficher du contenu directement dans un contrôleur. Empiler
- plutôt les affichages dans l'objet de réponse :
- </para>
- <programlisting language="php"><![CDATA[
- // Dans une action d'un contrôleur:
- $this->getResponse()
- ->setHeader('Content-Type', 'text/html')
- ->appendBody($content);
- ]]></programlisting>
- <para>
- Grâce à cela, tous les en-têtes sont envoyés d'un coup, juste avant l'affichage
- du contenu.
- </para>
- <note>
- <para>
- Si vous utilisez
- <link linkend="zend.controller.action.viewintegration">des vues dans vos
- action</link>, vous n'avez pas besoin d'ajouter le rendu de la vue dans la réponse,
- car <methodname>Zend_Controller_Action::render()</methodname> le fait par
- défaut.
- </para>
- </note>
- <para>
- Si une exception est ajoutée par le contrôleur frontal à la réponse, utilisez
- <methodname>isException()</methodname> pour vérifier ceci, et récupérez les exceptions avec
- <methodname>getException()</methodname>. Vous pourriez par exemple créer un objet de réponse
- d'erreur, comme un 404, et journaliser l'exception, etc.
- </para>
- <para>
- Pour prendre la main sur l'objet de réponse, demandez le au contrôleur frontal
- via un accesseur, ou commandez lui de vous retourner la celle-ci lors après la
- distribution.
- </para>
- <programlisting language="php"><![CDATA[
- // récupère la réponse après distribution et affichage:
- $front->dispatch();
- $response = $front->getResponse();
- if ($response->isException()) {
- // log, mail, etc...
- }
- // Demande au contrôleur frontal de ne pas afficher, mais retourner :
- $front->returnResponse(true);
- $response = $front->dispatch();
- // du code ici
- // enfin, affichage:
- $response->sendResponse();
- ]]></programlisting>
- <para>
- Par défaut, les messages d'exceptions ne sont pas affichés. Utilisez
- <methodname>renderExceptions()</methodname> si vous le voulez. Aussi, vous pouvez activer leur
- rendu grâce à Zend_Controller_Front::throwExceptions() :
- </para>
- <programlisting language="php"><![CDATA[
- $response->renderExceptions(true);
- $front->dispatch($request, $response);
- // ou:
- $front->returnResponse(true);
- $response = $front->dispatch();
- $response->renderExceptions();
- $response->sendResponse();
- // ou:
- $front->throwExceptions(true);
- $front->dispatch();
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.response.headers">
- <title>Manipulation des en-têtes</title>
- <para>
- Comme nous l'avons vu, un des rôles de l'objet de réponse est de gérer les
- en-têtes <acronym>HTTP</acronym>. Une variété de méthodes permet de contrôler cette gestion :
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>canSendHeaders($throw = false)</methodname> est utilisée pour déterminer
- si les en-têtes n'ont pas déjà été envoyés. Si le paramètre optionnel
- <varname>$throw</varname> est à <constant>TRUE</constant>, alors une exception sera envoyée
- si c'est le cas. L'attribut <code>headersSentThrowsException</code> permet
- aussi de gérer ce comportement.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setHeader($name, $value, $replace = false)</methodname> est utilisée pour
- affecter un en-tête unique. Par défaut, il n'écrase un éventuel précédent du
- même nom, sauf si <varname>$replace</varname> est mis à <constant>TRUE</constant>.
- </para>
- <para>
- Avant d'affecter un en-tête, cette méthode utilise
- <methodname>canSendHeaders()</methodname> pour voir si à ce point l'en-tête peut être
- envoyé.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setRedirect($url, $code = 302)</methodname> envoie un en-tête <acronym>HTTP</acronym>
- Location indiquant une redirection. Si un code de statut est passé, il sera
- utilisé.
- </para>
- <para>
- En interne, cette méthode appelle <methodname>setHeader()</methodname> avec
- <varname>$replace</varname> à <constant>TRUE</constant>, pour s'assurer de l'unicité de cet
- en-tête.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getHeaders()</methodname> retourne un tableau contenant tous les
- en-têtes. Chaque élément est un tableau "nom" 'valeur.
- </para>
- </listitem>
- <listitem>
- <para><methodname>clearHeaders()</methodname> efface tous les en-têtes enregistrés.</para>
- </listitem>
- <listitem>
- <para>
- <methodname>setRawHeader()</methodname> s'utilise pour affecter un en-tête brut,
- n'utilisant pas la syntaxe clé/valeur, comme un statut.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getRawHeaders()</methodname> retourne tous les en-têtes bruts
- enregistrés.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearRawHeaders()</methodname> efface tous les en-têtes bruts
- enregistrés.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearAllHeaders()</methodname> efface tous les en-têtes bruts et
- réguliers enregistrés.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- De plus, des accesseurs spéciaux sont disponibles pour manipuler le code de
- réponse <acronym>HTTP</acronym> : <methodname>setHttpResponseCode()</methodname> et
- <methodname>getHttpResponseCode()</methodname>.
- </para>
- </sect2>
- <sect2 id="zend.controller.response.namedsegments">
- <title>Segments nommés</title>
- <para>
- L'objet de réponse propose une fragmentation par segments. Ceci permet de séparer
- le corps de la réponse dans plusieurs segments réceptacles, que vous pouvez afficher
- dans un ordre précis. En interne, il s'agit d'un tableau namespacé qui dispose de
- méthodes de manipulation.
- </para>
- <para>
- Par exemple, vous pourriez utiliser l'évènement <methodname>preDispatch()</methodname> pour
- rajouter un bandeau de header au corps de la réponse, et l'évènement
- <methodname>postDispatch()</methodname> pour en ajouter un bandeau de footer :
- </para>
- <programlisting language="php"><![CDATA[
- // Considérons ce plugin comme étant enregistré
- // auprès du contrôleur frontal
- 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'));
- }
- }
- // un contrôleur d'action
- class MyController extends Zend_Controller_Action
- {
- public function fooAction()
- {
- $this->render();
- }
- }
- ]]></programlisting>
- <para>
- Un appel à <code>/my/foo</code> dans ce cas là, générera un objet de réponse
- ressemblant à ceci :
- </para>
- <programlisting language="php"><![CDATA[
- array(
- 'header' => ..., // contenu du segment header
- 'default' => ..., // corps, contenu de MyController::fooAction()
- 'footer' => ... // contenu du segment footer
- );
- ]]></programlisting>
- <para>
- Lorsque ceci est rendu, ça l'est dans l'ordre dans lequel les segments sont
- rangés dans la réponse.
- </para>
- <para>
- Voici quelques méthodes permettant de manipuler les segments de la
- réponse :
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>setBody()</methodname> et <methodname>appendBody()</methodname> effacent et écrivent,
- ou rajoutent un contenu à un segment qu'on leur indique en deuxième paramètre
- (<varname>$name</varname>). Si celui-ci n'existe pas, il sera crée en fin de pile. Si
- le paramètre segment n'est pas défini, alors le segment "default"est
- utilisé.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>prepend($name, $content)</methodname> va créer un segment appelé
- <varname>$name</varname> et le placé au début du tableau. Si le segment existe, il
- sera écrasé.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>append($name, $content)</methodname> va créer un segment appelé
- <varname>$name</varname> et le placer à la fin du tableau. Si le segment existe, il
- sera écrasé.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>insert($name, $content, $parent = null, $before = false)</methodname> va
- créer un segment appelé <varname>$name</varname>. Si <varname>$parent</varname> est
- renseigné, le nouveau segment sera placé avant ou après le segment
- <varname>$parent</varname>, ceci dépendant de la valeur de <varname>$before</varname>. Si
- le segment existe, il sera écrasé.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearBody($name = null)</methodname> va vider le contenu du segment qui
- lui est passé en paramètre via <varname>$name</varname>. Par défaut, il vide tout le
- tableau (détruit tous les segments).
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getBody($spec = false)</methodname> retourne le contenu du segment
- <varname>$spec</varname>. Si <varname>$spec</varname> vaut <constant>FALSE</constant>, il retourne
- le contenu de tous les segments. Si <constant>TRUE</constant>, c'est le tableau de
- segments qui est retourné.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.response.exceptions">
- <title>Manipulation des exceptions dans l'objet de réponse</title>
- <para>
- Comme déjà mentionné, par défaut, les exceptions rencontrées durant le processus
- <acronym>MVC</acronym> de distribution, sont ajoutées à l'objet de réponse. Elles le sont dans une pile,
- ce qui vous permet de toutes les garder -- les exceptions d'application, les exceptions
- de distribution, les exceptions de plugin -- etc... Si vous voulez manipuler finement
- celles-ci, voyez plutôt les méthodes ci-après :
- </para>
- <itemizedlist>
- <listitem>
- <para><methodname>setException(Exception $e)</methodname> enregistre une exception.</para>
- </listitem>
- <listitem>
- <para>
- <methodname>isException()</methodname> est utilisée pour déterminer si il existe au
- moins une exception.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getException()</methodname> retourne toutes les exceptions sous forme de
- tableau.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>hasExceptionOfType($type)</methodname> sert à déterminer si des
- exceptions d'une classe spécifique existent.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>hasExceptionOfMessage($message)</methodname> sert à déterminer si des
- exceptions ayant un message spécifique existent.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>hasExceptionOfCode($code)</methodname> sert à déterminer si des
- exceptions ayant un code spécifique existent.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getExceptionByType($type)</methodname> retourne toutes les exceptions
- d'une classe spécifique. Un tableau est retourné, ou <constant>FALSE</constant> si
- aucun exception ne correspond
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getExceptionByMessage($message)</methodname> retourne toutes les
- exceptions ayant un message spécifique. Un tableau est retourné, ou
- <constant>FALSE</constant> si aucun exception ne correspond
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getExceptionByCode($code)</methodname> retourne toutes les exceptions
- ayant un code spécifique. Un tableau est retourné, ou <constant>FALSE</constant> si
- aucun exception ne correspond.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>renderExceptions($flag)</methodname> vous permet de définir si les
- exceptions doivent être envoyées lorsque la réponse est rendue.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.response.subclassing">
- <title>Dériver l'objet de réponse</title>
- <para>
- L'objet de réponse sert à collecter les en-têtes <acronym>HTTP</acronym> de la réponse, ainsi que
- son contenu, depuis le système <acronym>MVC</acronym> mais aussi de l'afficher au client. De plus, l'objet
- collecte les exceptions et permet de les gérer, de les retourner, ou de les garder sous
- silence.
- </para>
- <para>
- La classe de base est <classname>Zend_Controller_Response_Abstract</classname>,
- et toute dérivation devra en hériter directement ou indirectement. Les méthodes qu'elle
- propose ont été vues dans les sections précédentes.
- </para>
- <para>
- Vous pouvez dériver l'objet de réponse pour plusieurs raisons, incluant la
- volonté de modifier le retour de la sortie, pour ne pas envoyer d'en-têtes dans un
- environnement de requête CLI ou <acronym>PHP</acronym>-GTK, la gestion de templates, etc.
- </para>
- </sect2>
- </sect1>
|