Zend_Controller-Exceptions.xml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 15850 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.controller.exceptions">
  5. <title>MVC Ausnahmen</title>
  6. <sect2 id="zend.controller.exceptions.introduction">
  7. <title>Einführung</title>
  8. <para>
  9. Die MVC Komponenten im Zend Framework verwenden einen Front Controller, was bedeutet das
  10. alle Anfragen zu einer bestimmten Site über einen einzelnen Eintrittspunkt laufen. Als
  11. Ergebnis treten alle Ausnahmen eventuell am Front Controllerauf, was es Entwicklern
  12. erlaubt diese an einem einzelnen Ort zu behandeln.
  13. </para>
  14. <para>
  15. Trotzdem enthalten Ausnahmemeldungen und Backtrace Informationen oft sensitive
  16. Systeminformationen, wie SQL Anweisungen, Dateiorte, und andere. Um zu helfen die eigene
  17. Site zu schützen, werden standardmäßig alle Ausnahmen von
  18. <classname>Zend_Controller_Front</classname> gefangen und im Antwortobjekt registriert;
  19. zusätzlich zeigt das Antwortobjekt die Ausnahmemeldungen standardmäßig nicht an.
  20. </para>
  21. </sect2>
  22. <sect2 id="zend.controller.exceptions.handling">
  23. <title>Behandeln von Ausnahmen</title>
  24. <para>
  25. Verschiedene Mechanismen sind bereits in die MVC Komponenten eingebaut um die Behandlung
  26. von Ausnahmen zu erlauben.
  27. </para>
  28. <itemizedlist>
  29. <listitem>
  30. <para>
  31. Standardmäßig ist das
  32. <link linkend="zend.controller.plugins.standard.errorhandler">Error Handler
  33. Plugin</link> registriert und aktiv. Dieses Plugin wurde erstellt um
  34. folgendes zu behandeln:
  35. </para>
  36. <itemizedlist>
  37. <listitem>
  38. <para>
  39. Fehler durch fehlende Controller oder Aktionen
  40. </para>
  41. </listitem>
  42. <listitem>
  43. <para>
  44. Fehler die in Actioncontrollern auftreten
  45. </para>
  46. </listitem>
  47. </itemizedlist>
  48. <para>
  49. Es arbeitet als <code>postDispatch()</code> Plugin und prüft ob eine Dispatcher,
  50. Actioncontroller oder andere Ausnahme aufgetreten ist. Wenn das so ist, leitet
  51. es an den Error Handler Controller weiter.
  52. </para>
  53. <para>
  54. Dieser Handler deckt die meisten Ausnahmesituationen ab, und behandelt fehlende
  55. Controller und Aktionen taktvoll.
  56. </para>
  57. </listitem>
  58. <listitem>
  59. <para><classname>Zend_Controller_Front::throwExceptions()</classname></para>
  60. <para>
  61. Durch die Übergabe eines boolschen True Wertes an diese Methode, kann dem Front
  62. Controller mitgeteilt werden das, statt der Ansammlung der Ausnahmen im
  63. Antwortobjekt oder der Verwendung des Error Handler Plugin's, man diese
  64. Ausnahmen selbst behandeln will. Als Beispiel:
  65. </para>
  66. <programlisting language="php"><![CDATA[
  67. $front->throwExceptions(true);
  68. try {
  69. $front->dispatch();
  70. } catch (Exception $e) {
  71. // Ausnahmen selbst behandeln
  72. }
  73. ]]></programlisting>
  74. <para>
  75. Diese Methode ist möglicherweise der einfachste Weg um eigene
  76. Ausnahmebehandlungen hinzuzufügen die den vollen Umfang der möglichen Ausnahmen
  77. der Front Controller Anwendung behandeln.
  78. </para>
  79. </listitem>
  80. <listitem>
  81. <para>
  82. <classname>Zend_Controller_Response_Abstract::renderExceptions()</classname>
  83. </para>
  84. <para>
  85. Durch die Übergabe eines boolschen True Wertes an diese Methode kann dem
  86. Antwortobjekt mitgeteilt werden das es Ausnahmenachrichten und Backtrace
  87. darstellen soll, wenn es selbst dargestellt wird. In diesem Szenario wird jede
  88. Ausnahme die an der Anwendung auftritt angezeigt. Das wird nur in
  89. nicht-produktiven Umgebungen vorgeschlagen.
  90. </para>
  91. </listitem>
  92. <listitem>
  93. <para>
  94. <classname>Zend_Controller_Front::returnResponse()</classname> und
  95. <classname>Zend_Controller_Response_Abstract::isException()</classname>.
  96. </para>
  97. <para>
  98. Durch die Übergabe eines boolschen True zu
  99. <classname>Zend_Controller_Front::returnResponse()</classname>, wird
  100. <classname>Zend_Controller_Front::dispatch()</classname> die Antwort nicht
  101. darstellen, aber diese stattdessen zurückgeben. Sobald man die antwort hat, kann
  102. diese getestet werden um zu sehen ob irgendwelche Ausnahmen gefangen wurden
  103. indem die <code>isException()</code> Methode verwendet, und die Ausnahme über
  104. die <code>getException()</code> Methode empfangen wird. Als Beispiel:
  105. </para>
  106. <programlisting language="php"><![CDATA[
  107. $front->returnResponse(true);
  108. $response = $front->dispatch();
  109. if ($response->isException()) {
  110. $exceptions = $response->getException();
  111. // Ausnahme behandeln ...
  112. } else {
  113. $response->sendHeaders();
  114. $response->outputBody();
  115. }
  116. ]]></programlisting>
  117. <para>
  118. Der primäre Vorteil die diese Methode über
  119. <classname>Zend_Controller_Front::throwExceptions()</classname> bietet ist, das
  120. Sie es erlaubt die Antwort wahlweise darzustellen nachdem die Ausnahme behandelt
  121. wurde. Das fängt jede Ausnahme in der Kontrollerkette, im Gegensatz zum Error
  122. Handler Plugin.
  123. </para>
  124. </listitem>
  125. </itemizedlist>
  126. </sect2>
  127. <sect2 id="zend.controller.exceptions.internal">
  128. <title>MVC Ausnahme die auftreten können</title>
  129. <para>
  130. Die verschiedenen MVC Komponenten -- Anfragen, Router, Dispatcher, Actioncontroller, und
  131. Antwortobjekte -- können alle gelegentlich Ausnahmen werfen. Einige Ausnahmen können
  132. wahlweise überschrieben werden und andere werden Verwendet um dem Entwickler anzuzeigen
  133. das die eigene Struktur der Anwendung überdacht werden sollte.
  134. </para>
  135. <para>Einige Beispiele:</para>
  136. <itemizedlist>
  137. <listitem>
  138. <para>
  139. <classname>Zend_Controller_Dispatcher::dispatch()</classname> wird standardmäßig
  140. eine Ausnahme werfen wenn ein ungültiger Controller angefragt wird. Es gibt zwei
  141. empfohlene Wege um damit umzugehen.
  142. </para>
  143. <itemizedlist>
  144. <listitem>
  145. <para>Den <code>useDefaultControllerAlways</code> Parameter setzen.</para>
  146. <para>
  147. Im eigenen Frontcontroller, oder dem eigenen Dispatcher, die folgende
  148. Anweisung hinzufügen:
  149. </para>
  150. <programlisting language="php"><![CDATA[
  151. $front->setParam('useDefaultControllerAlways', true);
  152. // oder
  153. $dispatcher->setParam('useDefaultControllerAlways', true);
  154. ]]></programlisting>
  155. <para>
  156. Wenn dieses Flag gesetzt ist, wird der Dispatcher den Standardcontroller
  157. und die Standardaktion verwenden statt eine Ausnahme zu werfen. Der
  158. Nachteil dieser Methode ist das jegliche Schreibfehler die ein Benutzer
  159. macht wenn er auf die Site zugreift, trotzdem aufgelöst werden und die
  160. Homepage angezeigt wird, was bei der Optimierung von Suchmaschienen
  161. verherenden Schaden anrichten kann.
  162. </para>
  163. </listitem>
  164. <listitem>
  165. <para>
  166. Die Ausnahme die von <code>dispatch()</code> geworfen wird, ist eine
  167. <classname>Zend_Controller_Dispatcher_Exception</classname> die den Text
  168. 'Invalid controller specified' enthält. Eine der Methoden die in
  169. <link linkend="zend.controller.exceptions.handling">der vorhergehenden
  170. Sektion</link> beschrieben wurden können verwendet werden um die
  171. Ausnahme zu fangen und dann zu einer generellen Fehlerseite oder der
  172. Homepage umzuleiten.
  173. </para>
  174. </listitem>
  175. </itemizedlist>
  176. </listitem>
  177. <listitem>
  178. <para>
  179. <classname>Zend_Controller_Action::__call()</classname> wird eine
  180. <classname>Zend_Controller_Action_Exception</classname> geworfen wenn eine nicht
  181. existierende Aktion einer Methode nicht dargestellt werden kann. Normalerweise
  182. wird es gewünscht sein in Fällen wie diesen eine Standardaktion im Controller zu
  183. verwenden. Wege um das zu tun beinhalten:
  184. </para>
  185. <itemizedlist>
  186. <listitem>
  187. <para>
  188. Eine Subklasse von <classname>Zend_Controller_Action</classname>
  189. erstellen und die <code>__call()</code> Methode überschreiben. Als
  190. Beispiel:
  191. </para>
  192. <programlisting language="php"><![CDATA[
  193. class My_Controller_Action extends Zend_Controller_Action
  194. {
  195. public function __call($method, $args)
  196. {
  197. if ('Action' == substr($method, -6)) {
  198. $controller = $this->getRequest()->getControllerName();
  199. $url = '/' . $controller . '/index';
  200. return $this->_redirect($url);
  201. }
  202. throw new Exception('Ungültige Methode');
  203. }
  204. }
  205. ]]></programlisting>
  206. <para>
  207. Das obige Beispiel fängt jede nicht definierte Aktionsmethode ab die
  208. aufgerufen wird und leitet Sie zur Standardaktion im Controller um.
  209. </para>
  210. </listitem>
  211. <listitem>
  212. <para>
  213. Eine Subklasse von <classname>Zend_Controller_Dispatcher</classname>
  214. erstellen und die <code>getAction()</code> Methode überschreiben um zu
  215. prüfen ob die Aktion existiert. Als Beispiel:
  216. </para>
  217. <programlisting language="php"><![CDATA[
  218. class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
  219. {
  220. public function getAction($request)
  221. {
  222. $action = $request->getActionName();
  223. if (empty($action)) {
  224. $action = $this->getDefaultAction();
  225. $request->setActionName($action);
  226. $action = $this->formatActionName($action);
  227. } else {
  228. $controller = $this->getController();
  229. $action = $this->formatActionName($action);
  230. if (!method_exists($controller, $action)) {
  231. $action = $this->getDefaultAction();
  232. $request->setActionName($action);
  233. $action = $this->formatActionName($action);
  234. }
  235. }
  236. return $action;
  237. }
  238. }
  239. ]]></programlisting>
  240. <para>
  241. Der obige Code prüft ob die angefragte Aktion in der Controllerklasse
  242. existiert ; wenn nicht wird die Aktion auf die Standardaktion resetiert.
  243. </para>
  244. <para>
  245. Diese Methode ist nützlich, weil Sie die Aktion transparent ändert bevor
  246. diese letztendlich dargestellt wird. Trotzdem bedeutet es auch, das
  247. Schreibfehler in der URL trotzdem richtig dargestellt werden, was für
  248. die Optimierung von Suchmaschinen nicht gut ist.
  249. </para>
  250. </listitem>
  251. <listitem>
  252. <para>
  253. Verwenden von
  254. <classname>Zend_Controller_Action::preDispatch()</classname> oder
  255. <classname>Zend_Controller_Plugin_Abstract::preDispatch()</classname> um
  256. eine ungültige Aktion zu identifizieren.
  257. </para>
  258. <para>
  259. Durch das Erstellen einer Subklasse von
  260. <classname>Zend_Controller_Action</classname> und dem modifizieren von
  261. <code>preDispatch()</code>, können alle eigenen Kontroller geändert
  262. werden damit Sie an andere Aktionen weiterleiten oder umleiten bevor die
  263. Aktion letztendlich dargestellt wird. Der Code hierfür schaut ähnlich
  264. wie der Code für das Überschreiben von <code>__call()</code> aus, der
  265. oben schon angezeigt wurde.
  266. </para>
  267. <para>
  268. Alternativ kann diese Information in einem globalen Plugin geprüft
  269. werden. Das hat den Vorteil das es unabhängig von Actioncontroller ist;
  270. wenn die eigene Anwendung aus einer Reihe von Actioncontrollern besteht,
  271. und nicht alle von der gleichen Klasse abgeleitet sind, kann diese
  272. Methode Kontinuität in der Handhabung der verschiedenen Klassen bringen.
  273. </para>
  274. <para>
  275. Als Beispiel:
  276. </para>
  277. <programlisting language="php"><![CDATA[
  278. class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract
  279. {
  280. public function preDispatch(Zend_Controller_Request_Abstract $request)
  281. {
  282. $front = Zend_Controller_Front::getInstance();
  283. $dispatcher = $front->getDispatcher();
  284. $class = $dispatcher->getControllerClass($request);
  285. if (!$controller) {
  286. $class = $dispatcher->getDefaultControllerClass($request);
  287. }
  288. $r = new ReflectionClass($class);
  289. $action = $dispatcher->getActionMethod($request);
  290. if (!$r->hasMethod($action)) {
  291. $defaultAction = $dispatcher->getDefaultAction();
  292. $controllerName = $request->getControllerName();
  293. $response = $front->getResponse();
  294. $response->setRedirect('/' . $controllerName
  295. . '/' . $defaultAction);
  296. $response->sendHeaders();
  297. exit;
  298. }
  299. }
  300. }
  301. ]]></programlisting>
  302. <para>
  303. In diesem Beispiel wird geprüft ob die angefragte Aktion im Controller
  304. vorhanden ist. Wenn dem nicht so ist, wird auf die Standardaktion im
  305. Controller umgeleitet und die Ausführung des Sktipts sofort beendet.
  306. </para>
  307. </listitem>
  308. </itemizedlist>
  309. </listitem>
  310. </itemizedlist>
  311. </sect2>
  312. </sect1>
  313. <!--
  314. vim:se ts=4 sw=4 et:
  315. -->