Komponenty MVC w Zend Framework używają kontrolera frontowego, co oznacza, że wszystkie żądania do danej strony przechodzą przez pojedynczy punkt. W rezultacie wszystkie wyjątki ostatecznie zbierane są w kontrolerze frontowym, pozwalając programiście na obsłużenie ich w jednym miejscu.
Jakkolwiek, wiadomości o wyjątkach oraz informacje o backtrace
często zawierają wrażliwe informacje o systemie, jak np. zapytania
SQL, informacje o lokacjach plików i wiele innych. Aby pomóc ci
chronić swój serwis, domyślnie Zend_Controller_Front
łapie wszystkie wyjątki i rejestruje je w obiekcie odpowiedzi; z
kolei, obiekt odpowiedzi domyślnie nie wyświetla wiadomości o
wyjątkach.
Obecnie w komponentach MVC wbudowanych jest kilka mechanizmów pozwalających na obsługę wyjątków
Domyślnie rejestrowana i aktywna jest wtyczka obsługi błędów. Ta wtyczka została stworzona aby obsługiwać:
Błędy spowodowane brakującym kontrolerem lub akcją
Błędy występujące wewnątrz akcji kontrolerów
Wtyczka działa w oparciu o metodę postDispatch()
,
i sprawdza czy obiekt uruchamiający, kontroler akcji, lub
inny obiekt wyrzucił wyjątek. Jeśli tak, przekazuje ona
żądanie do kontrolera obsługi błędu.
Ta wtyczka obsłuży większość sytuacji, w których został wyrzucony wyjątek, a także poprawnie obsłuży brakujące kontrolery oraz akcje.
Zend_Controller_Front::throwExceptions()
Przekazująć logiczną wartość true do tej metody, możesz nakazać kontrolerowi frontowemu aby zamiast składować wyjątki w obiekcie odpowiedzi, wyrzucił je, żebyś mógł obsłużyć je samodzielnie. Na przykład:
<?php $front->throwExceptions(true); try { $front->dispatch(); } catch (Exception $e) { // sam obsłuż wyjątki }
Ta metoda jest najprawdopodobniej najłatwiejszym sposobem dodania własnej obsługi wyjątków do twojej aplikacji używającej kontrolera frontowego.
Zend_Controller_Response_Abstract::renderExceptions()
Przekazując logiczną wartość true do tej metody, możesz nakazać obiektowi odpowiedzi aby renderował on wyjątki gdy sam będzie renderowany. W takim scenariuszu, każdy wyjątek wyrzucony w twojej aplikacji będzie wyświetlony. To jest jedynie rekomendowane dla nieprodukcyjnych środowisk.
Zend_Controller_Front::returnResponse()
oraz
Zend_Controller_Response_Abstract::isException()
Przekazanie wartości logicznej true do metody
Zend_Controller_Front::returnResponse()
,
spowoduje, że obiekt
Zend_Controller_Front::dispatch()
nie będzie
renderował odpowiedzi, a zamiast tego ją zwróci. Gdy już
masz odpowiedź, możesz sprawdzić czy są w niej wyjątki
używając metody isException()
, a następnie
odebrać wyjątki używając metody getException()
.
Na przykład:
<?php $front->returnResponse(true); $response = $front->dispatch(); if ($response->isException()) { $exceptions = $response->getException(); // obsługa wyjątków ... } else { $response->sendHeaders(); $response->outputBody(); }
Główną zaletą, dzięki której ta metoda umożliwia więcej niż
Zend_Controller_Front::throwExceptions()
, jest
to, że możesz warunkowo wyświetlać odpowiedź po obsłudze
wyjątków.
Różne komponenty MVC -- obiekt żądania, router, obiekt uruchamiający, kontrolery akcji, oraz obiekt odpowiedzi -- każdy może z różnych przyczyn wyrzucać wyjątki. Niektóre wyjątki mogą być warunkowo nadpisane, a inne są używane aby wskazać programiście potrzebę poprawienia aplikacji.
Kilka przykładów:
Zend_Controller_Dispatcher::dispatch()
domyślnie wyrzuci wyjątek jeśli zażądano nieprawidłowego
kontrolera. Są dwa zalecane sposoby na obsłużenie tego:
Ustawienie parametru useDefaultControllerAlways
.
W twoim kontrolerze frontowym, lub w obiekcie uruchamiającym, dodaj poniższą dyrektywę:
<?php $front->setParam('useDefaultControllerAlways', true); // lub $dispatcher->setParam('useDefaultControllerAlways', true);
Gdy ta flaga jest ustawiona, obiekt uruchamiający, użyje domyślnego kontrolera oraz akcji zamiast wyrzucania wyjątku. Minusem użycia tej metody jest to, że jakikolwiek błąd literowy w adresie dostępowym do twojej strony spowoduje wyświetlenie strony głównej, co może źle wpłynąć na optymalizację serwisu dla wyszukiwarek internetowych.
Wyjątek wyrzucany przez metodę dispatch()
jest wyjątkiem Zend_Controller_Dispatcher_Exception
zawierającym tekst 'Invalid controller specified'.
Użyj jednej z metod opisanych w poprzedniej
sekcji aby złapać wyjątek, a następnie
przekierować do strony błędu lub do strony głownej.
Metoda Zend_Controller_Action::__call()
wyrzuci
wyjątek Zend_Controller_Action_Exception
jeśli nie może uruchomić nieistniejącej metody akcji.
Najczęściej będziesz chciał użyć jakiejś domyślnej akcji
w kontrolerze w tego typu sprawach. Przykładowe metody
za pomocą których możesz to osiśgnąć:
Rozszerzenie klasy Zend_Controller_Action
i nadpisanie metody __call()
. Na przykład:
<?php 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('Invalid method'); } }
Powyższa metoda przechwytuje wszystkie wywołane niezdefiniowane akcje i przekierowuje żądanie do domyślnej akcji w kontrolerze.
Rozszerzenie klasy Zend_Controller_Dispatcher
o
nadpisanie metody getAction()
, ktora sprawdza czy
akcja istnieje. Na przykład:
<?php 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; } }
Powyższy kod sprawdza czy zażądana akcja istnieje w klasie kontrolera; jeśli nie, resetuje akcję do akcji domyślnej.
Ta metoda jest wygodna ponieważ możesz w niewidoczny sposób zmienić akcję przed ostatecznym uruchomieniem. Jednak to także oznacza, że jakikolwiek błąd literowy w adresie URL może wciąż uruchomić żądanie poprawnie, co nie jest zbyt dobre dla optymalizacji dla wyszukiwarek internetowych.
Użycie metody Zend_Controller_Action::preDispatch()
lub Zend_Controller_Plugin_Abstract::preDispatch()
do zidentyfikowania nieprawidłowych akcji.
Rozszerzając klasę Zend_Controller_Action
i
modyfikując metodę preDispatch()
, możesz
zmodyfikować wszystkie twoje kontrolery w taki
sposób, aby przenosiły one żądanie do innej akcji
lub przekierowywały zamiast uruchamiać akcję.
Kod wyglądałby podobnie kod nadpisujący metodę
__call()
, który został przedstawiony wyżej.
Alternatywnie, możesz sprawdzać te informacje we wtyczce globalnej. Zaletą tego rozwiązania jest to, że kontroler akcji staje się niezależny; jeśli twoja aplikacja składa się z różnorodnych kontrolerów akcji i nie wszystkie dziedziczą z tej samej klasy, ta metoda może dodać konsekwencji w obsłudze różnych klas.
Przykład:
<?php class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract { public function preDispatch(Zend_Controller_Request_Abstract $request) { $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher(); $controller = $dispatcher->getController($request); if (!$controller) { $controller = $dispatcher->getDefaultControllerName($request); } $action = $dispatcher->getAction($request); if (!method_exists($controller, $action)) { $defaultAction = $dispatcher->getDefaultAction(); $controllerName = $request->getControllerName(); $response = Zend_Controller_Front::getInstance()->getResponse(); $response->setRedirect('/' . $controllerName . '/' . $defaultAction); $response->sendHeaders(); exit; } } }
W tym przykładzie sprawdzamy czy zażądana akcja jest dostępna w kontrolerze. Jeśli nie, przekierujemy żądanie do domyślnej akcji w kontrolerze, i kończymy wykonywanie skryptu.