MVC AusnahmenEinführung
Die MVC 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.
Trotzdem enthalten Ausnahmemeldungen und Backtrace Informationen oft sensitive Systeminformationen,
wie SQL Anweisungen, Dateiorte, und andere. Um zu helfen die eigene Site zu schützen, werden
standardmäßig alle Ausnahmen von Zend_Controller_Front gefangen und im Antwortobjekt
registriert; zusätzlich zeigt das Antwortobjekt die Ausnahmemeldungen standardmäßig nicht an.
Behandeln von Ausnahmen
Verschiedene Mechanismen sind bereits in die MVC Komponenten eingebaut um die Behandlung von
Ausnahmen zu erlauben.
Standardmäßig ist das
Error Handler Plugin
registriert und aktiv. Dieses Plugin wurde erstellt um folgendes zu behandeln:
Fehler durch fehlende Controller oder Aktionen
Fehler die in Actioncontrollern auftreten
Es arbeitet als postDispatch() 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.
Dieser Handler deckt die meisten Ausnahmesituationen ab, und behandelt fehlende
Controller und Aktionen taktvoll.
Zend_Controller_Front::throwExceptions()
Durch die Übergabe eines boolschen True 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:
throwExceptions(true);
try {
$front->dispatch();
} catch (Exception $e) {
// Ausnahmen selbst behandeln
}
]]>
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.
Zend_Controller_Response_Abstract::renderExceptions()
Durch die Übergabe eines boolschen True 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.
Zend_Controller_Front::returnResponse() und
Zend_Controller_Response_Abstract::isException().
Durch die Übergabe eines boolschen True zu
Zend_Controller_Front::returnResponse(), wird
Zend_Controller_Front::dispatch() 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 isException()
Methode verwendet, und die Ausnahme über die getException() Methode
empfangen wird. Als Beispiel:
returnResponse(true);
$response = $front->dispatch();
if ($response->isException()) {
$exceptions = $response->getException();
// Ausnahme behandeln ...
} else {
$response->sendHeaders();
$response->outputBody();
}
]]>
Der primäre Vorteil die diese Methode über
Zend_Controller_Front::throwExceptions() bietet ist, das Sie es erlaubt
die Antwort wahlweise darzustellen nachdem die Ausnahme behandelt wurde. Das fängt jede
Ausnahme in der Kontrollerkette, im Gegensatz zum Error Handler Plugin.
MVC Ausnahme die auftreten können
Die verschiedenen MVC 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.
Einige Beispiele:Zend_Controller_Dispatcher::dispatch() wird standardmäßig eine Ausnahme werfen
wenn ein ungültiger Controller angefragt wird. Es gibt zwei empfohlene Wege um damit
umzugehen.
Den useDefaultControllerAlways Parameter setzen.
Im eigenen Frontcontroller, oder dem eigenen Dispatcher, die folgende
Anweisung hinzufügen:
setParam('useDefaultControllerAlways', true);
// oder
$dispatcher->setParam('useDefaultControllerAlways', true);
]]>
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.
Die Ausnahme die von dispatch() geworfen wird, ist eine
Zend_Controller_Dispatcher_Exception die den Text
'Invalid controller specified' enthält. Eine der Methoden die in
der vorhergehenden Sektion
beschrieben wurden können verwendet werden um die Ausnahme zu fangen und dann zu
einer generellen Fehlerseite oder der Homepage umzuleiten.
Zend_Controller_Action::__call() wird eine
Zend_Controller_Action_Exception 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:
Eine Subklasse von Zend_Controller_Action erstellen und die
__call() Methode überschreiben. Als Beispiel:
getRequest()->getControllerName();
$url = '/' . $controller . '/index';
return $this->_redirect($url);
}
throw new Exception('Ungültige Methode');
}
}
]]>
Das obige Beispiel fängt jede nicht definierte Aktionsmethode ab die aufgerufen wird
und leitet Sie zur Standardaktion im Controller um.
Eine Subklasse von Zend_Controller_Dispatcher erstellen und die
getAction() Methode überschreiben um zu prüfen ob die Aktion
existiert. Als Beispiel:
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;
}
}
]]>
Der obige Code prüft ob die angefragte Aktion in der Controllerklasse existiert ;
wenn nicht wird die Aktion auf die Standardaktion resetiert.
Diese Methode ist nützlich, weil Sie die Aktion transparent ändert bevor diese
letztendlich dargestellt wird. Trotzdem bedeutet es auch, das Schreibfehler in der
URL trotzdem richtig dargestellt werden, was für die Optimierung von Suchmaschinen
nicht gut ist.
Verwenden von Zend_Controller_Action::preDispatch() oder
Zend_Controller_Plugin_Abstract::preDispatch() um eine ungültige
Aktion zu identifizieren.
Durch das Erstellen einer Subklasse von Zend_Controller_Action und
dem modifizieren von preDispatch(), können alle eigenen Kontroller
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 __call() aus, der oben schon angezeigt
wurde.
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.
Als Beispiel:
getDispatcher();
$class = $dispatcher->getControllerClass($request);
if (!$controller) {
$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;
}
}
}
]]>
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.