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.