Klasa Zend_Controller
została zbudowana w sposób bardzo elastyczny.
Można ją rozwijać rozszerzając klasy istniejące lub pisząc nowe klasy implementujące
interfejsy Zend_Controller_Router_Interface
oraz Zend_Controller_Dispatcher_Interface
.
Powodami dla których warto implementować nowy router lub dispatcher mogą być:
Istniejący w Zend Framework system routingu URI nie jest kompatybilny. Np. gdy chcemy go zintegrować z istniejącą witryną która używa swoich własnych konwencji routingu, które nie są kompatybilne z mechanizmem routingu dostarczanym przez Zend Framework.
Potrzebujesz zaimplementować routing dla czegoś zupełnie innego. Klasa Zend_Controller_Router
działa jedynie z adresami URI. Jest prawdopodobne że chciałbyś użyć wzorca MVC
do opracowania innego typu aplikacji, np. aplikacji konsolowej. W przypadku
aplikacji konsolowej własny router mógłby obrabiać argumenty linii poleceń w celu
określenia nazw kontrolerów, nazw akcji oraz opcjonalnych parametrów.
Mechanizm dostarczany przez Zend_Controller_Dispatcher
nie jest kompatybilny.
Domyślna konfiguracja przyjmuje taką konwencję, że kontrolery są klasami, a akcje metodami
tych klas. Bądź co bądź, jest wiele innych sposobów wykonania tego. Przykładem może być takie
rozwiązanie, w którym kontrolery są katalogami a akcje plikami w tych katalogach.
Chciałbyś dostarczyć dodatkowe możliwości które będą odziedziczone
przez wszystkie kontrolery. Na przykład Zend_Controller_Action
nie jest domyślnie zintegrowany z Zend_View
. Jednak mógłbyś
rozszerzyć swój własny kontroler aby to robił i zapewnienie takiej
funkcjonalności nie wymagałoby modyfikowania dostarczonych klas
Zend_Controller_Router
oraz Zend_Controller_Dispatcher
.
Proszę być ostrożnym podczas nadpisywania znaczących części systemu, sczególnie
wtedy gdy jest to dispatcher. Jedną z zalet klasy Zend_Controller
jest to że wprowadza ona ogólne konwencje budowy aplikacji. Jeżeli odejdziemy
zbyt daleko od tych konwencji, możemy stracić część tych zalet. Jednak
jest wiele różnych zapotrzebowań i jedno rozwiązanie nie jest w stanie spełnić
ich wszystkich więc dowolność jest zapewniona gdy jest potrzebna.
Kiedy rozszerzasz którekolwiek klasy Zend_Controller powinieneś użyć takich samych konwencji w nazywaniu i przechowywaniu plików. Takie postępowanie spowoduje to, że inny programista który jest zaznajomiony z Zend Framework będzie w stanie łatwo zrozumieć Twój projekt.
Klasy ładowane przez Zend Framework są nazywane wg tej samej konwencji, każda z nich jest poprzedzona przedrostkiem "Zend_". Zalecamy abyś nazywał wszystkie swoje klasy w analogiczny sposób, np. jeśli Twoja firma nazywa się Widget Inc., to prefiksem mogłoby być "Widget_".
Klasa Zend_Controller
jest przechowywana w taki sposób:
/library /Zend /Controller Action.php Dispatcher.php Router.php
Kiedy rozszerzasz klasy Zend_Controller
, zalecane jest aby
nowa klasa była przechowywana w identyczny sposób z uwzględnieniem własnego
prefiksu. To spowoduje że będą one łatwe do znalezienia i zrozumienia
dla kogoś kto przegląda kod Twojego projektu.
Na przykład struktura projektu firmy Widget Inc., który implementuje jedynie własny router mogłaby wyglądać w ten sposób:
/library /Zend /Widget /Controller Router.php README.txt
Pamiętaj, że w tym przykładzie Widget/Controller/
ma taką samą strukturę
jak Zend/Controller/
kiedy tylko jest to możliwe. W tym przypadku definiuje
on klasę Widget_Controller_Router
, która może być klasa rozszerzającą lub
zastępującą klasę Zend_Controller_Router
implementującą
Zend_Controller_Router_Interface
.
Zwróć także uwagę na to, że w powyższym przykładzie plik README.txt
został
umieszczony w katalogu Widget/Controller/
. Zend zaleca abyś dokumentował
swoje projekty dostarczając klientom osobne testy oraz dokumentację. Jakkolwiek, zalecamy
Ci abyś także tworzył prosty plik README.txt
w katalogu swojej klasy
aby wyjaśnić zmiany oraz zasady jej działania.
Interfejs Zend_Controller_Router_Interface
definiuje jedynie jedną metodę:
<?php /** * @param Zend_Controller_Dispatcher_Interface * @throws Zend_Controller_Router_Exception * @return Zend_Controller_Dispatcher_Token|boolean */ public function route(Zend_Controller_Dispatcher_Interface $dispatcher); ?>
Proces routingu ma miejsce tylko raz: wtedy gdy system po raz pierwszy otrzymuje żądanie.
Celem routera jest wygenerowanie obiektu Zend_Controller_Dispatch_Token
który
określa kontroler oraz akcję z tego kontrolera. To jest przekazywane do dispatchera. Jeśli
nie jest możliwe określenie mapowanie trasy do tokena to zwracana jest wartość logiczna
FALSE
.
Niektóre routery mogą przetwarzać dynamiczne elementy i przed zwróceniem
wygenerowanego tokena potrzebują możliwości sprawdzenia czy jest możliwe
jego wykonanie. Z tego powodu, metoda route()
routera otrzymuje
uchwyt obiektu dispatchera jako jedyny argument. Dispatcher posiada metodę
isDispatchable()
do sprawdzania możliwości jego wykonania.
Zend_Controller_Front
wpierw wywołuje router w celu otrzymania tokena, który
będzie przekazany do dispatchera. Dispatcher uruchomi akcję (tworząc instancję kontrolera
i wywołując jego akcję) a następnie zwróci logiczną wartość FALSE lub kolejny token.
Zend_Controller_Front
w pętli wywołuje dispatcher dopóki zwracany
jest kolejny token. Nazywamy to pętlą uruchomieniową (dispatch loop). Pozwala ona
na sekwencyjne uruchamianie akcji aż wszystkie zostaną wykonane.
Interfejs Zend_Controller_Dispatcher_Interface
dostarcza definicje dwóch metod:
<?php /** * @param Zend_Controller_Dispatcher_Token $route * @return boolean */ public function isDispatchable(Zend_Controller_Dispatcher_Token $route); ?>
Metoda isDispatchable()
sprawdza czy jest możliwe uruchomienie akcji
z tokena. Jeśli jest to możliwe, zwraca ona wartość TRUE
. W przeciwnym
wypadku zwraca wartość FALSE
. Decyzja o tym czy jest możliwe
uruchomienie akcji została pozostawiona klasie implementującej interfejs.
W domyślnej implementacji klasy Zend_Controller_Dispatcher
oznacza to
sprawdzenie, czy plik kontrolera istnieje, czy klasa istnieje w tym pliku
oraz czy wewnątrz klasy istnieje żądana akcja.
<?php /** * @param Zend_Controller_Dispatcher_Token $route * @return Zend_Controller_Dispatcher_Token|boolean */ public function dispatch(Zend_Controller_Dispatcher_Token $route); ?>
dispatch()
jest metodą, która wykonuje całą pracę. Ta metoda
musi uruchomić akcję kontrolera. Musi zwrócić kolejny token lub wartość
logiczną FALSE aby określić czy są jeszcze jakieś akcje do uruchomienia.