5.4. Bereitgestellte Unterklassen

5.4.1. Einführung

Das Zend Framework stellt verschiedene Alternativen zu den bereit gestellten Standardklassen zur Verfügung. Dies beinhaltet altive Request Objekte, Router und Response Objekte.

5.4.2. Zend_Controller_Request_Http

5.4.2.1. Einführung

Zend_Controller_Request_Http stellt ein Request Objekt für die Verwendung in einer HTTP Umgebung bereit. Zend_Controller_Request_Http ist die Standard Request Klasse, die von Zend_Controller_Dispatcher verwendet wird.

5.4.2.2. Auf Request Daten zugreifen

Zend_Controller_Request_Http kapselt den Zugriff auf relevante Werte wie der Schlüssel und Wert für Controller und Action Variablen des Routers und alle zusätzlichen Parameter, die aus der URI ermittelt wurden. Durch den Proxy zu Zend_Controller_Request_Http erlaubt es zusätzlich den Zugriff auf superglobale Werte als öffentliche Eigenschaften und verwaltet die aktuelle Basis URL und Request URI. Superglobale Werte können in einem Request Objekt nicht gesetzt werden, stattdessen verwendet man die setParam/getParam Methoden um Benutzerparameter zu setzen oder zu erhalten.

[Anmerkung] Superglobale Daten

Beim Zugriff auf superglobale Daten über die öffentlichen Eigenschaften von Zend_Controller_Request_Http ist es notwendig, darauf zu achten, dass der Eigenschaftsname (der superglobale Arrayschlüssel) einem superglobalen Wert in einer bestimmten Reihenfolge entspricht: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV.

Auf spezifische superglobale Werte kann alternativ über eine öffentliche Methode zugegriffen werden. Zum Beispiel kann auf den unverarbeitete Wert von $_POST['user'] durch Aufruf der getPost('user') Methode des Request Objekts zugegriffen werden.

5.4.2.3. Basis Url und Unterverzeichnisse

Zend_Controller_Request_Http erlaubt, dass Zend_Controller_RewriteBase in einem Unterverzeichnis verwendet werden kann. Zend_Controller_Request_Http versucht, die Basis URL automatisch zu erkennen und entsprechend zu setzen.

Wenn man zum Beispiel seine index.php in einem Webserverunterverzeichnis mit Namen /projects/myapp/index.php verwendet, sollte die Basis URL (die Rewrite Basis) auf /projects/myapp gesetzt werden. Dieser String wird dann vom Anfang des Pfades entfernt, bevor irgend welche Routingtreffer ermittelt werden. Dies befreit einem davon, es an den Anfang jeder Route setzen zu müssen. Eine Route 'user/:username' passt auf URIs wie http://localhost/projects/myapp/user/martel und http://example.com/user/martel.

[Anmerkung] URL Erkennung beachtet Groß- und Kleinschreibung

Die automatische Erkennung der Basis URL beachtet die Groß- und Kleinschreibung, weshalb man sicherstellen sollte, dass die URL einem Unterverzeichnis im Dateisystem entspricht (sogar auf einem Windows Rechner). Andernfalls wird auf die noRoute aktion umgeleitet.

Sollte die Basis URL falsch erkannt werden, kann man diese auch mit einem eigenen Pfad mit Hilfe der setBaseUrl() Methode der Zend_Controller_Request_Http Klasse oder der Zend_Controller_Front Klasse überschreiben. Die einfachste Methode ist die von Zend_Controller_Front, welche es an das Request Object weiter leitet. Beispiel, um eine eigene Basis URL zu setzen:

/** 
 * Dispatch Request with custom base URL with Zend_Controller_Front.
 */
$router     = new Zend_Controller_RewriteRouter();
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./application/controllers')
           ->setRouter($router)
           ->setBaseUrl('/projects/myapp'); // set the base url!
$response   = $controller->dispatch();

5.4.3. Zend_Controller_RewriteRouter

5.4.3.1. Einführung

Zend_Controller_RewriteRouter ist eine neue Version des Framework Routers. Routing ist der Prozess der Übernahme und Zerteilung einer URI, um zu ermitteln, welcher Controller und welche Aktion des Controllers die Anfrage erhalten soll. Die Definition des Controllers, der Aktion sowie weiterer Parameter wird in einem Objekt mit Namen Zend_Controller_Dispatcher_Token gekapselt, das dann vom Zend_Controller_Dispatcher verarbeitet wird. Das Routing geschieht nur einmal: wenn zu Beginn die Anfrage erhalten wird und bevor der erste Controller aufgerufen wird.

Zend_Controller_RewriteRouter wurde entwickelt, um mit reinen PHP Strukturen eine mod_rewrite ähnliche Funktionalität zu erlauben. Es richtet sich sehr frei nach dem Ruby on Rails Routing und benötigt kein tieferes Wissen über URL Weiterleitung des Webservers. Es wurde entwickelt, um mit einer einzigen mod_rewrite Regel zu arbeiten.

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

oder:

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

Der RewriteRouter kann auch mit dem IIS Webserver verwendet werden, wenn Isapi_Rewrite als Isapi Erweiterung installiert wurde und folgende Umschreibungsregel verwendet wird:

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

Bei Verwenung von IIS, wird $_SERVER['REQUEST_URI'] entweder nicht vorhanden sein oder auf einen leeren String gesetzt sein. In diesem Fall wird Zend_Controller_Request_Http versuchen, den durch die Isapi_Rewrite Erweiterung gesetzten Wert $_SERVER['HTTP_X_REWRITE_URL'] zu verwenden.

Bei der verwendung von Lighttpd, ist folgende Umschreibungsregel gültig:

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

5.4.3.2. Einen Router verwenden

Um den RewriteRouter richtig zu verwenden, mußt du ihn instanziieren, einige benutzerdefinierte Routen hinzufügen und in den Controller einbinden. Der folgende Code veranschaulicht die Vorgehensweise:

/* Erstelle einen Router */

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

/* binde ihn in den Controller ein */

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

5.4.3.3. Einfache Routen

Das Herz des RewriteRouter ist die Definition der benutzerdefinierten Routen. Routen werden durch Aufruf der addRoute Methode des RewriteRouter und der Übergabe einer neuen Instanz von Zend_Controller_Router_Route erstellt:

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

Der erste Parameter ist der Name der Route. Zum derzeitigen Zeitpunkt ist er redundant aber wird in Zukunft in einem URL View Helper verwendet, um eine einfache Erstellung von URLs in deinen Views zu ermöglichen. Wenn du die vorher konfigurierte, benannte Route verwenden möchtest, kannst du sie mit den getRoute Methode des RewriteRouter erhalten. Der zweite Parameter ist eine Instanz von Zend_Controller_Router_Route.

The erste Parameter für den Zend_Controller_Router_Route Konstruktur ist eine Route, die auf eine URL passt - zum Beispiel passt die obige Route auf http://example.com/user/martel. Der Doppelpunkt in einer Route markiert eine URL Variable, die durch die Zend_Controller_Action::_getParam Methode zugänglich ist. In unserem Beispiel wird der mit 'username' benannte Parameter auf den Wert 'martel' gesetzt.

[Anmerkung] Reihenfolge der Definitionen

Routen werden in umgekehrter Reihenfolge abgeglichen, so dass man sicherstellen muss, dass die allgemeinste Route als erstes definiert ist.

[Anmerkung] Erlaubte Zeichen

Fürs Erste erlaubt die aktuelle Implementation die Verwendung jedes Zeichens für den Variablenbezeichner außer den Schrägstrich (/), es wird aber sehr empfohlen, dass du nur Zeichen verwendest, die für PHP Variablen verwendet werden dürfen. In Zukunft wird die Implementation vermutlich angepasst und dies könnte Fehler in deinen Code einführen.

Es gibt zwei besondere Variablen, die in deinen Routen verwendet werden können - 'controller' und 'action'. Diese besonderen Variablen werden verwendet, um einen gewählten Controller und/oder eine Aktion in der URL zu finden. Die 'action' Variable muß immer entweder in der Route oder als Standardparameter definiert sein. Die 'controller' Variable wird standardmäßig auf IndexController verweisen, wenn sie nicht definiert wurde.

[Anmerkung] Spezielle Variablen

Die Namen dieser speziellen Variablen können unterschiedlich sein, wenn man die Standardwerte in Zend_Controller_Request_Http mit Hilfe der setControllerKey und setActionKey Methoden verändert.

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

Wenn du deinen Browser mit dieser Route auf http://example.com/news/latest richtest, wird der Zend_Controller_Dispatcher die Aktion latestAction deines Controllers NewsController ausführen.

5.4.3.4. Vorgegebene Variablenwerte

Jede Variable in der Route kann einen vorgegebenen Wert haben. Um diesen vorzugeben, mußt du einen dritten Parameter zur addRoute Methode hinzufügen. Dieser dritte Parameter ist ein Array mit den Variablennamen als Schlüssel und den vorgegebenen Werten als Werten.

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

Was nicht sofort erkennbar sein mag, ist, dass die obige Route auf URLs wie http://example.com/archive/2005 und http://example.com/archive passt. Im letzteren Fall hat die Variable 'year' den Wert 2006.

Im obigen Beispiel haben wir keinen Controller angegeben, so dass immer auf die noRoute Aktion des IndexController verwiesen wird. Damit es anwendbar ist, musst du einen gültigen Controller und eine gültige Aktion als Standardwerte festlegen:

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

This route will then result in dispatching to showAction of ArchiveController.

5.4.3.5. Anforderungen an Variablen

Du kannst einen dritten Parameter hinzufügen, in dem Anforderungen an die Variablen angegeben werden können. Diese werden als reguläre Ausdrücke definiert:

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

Im Gegensatz zu Ruby on Rails wird Zend_Controller_RewriteRouter für eine Route Standardwerte verwenden, wenn die Anforderungen an die Variablen im vierten Parameter nicht erfüllt werden. Also passt die URL http://example.com/archive/test auf die obige Route und setzt den Parameter 'year' auf 2006. Diese Funktionalität kann sich in Zukunft ändern, da sie im Moment beim Schreiben dieser Dokumentation noch diskutiert wird.

5.4.3.6. Basis URL und Unterverzeichnisse

Im Gegensatz zum ursprünglichen Route kann RewriteRouter auch in Unterverzeichnissen verwendet werden. Die Methode setRewriteBase() des ursprünglichen RewriteRouter existiert nicht mehr. Stattdessen wird die Basis URL automatisch durch Zend_Controller_Request_Http ermittelt.

Sollte die Basis URL falsch erkannt werden, kannst du sie mit deinem eigenen Pfad mit Hilfe von Zend_Controller_Request_Http durch den Aufruf der setBaseUrl() Methode setzen (siehe Abschnitt 5.4.2.3, „Basis Url und Unterverzeichnisse“).

5.4.3.7. Standardrouten

Zend_Controller_RewriteRouter hat eine vordefinierte Standardroute, um Kompatibilität mit der ersten Version des Routers zu gewährleisten. Sie passt auf URIs in Form von 'controller/action' and erkennt außerdem jeden zusätzlichen Parameter, der an die URI angehängt wird. Sie ist wie folgt konfiguiert:

// Route for Router v1 compatibility
$compat = new Zend_Controller_Router_Route(':controller/:action/*', array('controller' => 'index', 'action' => 'index'));
$this->addRoute('default', $compat);
[Anmerkung] URIs abbilden

Zend_Controller_RewriteRouter wurde für Rückwärtskompatibilität konfiguriert. Es passt automatisch auf controller/action URIs mit zusätzlichen Parameter. Die zusätzlichen Parameter benötigen keine weiteren Routen, solange sie keine vorgegebenen Variablenwerte oder Variablenanforderungen benötigen. Auf diese zusätzlichen Parameter kann über die Zend_Controller_Action::_getParam() Methode zugegriffen werden.

Wenn man die Standardroute nicht in seinem Routing Schema haben möchte, kann diese mit Hilfe von removeDefaultRoutes() entfernt werden:

// Entferne Standardroute
$router->removeDefaultRoutes();

5.4.3.8. Statische Routen

Die obigen Beispiele verwenden alle dynamische Routen - Routen die zu prüfende Muster verwenden. Manchmal ist eine bestimmte Route jedoch fest verankert und die Verwendung regulärer Ausdrücke wäre zuviel des Guten. Die Antwort auf solche Situationen ist die Verwendung von statischen Routen:

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

5.4.3.9. Zend_Config mit dem RewriteRouter verwenden

Manchmal ist es praktischer, eine Konfigurationsdatei mit neuen Routen zu aktualisieren, als den Code zu ändern. Dies ist mit Hilfe der addConfig() Methode möglich. Im Wesentlichen kann man eine Zend_Config kompatible Konfiguration erstellen, in seinem Code einlesen und an den RewriteRouter übergeben:

/**
 * Beispiel 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');

Im oberen Beispiel teilen wir dem Router mit, den 'routes' Bereich der INI Datei für seine Routen zu verwenden. Jeder Schlüssel auf erster Ebene in diesem Bereich wird verwendet, um den Namen der Routen zu definieren; das obige Beispiel definiert die Routen 'archive' und 'news'. Jede Route erfordert dann mindestens einen 'route' Eintrag und einen oder mehrere 'defaults' Einträge; optional können eine oder mehrere 'reqs' (kurz für 'required', d.h. erforderlich) Einträge angegeben werden. Alles in allem entspricht dies den drei Argumenten, die an ein Zend_Controller_Router_Route_Interface Objekt übergeben werden. Ein Optionsschlüssel 'type' kann verwendet werden, um den Typ der Routenklasse für diese Route anzugeben; standardmäßig wird Zend_Controller_Router_Route verwendet. Im obigen Beispiel wird die 'news' Route definiert, um Zend_Controller_Router_StaticRoute zu verwenden.

5.4.4. Zend_Controller_Response_Http

Zend_Controller_Response_Http ist ein Response Objekt, das für die Verwendung in einer HTTP Umgebung geeignet ist. Es enthält Methoden für das Setzen, Erhalten und Entfernen von Headern und die __toString() Methode sendet alle Header auf einmal bevor die Reponse Inhalte zurückgegeben werden.

setHeader() nimmt zwei Argumente entgegen, einen Header Typ und den Header Wert. Ein dritter, optionaler Parameter (wenn übergeben und true) erzwingt das Überschreiben des vorhandenen Headers gleichen Typs mit dem neuen Header.

5.4.5. Zend_Controller_Response_Cli

Zend_Controller_Response_Cli is ein Response Object, das für die Verwendung in einer CLI Umgebung geeignet ist. Es hat keine Methoden für die Behandlung von Headern und gibt nur alle Inhalte zurück, wenn __toString() aufgerufen wird.