Zend_Controller-Exceptions.xml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 16658 -->
  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>
  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 <methodname>postDispatch()</methodname> Plugin und prüft ob
  50. eine Dispatcher, Actioncontroller oder andere Ausnahme aufgetreten ist. Wenn
  51. das so ist, leitet 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><methodname>Zend_Controller_Front::throwExceptions()</methodname></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. <methodname>Zend_Controller_Response_Abstract::renderExceptions()</methodname>
  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. <methodname>Zend_Controller_Front::returnResponse()</methodname> und
  95. <methodname>Zend_Controller_Response_Abstract::isException()</methodname>.
  96. </para>
  97. <para>
  98. Durch die Übergabe eines boolschen True an
  99. <methodname>Zend_Controller_Front::returnResponse()</methodname>, wird
  100. <methodname>Zend_Controller_Front::dispatch()</methodname> die Antwort nicht
  101. darstellen, aber diese stattdessen zurückgeben. Sobald man die antwort hat,
  102. kann diese getestet werden um zu sehen ob irgendwelche Ausnahmen gefangen
  103. wurden indem die <methodname>isException()</methodname> Methode verwendet, und
  104. die Ausnahme über die <methodname>getException()</methodname> Methode empfangen
  105. wird. Als Beispiel:
  106. </para>
  107. <programlisting language="php"><![CDATA[
  108. $front->returnResponse(true);
  109. $response = $front->dispatch();
  110. if ($response->isException()) {
  111. $exceptions = $response->getException();
  112. // Ausnahme behandeln ...
  113. } else {
  114. $response->sendHeaders();
  115. $response->outputBody();
  116. }
  117. ]]></programlisting>
  118. <para>
  119. Der primäre Vorteil die diese Methode über
  120. <methodname>Zend_Controller_Front::throwExceptions()</methodname> bietet ist,
  121. das Sie es erlaubt die Antwort wahlweise darzustellen nachdem die Ausnahme
  122. behandelt wurde. Das fängt jede Ausnahme in der Kontrollerkette, im Gegensatz
  123. zum Error Handler Plugin.
  124. </para>
  125. </listitem>
  126. </itemizedlist>
  127. </sect2>
  128. <sect2 id="zend.controller.exceptions.internal">
  129. <title>MVC Ausnahme die auftreten können</title>
  130. <para>
  131. Die verschiedenen <acronym>MVC</acronym> Komponenten -- Anfragen, Router, Dispatcher,
  132. Actioncontroller, und Antwortobjekte -- können alle gelegentlich Ausnahmen werfen.
  133. Einige Ausnahmen können wahlweise überschrieben werden und andere werden Verwendet um
  134. dem Entwickler anzuzeigen das die eigene Struktur der Anwendung überdacht werden
  135. sollte.
  136. </para>
  137. <para>Einige Beispiele:</para>
  138. <itemizedlist>
  139. <listitem>
  140. <para>
  141. <methodname>Zend_Controller_Dispatcher::dispatch()</methodname> wird
  142. standardmäßig eine Ausnahme werfen wenn ein ungültiger Controller angefragt
  143. wird. Es gibt zwei empfohlene Wege um damit umzugehen.
  144. </para>
  145. <itemizedlist>
  146. <listitem>
  147. <para>
  148. Den <property>useDefaultControllerAlways</property> Parameter setzen.
  149. </para>
  150. <para>
  151. Im eigenen Frontcontroller, oder dem eigenen Dispatcher, die folgende
  152. Anweisung hinzufügen:
  153. </para>
  154. <programlisting language="php"><![CDATA[
  155. $front->setParam('useDefaultControllerAlways', true);
  156. // oder
  157. $dispatcher->setParam('useDefaultControllerAlways', true);
  158. ]]></programlisting>
  159. <para>
  160. Wenn dieses Flag gesetzt ist, wird der Dispatcher den Standardcontroller
  161. und die Standardaktion verwenden statt eine Ausnahme zu werfen. Der
  162. Nachteil dieser Methode ist das jegliche Schreibfehler die ein Benutzer
  163. macht wenn er auf die Site zugreift, trotzdem aufgelöst werden und die
  164. Homepage angezeigt wird, was bei der Optimierung von Suchmaschienen
  165. verherenden Schaden anrichten kann.
  166. </para>
  167. </listitem>
  168. <listitem>
  169. <para>
  170. Die Ausnahme die von <methodname>dispatch()</methodname> geworfen wird,
  171. ist eine <classname>Zend_Controller_Dispatcher_Exception</classname>
  172. die den Text 'Invalid controller specified' enthält. Eine der Methoden
  173. die in <link linkend="zend.controller.exceptions.handling">der
  174. vorhergehenden Sektion</link> beschrieben wurden können verwendet
  175. werden um die Ausnahme zu fangen und dann zu einer generellen
  176. Fehlerseite oder der Homepage umzuleiten.
  177. </para>
  178. </listitem>
  179. </itemizedlist>
  180. </listitem>
  181. <listitem>
  182. <para>
  183. <methodname>Zend_Controller_Action::__call()</methodname> wird eine
  184. <classname>Zend_Controller_Action_Exception</classname> geworfen wenn eine nicht
  185. existierende Aktion einer Methode nicht dargestellt werden kann. Normalerweise
  186. wird es gewünscht sein in Fällen wie diesen eine Standardaktion im Controller zu
  187. verwenden. Wege um das zu tun beinhalten:
  188. </para>
  189. <itemizedlist>
  190. <listitem>
  191. <para>
  192. Eine Subklasse von <classname>Zend_Controller_Action</classname>
  193. erstellen und die <methodname>__call()</methodname> Methode
  194. überschreiben. Als Beispiel:
  195. </para>
  196. <programlisting language="php"><![CDATA[
  197. class My_Controller_Action extends Zend_Controller_Action
  198. {
  199. public function __call($method, $args)
  200. {
  201. if ('Action' == substr($method, -6)) {
  202. $controller = $this->getRequest()->getControllerName();
  203. $url = '/' . $controller . '/index';
  204. return $this->_redirect($url);
  205. }
  206. throw new Exception('Ungültige Methode');
  207. }
  208. }
  209. ]]></programlisting>
  210. <para>
  211. Das obige Beispiel fängt jede nicht definierte Aktionsmethode ab die
  212. aufgerufen wird und leitet Sie zur Standardaktion im Controller um.
  213. </para>
  214. </listitem>
  215. <listitem>
  216. <para>
  217. Eine Subklasse von <classname>Zend_Controller_Dispatcher</classname>
  218. erstellen und die <methodname>getAction()</methodname> Methode
  219. überschreiben um zu prüfen ob die Aktion existiert. Als Beispiel:
  220. </para>
  221. <programlisting language="php"><![CDATA[
  222. class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
  223. {
  224. public function getAction($request)
  225. {
  226. $action = $request->getActionName();
  227. if (empty($action)) {
  228. $action = $this->getDefaultAction();
  229. $request->setActionName($action);
  230. $action = $this->formatActionName($action);
  231. } else {
  232. $controller = $this->getController();
  233. $action = $this->formatActionName($action);
  234. if (!method_exists($controller, $action)) {
  235. $action = $this->getDefaultAction();
  236. $request->setActionName($action);
  237. $action = $this->formatActionName($action);
  238. }
  239. }
  240. return $action;
  241. }
  242. }
  243. ]]></programlisting>
  244. <para>
  245. Der obige Code prüft ob die angefragte Aktion in der Controllerklasse
  246. existiert ; wenn nicht wird die Aktion auf die Standardaktion resetiert.
  247. </para>
  248. <para>
  249. Diese Methode ist nützlich, weil Sie die Aktion transparent ändert bevor
  250. diese letztendlich dargestellt wird. Trotzdem bedeutet es auch, das
  251. Schreibfehler in der <acronym>URL</acronym> trotzdem richtig dargestellt
  252. werden, was für die Optimierung von Suchmaschinen nicht gut ist.
  253. </para>
  254. </listitem>
  255. <listitem>
  256. <para>
  257. Verwenden von
  258. <methodname>Zend_Controller_Action::preDispatch()</methodname> oder
  259. <methodname>Zend_Controller_Plugin_Abstract::preDispatch()</methodname>
  260. um eine ungültige Aktion zu identifizieren.
  261. </para>
  262. <para>
  263. Durch das Erstellen einer Subklasse von
  264. <classname>Zend_Controller_Action</classname> und dem modifizieren von
  265. <methodname>preDispatch()</methodname>, können alle eigenen Kontroller
  266. geändert werden damit Sie an andere Aktionen weiterleiten oder umleiten
  267. bevor die Aktion letztendlich dargestellt wird. Der Code hierfür schaut
  268. ähnlich wie der Code für das Überschreiben von
  269. <methodname>__call()</methodname> aus, der oben schon angezeigt wurde.
  270. </para>
  271. <para>
  272. Alternativ kann diese Information in einem globalen Plugin geprüft
  273. werden. Das hat den Vorteil das es unabhängig von Actioncontroller ist;
  274. wenn die eigene Anwendung aus einer Reihe von Actioncontrollern besteht,
  275. und nicht alle von der gleichen Klasse abgeleitet sind, kann diese
  276. Methode Kontinuität in der Handhabung der verschiedenen Klassen bringen.
  277. </para>
  278. <para>
  279. Als Beispiel:
  280. </para>
  281. <programlisting language="php"><![CDATA[
  282. class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract
  283. {
  284. public function preDispatch(Zend_Controller_Request_Abstract $request)
  285. {
  286. $front = Zend_Controller_Front::getInstance();
  287. $dispatcher = $front->getDispatcher();
  288. $class = $dispatcher->getControllerClass($request);
  289. if (!$controller) {
  290. $class = $dispatcher->getDefaultControllerClass($request);
  291. }
  292. $r = new ReflectionClass($class);
  293. $action = $dispatcher->getActionMethod($request);
  294. if (!$r->hasMethod($action)) {
  295. $defaultAction = $dispatcher->getDefaultAction();
  296. $controllerName = $request->getControllerName();
  297. $response = $front->getResponse();
  298. $response->setRedirect('/' . $controllerName
  299. . '/' . $defaultAction);
  300. $response->sendHeaders();
  301. exit;
  302. }
  303. }
  304. }
  305. ]]></programlisting>
  306. <para>
  307. In diesem Beispiel wird geprüft ob die angefragte Aktion im Controller
  308. vorhanden ist. Wenn dem nicht so ist, wird auf die Standardaktion im
  309. Controller umgeleitet und die Ausführung des Sktipts sofort beendet.
  310. </para>
  311. </listitem>
  312. </itemizedlist>
  313. </listitem>
  314. </itemizedlist>
  315. </sect2>
  316. </sect1>
  317. <!--
  318. vim:se ts=4 sw=4 et:
  319. -->