5.4. Dostępne podklasy

5.4.1. Wprowadzenie

Zend Framework zapewnia kilka alternatyw dla domyślnych klas, włączając w to alternatywne obiekty żądania, routery oraz obiekty odpowiedzi.

5.4.2. Zend_Controller_Request_Http

5.4.2.1. Wprowadzenie

Zend_Controller_Request_Http zapewnia obiekt żądania do użycia w środowisku HTTP. Klasa Zend_Controller_Request_Http jest domyślną klasą żądania używaną przez Zend_Controller_Dispatcher.

5.4.2.2. Dostęp do danych żądania

Zend_Controller_Request_Http obudowuje dostęp do odpowiednich wartości takich jak nazwa klucza i wartość dla zmiennych kontrolera i akcji routera, oraz do dodatkowych parametrów pobranych z adresu URI. Rozszerzając Zend_Controller_Request_Http dodatkowo pozwala na uzyskanie dostępu do wartości zawartych w superglobalnych tablicach jako do publicznych właściwości obiektu i zarządza obecnym bazowym adresem URL oraz adresem URL żądania. Superglobalne wartości nie mogą być ustawione w obiekcie żądania, zamiast tego użyj metod setParam/getParam aby ustawić lub odebrać parametry użytkownika.

[Notatka] Dane superglobalne

Kiedy uzyskujemy dostęp do danych superglobalnych za pomocą klasy Zend_Controller_Request_Http jak do jej publicznych właściwości, ważne jest aby pamiętać, że nazwa właściwości (klucz tablicy superglobalnej) jest dopasowana do superglobalnych w określonej kolejności: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV.

Konkretne zmienne superglobalne mogą być alternatywnie dostępne za pomocą publicznej metody. Na przykład, wartość $_POST['user'] może być dostępna przez wywołanie metody getPost('user') na obiekcie żądania.

5.4.2.3. Bazowy Url oraz podkatalogi

Klasa Zend_Controller_Request_Http pozwala na użycie klasy Zend_Controller_RewriteRouter w podkatalogach. Zend_Controller_Request_Http spróbuje automatycznie wykryć twój bazowy adres URL i ustawi go odpowiednio.

Na przykład jeśli twój plik index.php jest w podkatalogu nazwanym /projects/myapp/index.php, bazowy URL (bazowy adres przepisania) powinien być ustawiony na /projects/myapp. Ten łańcuch znaków zostanie obcięty z początu ścieżki zanim będą dopasowane jakiekolwiek trasy. To zwalnia z konieczności dołączania tego adresu do każdej z tras. Trasa 'user/:username' dopasuje adresy URI takie jak http://localhost/projects/myapp/user/martel oraz http://example.com/user/martel.

[Notatka] Detekcja URL jest wrażliwa na małe i duże litery

Automatyczna detekcja adresów URL jest wrażliwa na małe i duże litery, więc upewnij się, że adres URL zostanie dobrze dopasowany do nazwy podkatalogu w systemie plików (nawet w systemie Windows). Jeśli nie zostanie, zostanie wywołana akcja noRoute.

Jeśli bazowy adres URL jest wykrywany nieprawidłowo, możesz go nadpisać w obiekcie Zend_Http_Request wywołując metodę setBaseUrl() lub tą samą metodę klasy Zend_Controller_Request_Http lub klasy Zend_Controller_Front. Najłatwiejszy sposób to ustawienie tego w klasie Zend_Controller_Front, która przekaże to do obiektu żądania. Przykładowe użycie ustawiania własnego bazowego adresu URL:

/** 
 * Uruchom żądanie z własnym bazowym URL za pomocą Zend_Controller_Front.
 */
$router     = new Zend_Controller_RewriteRouter();
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./application/controllers')
           ->setRouter($router)
           ->setBaseUrl('/projects/myapp'); // ustaw bazowy URL!
$response   = $controller->dispatch();

5.4.3. Zend_Controller_RewriteRouter

5.4.3.1. Wprowadzenie

Zend_Controller_RewriteRouter jest nową wersją routera we frameworku. Routing jest procesem pobrania adresu URI i rozłożenia go w celu ustalenia jaki kontroler i jaka akcja powinny otrzymać żądanie. Ta informacja o kontrolerze, akcji i opcjonalnych parametrach jest pakowana do obiektu Zend_Controller_Request_Http, który jest potem przetwarzany przez Zend_Controller_Dispatcher. Routing ma miejsce tylko raz: wtedy gdy żądanie jest po raz pierwszy otrzymane, przed wywołaniem pierwszego kontrolera.

Zend_Controller_RewriteRouter jest zaprojektowany w celu uzyskania w czystym PHP takiej funkcjonalności jak w mod_rewrite. Jest to luźno wzorowane na routingu Ruby on Rails i nie wymaga żadnej wiedzy o przepisywaniu adresów przez serwer www. Jest to zaprojektowane w taki sposób, aby działało po dodaniu tylko jednej reguły mod_rewrite (jednej z poniższych):

RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

lub:

RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 

RewriteRouter może być także użyty z serwerem IIS, jeśli moduł Isapi_Rewrite jest zainstalowany jako rozszerzenie Isapi, z taką regułą przepisywania:

RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css)$)[\w\%]*$)? /index.php [I]
[Notatka] IIS Isapi_Rewrite

Jeśli używasz serwera IIS, to wartość $_SERVER['REQUEST_URI'] nie istnieje lub jest pustym łańcuchem znaków. W takim wypadku, Zend_Controller_Request_Http spróbuje użyć wartości $_SERVER['HTTP_X_REWRITE_URL'] ustawionej przez rozszerzenie Isapi_Rewrite.

Jeśli używasz serwera Lighttpd, poniższa reguła jest prawidłowa:

url.rewrite-once = ( ".*\.(js|ico|gif|jpg|png|css)$" => "$0", "" => "/index.php")

5.4.3.2. Użycie routera

Aby prawidłowo użyć RewriteRoutera musisz utworzyć jego instancję, zdefiniować jakieś trasy i przekazać ten obiekt do kontrolera. Poniższy kod pokazuje tą procedurę:

/* Utwórz router */

$router = new Zend_Controller_RewriteRouter();
$router->addRoute(
	'user',
	new Zend_Controller_Router_Route('user/:username', array('controller' => 'user', 'action' => 'info'))
);

/* Ustaw go w kontrolerze */

$ctrl = Zend_Controller_Front::getInstance();
$ctrl->setRouter($router);

5.4.3.3. Podstawowe trasy

Sercem RewriteRoutera jest definicja tras określonych przez użytkownika. Trasy są tworzone przez wywołanie metody addRoute obiektu RewriteRouter i przekazanie do niej nowej instancji obiektu Zend_Controller_Router_Route:

$router->addRoute('user', new Zend_Controller_Router_Route('user/:username'));

Pierwszy parametr jest nazwą trasy. Obecnie nie jest konieczne jego definiowanie, jednak będzie on używany w przyszłości w klasie pomocniczej widoku ułatwiającej łatwe generowanie adresów URL. Jeśli chcesz użyć wcześniej skonfigurowanej trasy, możesz ją odebrać za pomocą metody getRoute RewriteRoutera. Drugi parametr jest instancją Zend_Controller_Router_Route.

Pierwszy parametr konstruktora obiektu Zend_Controller_Router_Route jest trasą, która ma być dopasowana do adresu URL - na przykład powyższa trasa zostanie dopasowana do adresu http://example.com/user/martel. Dwukropek w trasie oznacza zmienną adresu URL. Po udanym dopasowaniu trasy, wartości wszystkich zdefiniowanych zmiennych zostaną przekazane do obiektu Zend_Controller_Request. Po tym będą one dostępne za pomocą metod Zend_Controller_Request::getParam oraz Zend_Controller_Action::_getParam. W naszym przykładzie parametr nazwany username będzie miał ustawioną wartość 'martel'.

[Notatka] Odwrotne dopasowywanie

Trasy są dopasowywane w odwrotnej kolejności więc musisz pamiętać żeby podstawowe trasy były zdefiniowane na początku.

[Notatka] Użycie znaków

Teraz obecna implementacja pozwala na użycie w nazwie zmiennej dowolnych znaków z wyjątkiem ukośnika (/), ale jest mocno zalecane używanie jedynie znaków, które są bezproblemowo obsługiwane ptzrz PHP. W przyszłości implementacja prawdopodobnie zostanie zmodyfikowana co mogłoby wprowadzić do twojego kodu błędy.

Są dwie specjalne zmienne które nie mogą być użyte w twoich trasach - ':controller' oraz ':action'. Te specjalne zmienne będą użyte aby znaleść kotroler oraz akcję w danym adresie URL. Zmienna ':action' zawsze musi być zdefiniowana w trasie lub jako domyślny parametr. Zmienna ':controller' będzie domyślnie ustawiona na IndexController jeśli nie będzie zdefiniowana.

[Notatka] Specjalne zmienne

Nazwy tych specjalnych zmiennych mogą być inne, jeśli zdecydujesz zmienić je w obiekcie Zend_Controller_Request_Http za pomocą metod setControllerKey oraz setActionKey.

$router->addRoute(
    'user', new Zend_Controller_Router_Route(':controller/:action')
);

Jeśli skierujesz przeglądarkę na adres 'http://example.com/news/latest' ze zdefiniowaną powyższą trasą Zend_Controller_Dispatcher odwoła się do akcji latestAction z kontrolera NewsController.

5.4.3.4. Domyślne wartości zmiennych

Każda zmienna w trasie może mieć wartość domyślną. Aby to zrobić, musisz przekazać drugi parametr do konstruktora Zend_Controller_Router_Route. Ten parametr jest tablicą z nazwami zmiennych jako kluczami i z wartościami, które mają być uznane za domyślne.

$router->addRoute(
    'archive', new Zend_Controller_Router_Route('archive/:year', array('year' => 2006))
);

Może nie jest wyraźnie widoczne to, że powyższa trasa dopasuje adresy URL takie jak 'http://example.com/archive/2005' oraz 'http://example.com/archive'. Ostatecznie zmienna year i tak będzie miała wartość 2006.

Powyższy przykład spowoduje jedynie przekazanie zmiennej oznaczającej rok do żądania. Nie będzie miał miejsca routing, ponieważ parametry oznaczające kontroler i akcję nie są ustawione. Aby było to bardziej użyteczne, musisz zapewnić prawidłową nazwę kontrolera i akcji jako domyślne wartości.

$router->addRoute(
    'archive',
    new Zend_Controller_Router_Route('archive/:year', array('year' => 2006, 'controller' => 'archive', 'action' => 'show')
);

Ta trasa spowoduje uruchomienie akcji showAction kontrolera ArchiveController.

5.4.3.5. Wymagania zmiennych

Można dodać trzeci parametr do konstruktora Zend_Controller_Router_Route w którym będą ustawione wymagania zmiennych. Są one zdefiniowane jako wyrażenia regularne:

$router->addRoute(
    'archive',
    new Zend_Controller_Router_Route('archive/:year', array('year' => 2006), array('year' => '\d+'))
);
[Notatka] Zachowanie routera

W przeciwieństwie do Ruby on Rails, RewriteRouter z ZF dopasuje trasę i użyje domyślnej gdy trzeci parametr zawierający wymagania zmiennych nie zostanie znaleziony. Więc adres URL 'http://example.com/archive/test' zostanie dopasowany do powyższej trasy, a rok zostanie ustawiony na 2006. Ta funkcjonalność może w przyszłości się zmienić, ponieważ w momencie pisania tej dokumentacji ta kwestia jest jeszcze uzgadniana.

5.4.3.6. Bazowy adres URL i podkatalogi

W przeciwieństwie do oryginalnego routera, obecny RewriteRouter może być użyty w podkatalogach. Jednak oryginalna metoda RewriteRoutera setRewriteBase() nie jest już dostępna. Zamiast niej, bazowy adres URL zostanie automatycznie wykryty przez obiekt Zend_Controller_Request_Http.

Jeśli bazowy adres URL jest wykrywany nieprawidłowo, możesz go nadpisać w obiekcie Zend_Controller_Request_Http wywołując metodę setBaseUrl() (zobacz Sekcja 5.4.2.3, „Bazowy Url oraz podkatalogi”).

5.4.3.7. Domyślne trasy

Zend_Controller_RewriteRouter jest skonfigurowany z jedną domyślną trasą w celu zapewnienia kompatybilności z pierwsza wersją routera. Dopasuje on adresy w zakresie kontrolera i akcji, a także domyślnie dopasuje dodatkowe parametry dołączone do adresu URI. Jest skonfigurowany w ten sposób:

// Trasa kompatybilna z pierwszą wersja routera
$compat = new Zend_Controller_Router_Route(':controller/:action/*', array('controller' => 'index', 'action' => 'index'));
$this->addRoute('default', $compat);
[Notatka] Dopasowanie adresów URI

Zend_Controller_RewriteRouter jest skonfigurowany z kompatybilnością wsteczną. Automatycznie dopasuje kontroler i akcję z adresu wraz z dodatkowymi parametrami. Dodatkowe parametry nie wymagają dodawania nowych tras, o ile nie chcemy zdefiniować dla nich domyślnych wartości lub wymagań. Te dodatkowe parametry będą dostępne za pomocą metody Zend_Controller_Action::_getParam.

Jeśli nie potrzebujesz domyślnych tras w swoim schemacie routingu, możesz je usunąć używając metody removeDefaultRoutes():

// Usuwa domyślną trasę
$router->removeDefaultRoutes();

5.4.3.8. Trasy statyczne

Wszystkie powyższe przykłady używają dynamicznych tras -- tras, które są dopasowywane do szablonów. Czasem jakaś trasa jest niezmienna, a ciągłe sprawdzanie wyrażenia regularnego może być zabójcze dla serwera. Rozwiązaniem takiej sytuacji jest użycie statycznych tras:

$loginRoute = new Zend_Controller_Router_StaticRoute('login', array('controller' => 'login', 'action' => 'form'));
$router->addRoute('login', $static);

5.4.3.9. Użycie Zend_Config z RewriteRouterem

Czasem wygodniej jest uaktualnić plik konfiguracyjny z nowymi trasami niż zmieniać kod. Jest to możliwe za pomocą metody addConfig(). Zasadniczo tworzysz konfigurację kompatybilną z Zend_Config, a w kodzie odczytujesz ją i przekazujesz ją do RewriteRoutera.

/**
 * Przykładowy plik INI:
 * routes.archive.route = "archive/:year/*"
 * routes.archive.defaults.controller = archive
 * routes.archive.defaults.action = show
 * routes.archive.defaults.year = 2000
 * routes.archive.reqs.year = "\d+"
 * 
 * routes.news.type = "Zend_Controller_Router_StaticRoute"
 * routes.news.route = "news"
 * routes.news.defaults.controller = "news"
 * routes.news.defaults.action = "list"
 */
$config = new Zend_Config_Ini($file);
$router = new Zend_Controller_RewriteRouter();
$router->addConfig($config, 'routes');

W powyższym przykładzie, nakazujemy routerowi użyć sekcji 'routes' pliku INI aby użyć tras zdefiniowanych w tym pliku. Każdy element pierwszego poziomu w tej sekcji będzie użyty do zdefiiniowania nazwy trasy; powyższy przekład definiuje trasy 'archive' oraz 'news'. Wymagane jest aby każda trasa miała określony przynajmniej parametr 'route' i jeden lub więcej parametrów 'defaults'; opcjonalnie mogą być zdeiniowane parametry 'reqs' (skrót 'required'). Wszystkie te parametry odpowiadają trzem argumentom przekazywanym do obiektu Zend_Controller_Router_Route_Interface Klucz opcji 'type' może być użyty aby określić typ klasy, która ma być użyta dla danej trasy; domyślnie używana jest klasa Zend_Controller_Router_Route. W powyższym przykładzie, trasa 'news' jest zdefiniowana aby używała Zend_Controller_Router_StaticRoute.

5.4.4. Zend_Controller_Response_Http

Zend_Controller_Response_Http jest obiektem odpowiedzi odpowiednim do użycia w środowisku HTTP. Zawiera metody do ustawiania, odbierania i czyszczenia nagłówków, a metoda __toString() wysyła wszystkie nagłówki na raz przed wysłaniem zawartości odpowiedzi.

Metoda setHeader() przyjmuje dwa argumenty, typ nagłówka oraz wartość nagłówka. Trzeci opcjonalny parametr, jeśli jest przekazany i ma wartość true, spowoduje, że nowy nagłówek zastąpi inne zarejestrowane nagłówki o tym typie.

5.4.5. Zend_Controller_Response_Cli

Zend_Controller_Response_Cli jest obiektem odpowiedzi odpowiednim do użycia w środowisku CLI. Nie ma on metod do obsługi nagłówków i w prosty sposób zwraca całą zawartość gdy wywoływana jest metoda __toString().