Zend_Controller-Exceptions.xml 16 KB

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