Zend_Controller-Response.xml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.controller.response">
  5. <title>Objet de réponse</title>
  6. <sect2 id="zend.controller.response.usage">
  7. <title>Utilisation</title>
  8. <para>
  9. L'objet de réponse équilibre la balance du modèle <acronym>MVC</acronym> avec
  10. <link linkend="zend.controller.request">l'objet de requête</link>. Son but est de
  11. collecter du contenu et des en-têtes, afin d'être rendue. De plus, le contrôleur
  12. frontal passe les exceptions qu'il a rencontré à l'objet de réponse, vous offrant une
  13. possibilité élégante de les gérer. Ce comportement peut être changé avec
  14. <methodname>Zend_Controller_Front::throwExceptions(true)</methodname>&#160;:
  15. </para>
  16. <programlisting language="php"><![CDATA[
  17. $front->throwExceptions(true);
  18. ]]></programlisting>
  19. <para>
  20. Pour rendre toute la réponse : corps et en-têtes, utilisez
  21. <methodname>sendResponse()</methodname>.
  22. </para>
  23. <programlisting language="php"><![CDATA[
  24. $response->sendResponse();
  25. ]]></programlisting>
  26. <note>
  27. <para>
  28. Par défaut le contrôleur frontal appelle <methodname>sendResponse()</methodname> lorsque
  29. la distribution est terminée. Vous pouvez changer ce comportement avec
  30. <methodname>Zend_Controller_Front::returnResponse(true)</methodname>&#160;:
  31. </para>
  32. <programlisting language="php"><![CDATA[
  33. $front->returnResponse(true);
  34. $response = $front->dispatch();
  35. // opérations, comme une historisation...
  36. // et rendu de la réponse:
  37. $response->sendResponse();
  38. ]]></programlisting>
  39. </note>
  40. <para>
  41. Vous ne devriez pas afficher du contenu directement dans un contrôleur. Empiler
  42. plutôt les affichages dans l'objet de réponse&#160;:
  43. </para>
  44. <programlisting language="php"><![CDATA[
  45. // Dans une action d'un contrôleur:
  46. $this->getResponse()
  47. ->setHeader('Content-Type', 'text/html')
  48. ->appendBody($content);
  49. ]]></programlisting>
  50. <para>
  51. Grâce à cela, tous les en-têtes sont envoyés d'un coup, juste avant l'affichage
  52. du contenu.
  53. </para>
  54. <note>
  55. <para>
  56. Si vous utilisez
  57. <link linkend="zend.controller.action.viewintegration">des vues dans vos
  58. action</link>, vous n'avez pas besoin d'ajouter le rendu de la vue dans la réponse,
  59. car <methodname>Zend_Controller_Action::render()</methodname> le fait par
  60. défaut.
  61. </para>
  62. </note>
  63. <para>
  64. Si une exception est ajoutée par le contrôleur frontal à la réponse, utilisez
  65. <methodname>isException()</methodname> pour vérifier ceci, et récupérez les exceptions avec
  66. <methodname>getException()</methodname>. Vous pourriez par exemple créer un objet de réponse
  67. d'erreur, comme un 404, et journaliser l'exception, etc.
  68. </para>
  69. <para>
  70. Pour prendre la main sur l'objet de réponse, demandez le au contrôleur frontal
  71. via un accesseur, ou commandez lui de vous retourner la celle-ci lors après la
  72. distribution.
  73. </para>
  74. <programlisting language="php"><![CDATA[
  75. // récupère la réponse après distribution et affichage:
  76. $front->dispatch();
  77. $response = $front->getResponse();
  78. if ($response->isException()) {
  79. // log, mail, etc...
  80. }
  81. // Demande au contrôleur frontal de ne pas afficher, mais retourner :
  82. $front->returnResponse(true);
  83. $response = $front->dispatch();
  84. // du code ici
  85. // enfin, affichage:
  86. $response->sendResponse();
  87. ]]></programlisting>
  88. <para>
  89. Par défaut, les messages d'exceptions ne sont pas affichés. Utilisez
  90. <methodname>renderExceptions()</methodname> si vous le voulez. Aussi, vous pouvez activer leur
  91. rendu grâce à Zend_Controller_Front::throwExceptions()&#160;:
  92. </para>
  93. <programlisting language="php"><![CDATA[
  94. $response->renderExceptions(true);
  95. $front->dispatch($request, $response);
  96. // ou:
  97. $front->returnResponse(true);
  98. $response = $front->dispatch();
  99. $response->renderExceptions();
  100. $response->sendResponse();
  101. // ou:
  102. $front->throwExceptions(true);
  103. $front->dispatch();
  104. ]]></programlisting>
  105. </sect2>
  106. <sect2 id="zend.controller.response.headers">
  107. <title>Manipulation des en-têtes</title>
  108. <para>
  109. Comme nous l'avons vu, un des rôles de l'objet de réponse est de gérer les
  110. en-têtes <acronym>HTTP</acronym>. Une variété de méthodes permet de contrôler cette gestion&#160;:
  111. </para>
  112. <itemizedlist>
  113. <listitem>
  114. <para>
  115. <methodname>canSendHeaders($throw = false)</methodname> est utilisée pour déterminer
  116. si les en-têtes n'ont pas déjà été envoyés. Si le paramètre optionnel
  117. <varname>$throw</varname> est à <constant>TRUE</constant>, alors une exception sera envoyée
  118. si c'est le cas. L'attribut <code>headersSentThrowsException</code> permet
  119. aussi de gérer ce comportement.
  120. </para>
  121. </listitem>
  122. <listitem>
  123. <para>
  124. <methodname>setHeader($name, $value, $replace = false)</methodname> est utilisée pour
  125. affecter un en-tête unique. Par défaut, il n'écrase un éventuel précédent du
  126. même nom, sauf si <varname>$replace</varname> est mis à <constant>TRUE</constant>.
  127. </para>
  128. <para>
  129. Avant d'affecter un en-tête, cette méthode utilise
  130. <methodname>canSendHeaders()</methodname> pour voir si à ce point l'en-tête peut être
  131. envoyé.
  132. </para>
  133. </listitem>
  134. <listitem>
  135. <para>
  136. <methodname>setRedirect($url, $code = 302)</methodname> envoie un en-tête <acronym>HTTP</acronym>
  137. Location indiquant une redirection. Si un code de statut est passé, il sera
  138. utilisé.
  139. </para>
  140. <para>
  141. En interne, cette méthode appelle <methodname>setHeader()</methodname> avec
  142. <varname>$replace</varname> à <constant>TRUE</constant>, pour s'assurer de l'unicité de cet
  143. en-tête.
  144. </para>
  145. </listitem>
  146. <listitem>
  147. <para>
  148. <methodname>getHeaders()</methodname> retourne un tableau contenant tous les
  149. en-têtes. Chaque élément est un tableau "nom" 'valeur.
  150. </para>
  151. </listitem>
  152. <listitem>
  153. <para><methodname>clearHeaders()</methodname> efface tous les en-têtes enregistrés.</para>
  154. </listitem>
  155. <listitem>
  156. <para>
  157. <methodname>setRawHeader()</methodname> s'utilise pour affecter un en-tête brut,
  158. n'utilisant pas la syntaxe clé/valeur, comme un statut.
  159. </para>
  160. </listitem>
  161. <listitem>
  162. <para>
  163. <methodname>getRawHeaders()</methodname> retourne tous les en-têtes bruts
  164. enregistrés.
  165. </para>
  166. </listitem>
  167. <listitem>
  168. <para>
  169. <methodname>clearRawHeaders()</methodname> efface tous les en-têtes bruts
  170. enregistrés.
  171. </para>
  172. </listitem>
  173. <listitem>
  174. <para>
  175. <methodname>clearAllHeaders()</methodname> efface tous les en-têtes bruts et
  176. réguliers enregistrés.
  177. </para>
  178. </listitem>
  179. </itemizedlist>
  180. <para>
  181. De plus, des accesseurs spéciaux sont disponibles pour manipuler le code de
  182. réponse <acronym>HTTP</acronym>&#160;: <methodname>setHttpResponseCode()</methodname> et
  183. <methodname>getHttpResponseCode()</methodname>.
  184. </para>
  185. </sect2>
  186. <sect2 id="zend.controller.response.namedsegments">
  187. <title>Segments nommés</title>
  188. <para>
  189. L'objet de réponse propose une fragmentation par segments. Ceci permet de séparer
  190. le corps de la réponse dans plusieurs segments réceptacles, que vous pouvez afficher
  191. dans un ordre précis. En interne, il s'agit d'un tableau namespacé qui dispose de
  192. méthodes de manipulation.
  193. </para>
  194. <para>
  195. Par exemple, vous pourriez utiliser l'évènement <methodname>preDispatch()</methodname> pour
  196. rajouter un bandeau de header au corps de la réponse, et l'évènement
  197. <methodname>postDispatch()</methodname> pour en ajouter un bandeau de footer&#160;:
  198. </para>
  199. <programlisting language="php"><![CDATA[
  200. // Considérons ce plugin comme étant enregistré
  201. // auprès du contrôleur frontal
  202. class MyPlugin extends Zend_Controller_Plugin_Abstract
  203. {
  204. public function preDispatch(Zend_Controller_Request_Abstract $request)
  205. {
  206. $response = $this->getResponse();
  207. $view = new Zend_View();
  208. $view->setBasePath('../views/scripts');
  209. $response->prepend('header', $view->render('header.phtml'));
  210. }
  211. public function postDispatch(Zend_Controller_Request_Abstract $request)
  212. {
  213. $response = $this->getResponse();
  214. $view = new Zend_View();
  215. $view->setBasePath('../views/scripts');
  216. $response->append('footer', $view->render('footer.phtml'));
  217. }
  218. }
  219. // un contrôleur d'action
  220. class MyController extends Zend_Controller_Action
  221. {
  222. public function fooAction()
  223. {
  224. $this->render();
  225. }
  226. }
  227. ]]></programlisting>
  228. <para>
  229. Un appel à <code>/my/foo</code> dans ce cas là, générera un objet de réponse
  230. ressemblant à ceci&#160;:
  231. </para>
  232. <programlisting language="php"><![CDATA[
  233. array(
  234. 'header' => ..., // contenu du segment header
  235. 'default' => ..., // corps, contenu de MyController::fooAction()
  236. 'footer' => ... // contenu du segment footer
  237. );
  238. ]]></programlisting>
  239. <para>
  240. Lorsque ceci est rendu, ça l'est dans l'ordre dans lequel les segments sont
  241. rangés dans la réponse.
  242. </para>
  243. <para>
  244. Voici quelques méthodes permettant de manipuler les segments de la
  245. réponse&#160;:
  246. </para>
  247. <itemizedlist>
  248. <listitem>
  249. <para>
  250. <methodname>setBody()</methodname> et <methodname>appendBody()</methodname> effacent et écrivent,
  251. ou rajoutent un contenu à un segment qu'on leur indique en deuxième paramètre
  252. (<varname>$name</varname>). Si celui-ci n'existe pas, il sera crée en fin de pile. Si
  253. le paramètre segment n'est pas défini, alors le segment "default"est
  254. utilisé.
  255. </para>
  256. </listitem>
  257. <listitem>
  258. <para>
  259. <methodname>prepend($name, $content)</methodname> va créer un segment appelé
  260. <varname>$name</varname> et le placé au début du tableau. Si le segment existe, il
  261. sera écrasé.
  262. </para>
  263. </listitem>
  264. <listitem>
  265. <para>
  266. <methodname>append($name, $content)</methodname> va créer un segment appelé
  267. <varname>$name</varname> et le placer à la fin du tableau. Si le segment existe, il
  268. sera écrasé.
  269. </para>
  270. </listitem>
  271. <listitem>
  272. <para>
  273. <methodname>insert($name, $content, $parent = null, $before = false)</methodname> va
  274. créer un segment appelé <varname>$name</varname>. Si <varname>$parent</varname> est
  275. renseigné, le nouveau segment sera placé avant ou après le segment
  276. <varname>$parent</varname>, ceci dépendant de la valeur de <varname>$before</varname>. Si
  277. le segment existe, il sera écrasé.
  278. </para>
  279. </listitem>
  280. <listitem>
  281. <para>
  282. <methodname>clearBody($name = null)</methodname> va vider le contenu du segment qui
  283. lui est passé en paramètre via <varname>$name</varname>. Par défaut, il vide tout le
  284. tableau (détruit tous les segments).
  285. </para>
  286. </listitem>
  287. <listitem>
  288. <para>
  289. <methodname>getBody($spec = false)</methodname> retourne le contenu du segment
  290. <varname>$spec</varname>. Si <varname>$spec</varname> vaut <constant>FALSE</constant>, il retourne
  291. le contenu de tous les segments. Si <constant>TRUE</constant>, c'est le tableau de
  292. segments qui est retourné.
  293. </para>
  294. </listitem>
  295. </itemizedlist>
  296. </sect2>
  297. <sect2 id="zend.controller.response.exceptions">
  298. <title>Manipulation des exceptions dans l'objet de réponse</title>
  299. <para>
  300. Comme déjà mentionné, par défaut, les exceptions rencontrées durant le processus
  301. <acronym>MVC</acronym> de distribution, sont ajoutées à l'objet de réponse. Elles le sont dans une pile,
  302. ce qui vous permet de toutes les garder -- les exceptions d'application, les exceptions
  303. de distribution, les exceptions de plugin -- etc... Si vous voulez manipuler finement
  304. celles-ci, voyez plutôt les méthodes ci-après&#160;:
  305. </para>
  306. <itemizedlist>
  307. <listitem>
  308. <para><methodname>setException(Exception $e)</methodname> enregistre une exception.</para>
  309. </listitem>
  310. <listitem>
  311. <para>
  312. <methodname>isException()</methodname> est utilisée pour déterminer si il existe au
  313. moins une exception.
  314. </para>
  315. </listitem>
  316. <listitem>
  317. <para>
  318. <methodname>getException()</methodname> retourne toutes les exceptions sous forme de
  319. tableau.
  320. </para>
  321. </listitem>
  322. <listitem>
  323. <para>
  324. <methodname>hasExceptionOfType($type)</methodname> sert à déterminer si des
  325. exceptions d'une classe spécifique existent.
  326. </para>
  327. </listitem>
  328. <listitem>
  329. <para>
  330. <methodname>hasExceptionOfMessage($message)</methodname> sert à déterminer si des
  331. exceptions ayant un message spécifique existent.
  332. </para>
  333. </listitem>
  334. <listitem>
  335. <para>
  336. <methodname>hasExceptionOfCode($code)</methodname> sert à déterminer si des
  337. exceptions ayant un code spécifique existent.
  338. </para>
  339. </listitem>
  340. <listitem>
  341. <para>
  342. <methodname>getExceptionByType($type)</methodname> retourne toutes les exceptions
  343. d'une classe spécifique. Un tableau est retourné, ou <constant>FALSE</constant> si
  344. aucun exception ne correspond
  345. </para>
  346. </listitem>
  347. <listitem>
  348. <para>
  349. <methodname>getExceptionByMessage($message)</methodname> retourne toutes les
  350. exceptions ayant un message spécifique. Un tableau est retourné, ou
  351. <constant>FALSE</constant> si aucun exception ne correspond
  352. </para>
  353. </listitem>
  354. <listitem>
  355. <para>
  356. <methodname>getExceptionByCode($code)</methodname> retourne toutes les exceptions
  357. ayant un code spécifique. Un tableau est retourné, ou <constant>FALSE</constant> si
  358. aucun exception ne correspond.
  359. </para>
  360. </listitem>
  361. <listitem>
  362. <para>
  363. <methodname>renderExceptions($flag)</methodname> vous permet de définir si les
  364. exceptions doivent être envoyées lorsque la réponse est rendue.
  365. </para>
  366. </listitem>
  367. </itemizedlist>
  368. </sect2>
  369. <sect2 id="zend.controller.response.subclassing">
  370. <title>Dériver l'objet de réponse</title>
  371. <para>
  372. L'objet de réponse sert à collecter les en-têtes <acronym>HTTP</acronym> de la réponse, ainsi que
  373. son contenu, depuis le système <acronym>MVC</acronym> mais aussi de l'afficher au client. De plus, l'objet
  374. collecte les exceptions et permet de les gérer, de les retourner, ou de les garder sous
  375. silence.
  376. </para>
  377. <para>
  378. La classe de base est <classname>Zend_Controller_Response_Abstract</classname>,
  379. et toute dérivation devra en hériter directement ou indirectement. Les méthodes qu'elle
  380. propose ont été vues dans les sections précédentes.
  381. </para>
  382. <para>
  383. Vous pouvez dériver l'objet de réponse pour plusieurs raisons, incluant la
  384. volonté de modifier le retour de la sortie, pour ne pas envoyer d'en-têtes dans un
  385. environnement de requête CLI ou <acronym>PHP</acronym>-GTK, la gestion de templates, etc.
  386. </para>
  387. </sect2>
  388. </sect1>