| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.exceptions">
- <title>MVC Ausnahmen</title>
- <sect2 id="zend.controller.exceptions.introduction">
- <title>Einführung</title>
- <para>
- Die <acronym>MVC</acronym> Komponenten im Zend Framework verwenden einen Front
- Controller, was bedeutet das alle Anfragen zu einer bestimmten Site über einen
- einzelnen Eintrittspunkt laufen. Als Ergebnis treten alle Ausnahmen eventuell am Front
- Controllerauf, was es Entwicklern erlaubt diese an einem einzelnen Ort zu behandeln.
- </para>
- <para>
- Trotzdem enthalten Ausnahmemeldungen und Backtrace Informationen oft sensitive
- Systeminformationen, wie <acronym>SQL</acronym> Anweisungen, Dateiorte, und andere. Um
- zu helfen die eigene Site zu schützen, werden standardmäßig alle Ausnahmen von
- <classname>Zend_Controller_Front</classname> gefangen und im Antwortobjekt registriert;
- zusätzlich zeigt das Antwortobjekt die Ausnahmemeldungen standardmäßig nicht an.
- </para>
- </sect2>
- <sect2 id="zend.controller.exceptions.handling">
- <title>Behandeln von Ausnahmen</title>
- <para>
- Verschiedene Mechanismen sind bereits in die <acronym>MVC</acronym> Komponenten
- eingebaut um die Behandlung von Ausnahmen zu erlauben.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Standardmäßig ist das
- <link linkend="zend.controller.plugins.standard.errorhandler">Error Handler
- Plugin</link> registriert und aktiv. Dieses Plugin wurde erstellt um
- folgendes zu behandeln:
- </para>
- <itemizedlist>
- <listitem><para>Fehler durch fehlende Controller oder Aktionen</para></listitem>
- <listitem><para>Fehler die in Actioncontrollern auftreten</para></listitem>
- </itemizedlist>
- <para>
- Es arbeitet als <methodname>postDispatch()</methodname> Plugin und prüft ob
- eine Dispatcher, Actioncontroller oder andere Ausnahme aufgetreten ist. Wenn
- das so ist, leitet es an den Error Handler Controller weiter.
- </para>
- <para>
- Dieser Handler deckt die meisten Ausnahmesituationen ab, und behandelt fehlende
- Controller und Aktionen taktvoll.
- </para>
- </listitem>
- <listitem>
- <para><methodname>Zend_Controller_Front::throwExceptions()</methodname></para>
- <para>
- Durch die Übergabe eines boolschen <constant>TRUE</constant> Wertes an diese
- Methode, kann dem Front Controller mitgeteilt werden das, statt der Ansammlung
- der Ausnahmen im Antwortobjekt oder der Verwendung des Error Handler Plugin's,
- man diese Ausnahmen selbst behandeln will. Als Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- $front->throwExceptions(true);
- try {
- $front->dispatch();
- } catch (Exception $e) {
- // Ausnahmen selbst behandeln
- }
- ]]></programlisting>
- <para>
- Diese Methode ist möglicherweise der einfachste Weg um eigene
- Ausnahmebehandlungen hinzuzufügen die den vollen Umfang der möglichen Ausnahmen
- der Front Controller Anwendung behandeln.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>Zend_Controller_Response_Abstract::renderExceptions()</methodname>
- </para>
- <para>
- Durch die Übergabe eines boolschen <constant>TRUE</constant> Wertes an diese
- Methode kann dem Antwortobjekt mitgeteilt werden das es Ausnahmenachrichten und
- Backtrace darstellen soll, wenn es selbst dargestellt wird. In diesem Szenario
- wird jede Ausnahme die an der Anwendung auftritt angezeigt. Das wird nur in
- nicht-produktiven Umgebungen vorgeschlagen.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>Zend_Controller_Front::returnResponse()</methodname> und
- <methodname>Zend_Controller_Response_Abstract::isException()</methodname>.
- </para>
- <para>
- Durch die Übergabe eines boolschen <constant>TRUE</constant> an
- <methodname>Zend_Controller_Front::returnResponse()</methodname>, wird
- <methodname>Zend_Controller_Front::dispatch()</methodname> die Antwort nicht
- darstellen, aber diese stattdessen zurückgeben. Sobald man die antwort hat,
- kann diese getestet werden um zu sehen ob irgendwelche Ausnahmen gefangen
- wurden indem die <methodname>isException()</methodname> Methode verwendet, und
- die Ausnahme über die <methodname>getException()</methodname> Methode empfangen
- wird. Als Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- $front->returnResponse(true);
- $response = $front->dispatch();
- if ($response->isException()) {
- $exceptions = $response->getException();
- // Ausnahme behandeln ...
- } else {
- $response->sendHeaders();
- $response->outputBody();
- }
- ]]></programlisting>
- <para>
- Der primäre Vorteil welche diese Methode über
- <methodname>Zend_Controller_Front::throwExceptions()</methodname> bietet ist,
- das Sie es erlaubt die Antwort wahlweise darzustellen nachdem die Ausnahme
- behandelt wurde. Das fängt jede Ausnahme in der Controllerkette, im Gegensatz
- zum Error Handler Plugin.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.exceptions.internal">
- <title>MVC Ausnahme die auftreten können</title>
- <para>
- Die verschiedenen <acronym>MVC</acronym> Komponenten -- Anfragen, Router, Dispatcher,
- Actioncontroller, und Antwortobjekte -- können alle gelegentlich Ausnahmen werfen.
- Einige Ausnahmen können wahlweise überschrieben werden und andere werden Verwendet um
- dem Entwickler anzuzeigen das die eigene Struktur der Anwendung überdacht werden
- sollte.
- </para>
- <para>Einige Beispiele:</para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>Zend_Controller_Dispatcher::dispatch()</methodname> wird
- standardmäßig eine Ausnahme werfen wenn ein ungültiger Controller angefragt
- wird. Es gibt zwei empfohlene Wege um damit umzugehen.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Den <property>useDefaultControllerAlways</property> Parameter setzen.
- </para>
- <para>
- Im eigenen Frontcontroller, oder dem eigenen Dispatcher, die folgende
- Anweisung hinzufügen:
- </para>
- <programlisting language="php"><![CDATA[
- $front->setParam('useDefaultControllerAlways', true);
- // oder
- $dispatcher->setParam('useDefaultControllerAlways', true);
- ]]></programlisting>
- <para>
- Wenn dieses Flag gesetzt ist, wird der Dispatcher den Standardcontroller
- und die Standardaktion verwenden statt eine Ausnahme zu werfen. Der
- Nachteil dieser Methode ist das jegliche Schreibfehler die ein Benutzer
- macht wenn er auf die Site zugreift, trotzdem aufgelöst werden und die
- Homepage angezeigt wird, was bei der Optimierung von Suchmaschienen
- verherenden Schaden anrichten kann.
- </para>
- </listitem>
- <listitem>
- <para>
- Die Ausnahme die von <methodname>dispatch()</methodname> geworfen wird,
- ist eine <classname>Zend_Controller_Dispatcher_Exception</classname>
- die den Text 'Invalid controller specified' enthält. Eine der Methoden
- die in <link linkend="zend.controller.exceptions.handling">der
- vorhergehenden Sektion</link> beschrieben wurden können verwendet
- werden um die Ausnahme zu fangen und dann zu einer generellen
- Fehlerseite oder der Homepage umzuleiten.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- <methodname>Zend_Controller_Action::__call()</methodname> wird eine
- <classname>Zend_Controller_Action_Exception</classname> geworfen wenn eine nicht
- existierende Aktion einer Methode nicht dargestellt werden kann. Normalerweise
- wird es gewünscht sein in Fällen wie diesen eine Standardaktion im Controller zu
- verwenden. Wege um das zu tun beinhalten:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Eine Subklasse von <classname>Zend_Controller_Action</classname>
- erstellen und die <methodname>__call()</methodname> Methode
- überschreiben. Als Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Controller_Action extends Zend_Controller_Action
- {
- public function __call($method, $args)
- {
- if ('Action' == substr($method, -6)) {
- $controller = $this->getRequest()->getControllerName();
- $url = '/' . $controller . '/index';
- return $this->_redirect($url);
- }
- throw new Exception('Ungültige Methode');
- }
- }
- ]]></programlisting>
- <para>
- Das obige Beispiel fängt jede nicht definierte Aktionsmethode ab die
- aufgerufen wird und leitet Sie zur Standardaktion im Controller um.
- </para>
- </listitem>
- <listitem>
- <para>
- Eine Subklasse von <classname>Zend_Controller_Dispatcher</classname>
- erstellen und die <methodname>getAction()</methodname> Methode
- überschreiben um zu prüfen ob die Aktion existiert. Als Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
- {
- public function getAction($request)
- {
- $action = $request->getActionName();
- if (empty($action)) {
- $action = $this->getDefaultAction();
- $request->setActionName($action);
- $action = $this->formatActionName($action);
- } else {
- $controller = $this->getController();
- $action = $this->formatActionName($action);
- if (!method_exists($controller, $action)) {
- $action = $this->getDefaultAction();
- $request->setActionName($action);
- $action = $this->formatActionName($action);
- }
- }
- return $action;
- }
- }
- ]]></programlisting>
- <para>
- Der obige Code prüft ob die angefragte Aktion in der Controllerklasse
- existiert ; wenn nicht wird die Aktion auf die Standardaktion
- zurückgesetzt.
- </para>
- <para>
- Diese Methode ist nützlich, weil Sie die Aktion transparent ändert bevor
- diese letztendlich dargestellt wird. Trotzdem bedeutet es auch, das
- Schreibfehler in der <acronym>URL</acronym> trotzdem richtig dargestellt
- werden, was für die Optimierung von Suchmaschinen nicht gut ist.
- </para>
- </listitem>
- <listitem>
- <para>
- Verwenden von
- <methodname>Zend_Controller_Action::preDispatch()</methodname> oder
- <methodname>Zend_Controller_Plugin_Abstract::preDispatch()</methodname>
- um eine ungültige Aktion zu identifizieren.
- </para>
- <para>
- Durch das Erstellen einer Subklasse von
- <classname>Zend_Controller_Action</classname> und dem modifizieren von
- <methodname>preDispatch()</methodname>, können alle eigenen Controller
- geändert werden damit Sie an andere Aktionen weiterleiten oder umleiten
- bevor die Aktion letztendlich dargestellt wird. Der Code hierfür schaut
- ähnlich wie der Code für das Überschreiben von
- <methodname>__call()</methodname> aus, der oben schon angezeigt wurde.
- </para>
- <para>
- Alternativ kann diese Information in einem globalen Plugin geprüft
- werden. Das hat den Vorteil das es unabhängig von Actioncontroller ist;
- wenn die eigene Anwendung aus einer Reihe von Actioncontrollern besteht,
- und nicht alle von der gleichen Klasse abgeleitet sind, kann diese
- Methode Kontinuität in der Handhabung der verschiedenen Klassen bringen.
- </para>
- <para>
- Als Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract
- {
- public function preDispatch(Zend_Controller_Request_Abstract $request)
- {
- $front = Zend_Controller_Front::getInstance();
- $dispatcher = $front->getDispatcher();
- $class = $dispatcher->getControllerClass($request);
- if (!$class) {
- $class = $dispatcher->getDefaultControllerClass($request);
- }
- $r = new ReflectionClass($class);
- $action = $dispatcher->getActionMethod($request);
- if (!$r->hasMethod($action)) {
- $defaultAction = $dispatcher->getDefaultAction();
- $controllerName = $request->getControllerName();
- $response = $front->getResponse();
- $response->setRedirect('/' . $controllerName
- . '/' . $defaultAction);
- $response->sendHeaders();
- exit;
- }
- }
- }
- ]]></programlisting>
- <para>
- In diesem Beispiel wird geprüft ob die angefragte Aktion im Controller
- vorhanden ist. Wenn dem nicht so ist, wird auf die Standardaktion im
- Controller umgeleitet und die Ausführung des Sktipts sofort beendet.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </sect2>
- </sect1>
|