Zend_Controller-Exceptions.xml 16 KB

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