1 <sect1 id="zend.controller.exceptions">
2 <title>Wyjątki MVC</title>
4 <sect2 id="zend.controller.exceptions.introduction">
5 <title>Wprowadzenie</title>
8 Komponenty MVC w Zend Framework używają kontrolera frontowego, co
9 oznacza, że wszystkie żądania do danej strony przechodzą przez
10 pojedynczy punkt. W rezultacie wszystkie wyjątki ostatecznie
11 zbierane są w kontrolerze frontowym, pozwalając programiście na
12 obsłużenie ich w jednym miejscu.
16 Jakkolwiek, wiadomości o wyjątkach oraz informacje o backtrace
17 często zawierają wrażliwe informacje o systemie, jak np. zapytania
18 SQL, informacje o lokacjach plików i wiele innych. Aby pomóc ci
19 chronić swój serwis, domyślnie <code>Zend_Controller_Front</code>
20 łapie wszystkie wyjątki i rejestruje je w obiekcie odpowiedzi; z
21 kolei, obiekt odpowiedzi domyślnie nie wyświetla wiadomości o
26 <sect2 id="zend.controller.exceptions.handling">
27 <title>W jaki sposób możesz obsługiwać wyjątki?</title>
30 Obecnie w komponentach MVC wbudowanych jest kilka mechanizmów
31 pozwalających na obsługę wyjątków
37 Domyślnie rejestrowana i aktywna jest <link
38 linkend="zend.controller.plugins.standard.errorhandler">wtyczka
39 obsługi błędów</link>. Ta wtyczka została stworzona aby
44 <listitem><para>Błędy spowodowane brakującym kontrolerem lub akcją</para></listitem>
46 <listitem><para>Błędy występujące wewnątrz akcji kontrolerów</para></listitem>
50 Wtyczka działa w oparciu o metodę <code>postDispatch()</code>,
51 i sprawdza czy obiekt uruchamiający, kontroler akcji, lub
52 inny obiekt wyrzucił wyjątek. Jeśli tak, przekazuje ona
53 żądanie do kontrolera obsługi błędu.
57 Ta wtyczka obsłuży większość sytuacji, w których został
58 wyrzucony wyjątek, a także poprawnie obsłuży brakujące
59 kontrolery oraz akcje.
64 <para><code>Zend_Controller_Front::throwExceptions()</code></para>
67 Przekazująć logiczną wartość true do tej metody, możesz
68 nakazać kontrolerowi frontowemu aby zamiast składować
69 wyjątki w obiekcie odpowiedzi, wyrzucił je, żebyś mógł
70 obsłużyć je samodzielnie. Na przykład:
73 <programlisting role="php"><![CDATA[
74 $front->throwExceptions(true);
77 } catch (Exception $e) {
84 Ta metoda jest najprawdopodobniej najłatwiejszym sposobem
85 dodania własnej obsługi wyjątków do twojej aplikacji
86 używającej kontrolera frontowego.
91 <para><code>Zend_Controller_Response_Abstract::renderExceptions()</code></para>
94 Przekazując logiczną wartość true do tej metody, możesz
95 nakazać obiektowi odpowiedzi aby renderował on wyjątki gdy
96 sam będzie renderowany. W takim scenariuszu, każdy wyjątek
97 wyrzucony w twojej aplikacji będzie wyświetlony. To jest
98 jedynie rekomendowane dla nieprodukcyjnych środowisk.
104 <code>Zend_Controller_Front::returnResponse()</code> oraz
105 <code>Zend_Controller_Response_Abstract::isException()</code>
109 Przekazanie wartości logicznej true do metody
110 <code>Zend_Controller_Front::returnResponse()</code>,
112 <code>Zend_Controller_Front::dispatch()</code> nie będzie
113 renderował odpowiedzi, a zamiast tego ją zwróci. Gdy już
114 masz odpowiedź, możesz sprawdzić czy są w niej wyjątki
115 używając metody <code>isException()</code>, a następnie
116 odebrać wyjątki używając metody <code>getException()</code>.
120 <programlisting role="php"><![CDATA[
121 $front->returnResponse(true);
122 $response = $front->dispatch();
123 if ($response->isException()) {
124 $exceptions = $response->getException();
125 // obsługa wyjątków ...
127 $response->sendHeaders();
128 $response->outputBody();
134 Główną zaletą, dzięki której ta metoda umożliwia więcej niż
135 <code>Zend_Controller_Front::throwExceptions()</code>, jest
136 to, że możesz warunkowo wyświetlać odpowiedź po obsłudze
143 <sect2 id="zend.controller.exceptions.internal">
144 <title>Wyjątki MVC które możesz napotkać</title>
147 Różne komponenty MVC -- obiekt żądania, router, obiekt uruchamiający,
148 kontrolery akcji, oraz obiekt odpowiedzi -- każdy może z różnych
149 przyczyn wyrzucać wyjątki. Niektóre wyjątki mogą być warunkowo
150 nadpisane, a inne są używane aby wskazać programiście potrzebę
151 poprawienia aplikacji.
154 <para>Kilka przykładów:</para>
159 <code>Zend_Controller_Dispatcher::dispatch()</code>
160 domyślnie wyrzuci wyjątek jeśli zażądano nieprawidłowego
161 kontrolera. Są dwa zalecane sposoby na obsłużenie tego:
166 <para>Ustawienie parametru <code>useDefaultControllerAlways</code>.</para>
169 W twoim kontrolerze frontowym, lub w obiekcie
170 uruchamiającym, dodaj poniższą dyrektywę:
173 <programlisting role="php"><![CDATA[
174 $front->setParam('useDefaultControllerAlways', true);
177 $dispatcher->setParam('useDefaultControllerAlways', true);
182 Gdy ta flaga jest ustawiona, obiekt uruchamiający,
183 użyje domyślnego kontrolera oraz akcji zamiast
184 wyrzucania wyjątku. Minusem użycia tej metody jest
185 to, że jakikolwiek błąd literowy w adresie
186 dostępowym do twojej strony spowoduje wyświetlenie
187 strony głównej, co może źle wpłynąć na optymalizację
188 serwisu dla wyszukiwarek internetowych.
194 Wyjątek wyrzucany przez metodę <code>dispatch()</code>
195 jest wyjątkiem <code>Zend_Controller_Dispatcher_Exception</code>
196 zawierającym tekst 'Invalid controller specified'.
197 Użyj jednej z metod opisanych w <link
198 linkend="zend.controller.exceptions.handling">poprzedniej
199 sekcji</link> aby złapać wyjątek, a następnie
200 przekierować do strony błędu lub do strony głownej.
208 Metoda <code>Zend_Controller_Action::__call()</code> wyrzuci
209 wyjątek <code>Zend_Controller_Action_Exception</code>
210 jeśli nie może uruchomić nieistniejącej metody akcji.
211 Najczęściej będziesz chciał użyć jakiejś domyślnej akcji
212 w kontrolerze w tego typu sprawach. Przykładowe metody
213 za pomocą których możesz to osiśgnąć:
219 Rozszerzenie klasy <code>Zend_Controller_Action</code>
220 i nadpisanie metody <code>__call()</code>. Na przykład:
223 <programlisting role="php"><![CDATA[
224 class My_Controller_Action extends Zend_Controller_Action
226 public function __call($method, $args)
228 if ('Action' == substr($method, -6)) {
229 $controller = $this->getRequest()->getControllerName();
230 $url = '/' . $controller . '/index';
231 return $this->_redirect($url);
234 throw new Exception('Invalid method');
240 Powyższa metoda przechwytuje wszystkie wywołane
241 niezdefiniowane akcje i przekierowuje żądanie do
242 domyślnej akcji w kontrolerze.
248 Rozszerzenie klasy <code>Zend_Controller_Dispatcher</code> o
249 nadpisanie metody <code>getAction()</code>, która
250 sprawdza czy akcja istnieje. Na przykład:
253 <programlisting role="php"><![CDATA[
254 class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
256 public function getAction($request)
258 $action = $request->getActionName();
259 if (empty($action)) {
260 $action = $this->getDefaultAction();
261 $request->setActionName($action);
262 $action = $this->formatActionName($action);
264 $controller = $this->getController();
265 $action = $this->formatActionName($action);
266 if (!method_exists($controller, $action)) {
267 $action = $this->getDefaultAction();
268 $request->setActionName($action);
269 $action = $this->formatActionName($action);
280 Powyższy kod sprawdza czy zażądana akcja istnieje w
281 klasie kontrolera; jeśli nie, resetuje akcję do
286 Ta metoda jest wygodna ponieważ możesz w niewidoczny
287 sposób zmienić akcję przed ostatecznym uruchomieniem.
288 Jednak to także oznacza, że jakikolwiek błąd literowy
289 w adresie URL może wciąż uruchomić żądanie poprawnie,
290 co nie jest zbyt dobre dla optymalizacji dla
291 wyszukiwarek internetowych.
297 Użycie metody <code>Zend_Controller_Action::preDispatch()</code>
298 lub <code>Zend_Controller_Plugin_Abstract::preDispatch()</code>
299 do zidentyfikowania nieprawidłowych akcji.
303 Rozszerzając klasę <code>Zend_Controller_Action</code> i
304 modyfikując metodę <code>preDispatch()</code>, możesz
305 zmodyfikować wszystkie twoje kontrolery w taki
306 sposób, aby przenosiły one żądanie do innej akcji
307 lub przekierowywały zamiast uruchamiać akcję.
308 Kod wyglądałby podobnie kod nadpisujący metodę
309 <code>__call()</code>, który został przedstawiony wyżej.
313 Alternatywnie, możesz sprawdzać te informacje we
314 wtyczce globalnej. Zaletą tego rozwiązania jest to,
315 że kontroler akcji staje się niezależny; jeśli twoja
316 aplikacja składa się z różnorodnych kontrolerów
317 akcji i nie wszystkie dziedziczą z tej samej klasy,
318 ta metoda może dodać konsekwencji w obsłudze różnych
326 <programlisting role="php"><![CDATA[
327 class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract
329 public function preDispatch(Zend_Controller_Request_Abstract $request)
331 $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
332 $controller = $dispatcher->getController($request);
334 $controller = $dispatcher->getDefaultControllerName($request);
336 $action = $dispatcher->getAction($request);
338 if (!method_exists($controller, $action)) {
339 $defaultAction = $dispatcher->getDefaultAction();
340 $controllerName = $request->getControllerName();
341 $response = Zend_Controller_Front::getInstance()->getResponse();
342 $response->setRedirect('/' . $controllerName . '/' . $defaultAction);
343 $response->sendHeaders();
352 W tym przykładzie sprawdzamy czy zażądana akcja
353 jest dostępna w kontrolerze. Jeśli nie,
354 przekierujemy żądanie do domyślnej akcji w
355 kontrolerze, i kończymy wykonywanie skryptu.