Der Standard RouterEinführungZend_Controller_Router_Rewrite ist der Standard Router des Frameworks. Routing ist der Prozess der Übernahme und Zerteilung einer URI (dem Teil der URI der nach der Basis URL kommt), um zu ermitteln, welches Modul, welcher Controller und welche Aktion des Controllers die Anfrage erhalten soll. Die Definition des Moduls, des Controllers, der Aktion sowie weiterer Parameter wird in einem Objekt mit Namen Zend_Controller_Dispatcher_Token gekapselt, das dann vom Zend_Controller_Dispatcher_Standard verarbeitet wird. Das Routing geschieht nur einmal: wenn zu Beginn die Anfrage erhalten wird und bevor der erste Controller aufgerufen wird. Zend_Controller_Router_Rewrite 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.
oder (bevorzugt):
Der Rewrite Router kann auch mit dem IIS Webserver verwendet werden (Versionen <= 7.0), wenn » Isapi_Rewrite als Isapi Erweiterung installiert wurde und folgende Umschreibungsregel verwendet wird:
IIS 7.0 führt ein natives URL Rewriting Modul ein, und kann wie folgt konfiguriert werden:
Bei der Verwendung von Lighttpd, ist folgende Umschreibungsregel gültig:
Einen Router verwendenUm den Rewrite Router richtig zu verwenden, muß er instanziiert, einige benutzerdefinierte Routen hinzufügt und in den Controller einbunden werden. Der folgende Code veranschaulicht die Vorgehensweise:
Grundsätzliche Rewrite Router OperationenDas Herz des RewriteRouters ist die Definition von Benutzerdefinierten Routen. Routen werden durch aufruf der addRoute Methode des RewriteRouters hinzugefügt und übergeben eine neue Instanz einer Klasse die Zend_Controller_Router_Route_Interface implementiert. Z.B.:
Der Rewrite Router kommt mit sechs Basistypen von Routen (eine von denen ist speziell): is special): Routen können unzählige Male verwendet werden um eine Kette oder benutzerdefinierte Routing Schemas von Anwendungen zu erstellen. Es kann jede beliebige Anzahl von Routen in jeder beliebigen Konfiguration verwendet werden, mit Ausnahme der Modul Route, welche nur einmal verwendet werden sollte, und möglicherweise die am meisten standardmäßige Route ist (z.B., als ein Standard). Jede Route wird später detailiert beschrieben. Der erste Parameter für addRoute ist der Name der Route. Er wird als Handle verwendet um die Route außerhalb des Routers zu erhalten (z.B. für den Zweck der URL Erzeugung). Der zweite Parameter ist die Route selbst.
Routen ist ein einfacher Prozess des Durchlaufens aller vorhandenen Routen und Vergleichens deren Definitionen mit der aktuellen Anfrage URI. Wenn ein positiver Vergleich gefunden wird, werden variable Werte von der Instanz des Routers zurückgegeben, und werden für die spätere Verwendung im Dispatcher in das Zend_Controller_Request Objekt iniziiert, sowie in von Benutzern erstellten Controllern. Bei einem negativen Ergebnis des Vergleiches, wird die nächste Route in der Kette geprüft. Wenn man herausfinden will welche Route gepasst hat, kann man die getCurrentRouteName() Methode verwenden, die den Identifikator zurückgibt der verwendet wurde als die Route im Router registriert wurde. Wenn man das aktuelle Route Objekt benötigt, kann getCurrentRoute() verwendet werden.
Es gibt drei spezielle Variablen welche in den Routen verwendet werden können - 'module', 'controller' und 'action'. Diese speziellen Variablen werden durch Zend_Controller_Dispatcher verwendet um einen Controller und die Aktion zu funden zu der verwiesen wird.
Standard RoutenZend_Controller_Router_Rewrite kommt mit einer Standard Route vorkonfiguriert, welche URIs im Sinn von controller/action entspricht. Zusätzlich kann ein Modul Name als erstes Pfad Element definiert werden, welches URIs in der Form von module/controller/action erlaubt. Letztendlich wird es auch allen zusätzlichen Parametern entsprechen die der URI standardmäßig hinzugefügt wurden - controller/action/var1/value1/var2/value2. Einige Beispiele wie solche Routen verglichen werden:
Die Standardroute ist einfach ein Zend_Controller_Router_Route_Module Objekt welches unter dem Namen (Index) 'default' im RewriteRouter gespeichert ist. Es wird mehr oder weniger wie folgt erstellt:
Wenn diese spezielle Standard Route im eigenen Routing Schema nicht gewünscht ist, kann Sie durch Erstellung einer eigenen 'default' Route überschrieben werden (z.B. durch Speichern unter dem Namen 'default') oder dem kompletten Entfernen durch verwenden von removeDefaultRoutes():
Basis URL und UnterverzeichnisseDer Rewrite Router kann in Unterverzeichnissen verwendet werden (z.B. http://domain.com/user/application-root/) und in diesem Fall sollte die Basis URL der Anwendung (/user/application-root) automatisch durch Zend_Controller_Request_Http erkannt und auch verwendet werden. Sollte die Basis URL nicht richtig erkannt werden kann diese mit eigenen Basispfad überschrieben werden durch Verwendung von Zend_Controller_Request_Http und Auruf der setBaseUrl() Methode (siehe Basis URL und Unterverzeichnisse):
Globale ParameterMan kann in einem Router globale Parameter setzen die der Route automatisch zur Verfügung stehen wenn Sie durch setGlobalParam() eingefügt werden. Wenn ein globaler Parameter gesetzt ist, aber auch direkt an die Assemble Methode gegeben wird, überschreibt der Benutzer-Parameter den Globalen-Parameter. Globale Parameter können auf folgendem Weg gesetzt werden:
Router TypenZend_Controller_Router_RouteZend_Controller_Router_Route ist die standardmäßige Framework Route. Sie kombiniert einfache Verwendung mit einer flexiblen Routendefinition. Jede Route besteht primär aus URL Übereinstimmungen (von statischen und dynamischen Teilen (Variablen)) und kann mit Standardwerten initialisiert werden wie auch mit variablen Notwendigkeiten. Angenommen unsere fiktive Anwendung benötigt eine informelle Seite über den Seitenauthor. Es soll möglich sein mit dem Browser auf http://domain.com/author/martel zu verweisen um die Informationen über diesen "martel" Typ zu sehen. Und die Route für so eine Funktionalität würde so aussehen:
Der ersten Parameter im Konstruktor von Zend_Controller_Router_Route ist eine Routendefinition die einer URL entspricht. Routendefinitionen bestehen aus statischen und dynamischen Teilen die durch einen Schrägstrich ('/') seperiert sind. Statische Teile sind nur einfacher Text: author. Dynamische Teile, Variablen genannt, werden durch einen vorangestellten Doppelpunkt, zum variablen Namen, markiert: :username.
Diese Beispielroute wird verglichen wenn der Browser auf http://domain.com/author/martel zeigt. In diesem Fall werden alle seine Variablen dem Zend_Controller_Request Objekt injiziiert und es kann im ProfileController darauf zugegriffen werden. Variablen die von diesem Beispiel zurückgegeben werden können als Array mit den folgenden Schlüssel- und Wertepaaren repräsentiert werden:
Später sollte Zend_Controller_Dispatcher_Standard die userinfoAction() Methode der eigenen ProfileController Klasse aufrufen (im Standardmodul) basierend auf diesen Werten. Dort ist es möglich alle Variablen durch die Zend_Controller_Action::_getParam() oder Zend_Controller_Request::getParam() Methoden zuzugreifen:
Eine Routendefinition kann ein weiteres spezielles Zeichen enthalten - eine Wildcard - dargestellt durch ein '*' Symbol. Es wird verwendet um Parameter genauso wie im standard Modulrouter zu erhalten (var => Wertepaare definiert in der URI). Die folgende Route imitiert mehr oder weniger das Verhalten des Modulrouters:
Variable StandardsJede Variable im Router kann einen Standardwert haben und das ist für was der zweite Parameter des Konstruktors von Zend_Controller_Router_Route verwendet wird. Dieser Parameter ist ein Array mit Schlüsseln die Variablennamen repräsentieren und mit Werten als gewünschte Standards:
Die obige Route entspricht URLs wie http://domain.com/archive/2005 und http://example.com/archive. Im späteren Fall wird die Variable year einen initialen Standardwert von 2006 haben. Dieses Beispiel resultiert darin das eine year Variable in das Anfrage Objekt injiziiert wird. Da keine Routinginformation vorhanden ist (es sind keine Controller und Aktionsparameter definiert), wird die Anwendung zum Standardcontroller und der Aktionsmethode (welche beide in Zend_Controller_Dispatcher_Abstract definiert sind) weitergeleitet. Um es verwendbarer zu machen muß ein gültiger Controller und eine gültige aktion als Standard für die Route angegeben werden:
Diese Route führt dazu das an die Methode showAction() der Klasse ArchiveController weitergeleitet wird. Variable AnforderungenMan kann einen dritten Parameter dem Zend_Controller_Router_Route Konstruktor hinzufügen wo variable Anforderungen gesetzt werden können. Diese werden als Teil eines regulären Ausdrucks definiert: Mit einer Route die wie oben definiert ist, wird das Routing nur dann stattfinden wenn die year Variable nummerische Daten enthält, z.B. http://domain.com/archive/2345. Eine URL wie http://example.com/archive/test wird nicht zugeordnet und die Kontrolle wird stattdessen an die nächste Route in der Kette übertragen. Übersetzte SegmenteDie Standardroute unterstützt übersetzte Segmente. Um dieses Feature zu verwenden muß zumindest ein Übersetzer (eine Instanz von Zend_Translate) auf einem der folgenden Wege definiert werden:
Standardmäßig wird das Gebietsschema verwendet das in der Instanz von Zend_Translate verwendet wird. Um es zu überschreiben, kann es (als Instanz von Zend_Locale oder einem Gebietsschema-String) auf einem der folgenden Wege gesetzt werden:
Übersetzte Segmente werden in zwei Teile getrennt. Ein fixes Segment dem ein einzelnes @-Zeichen vorangestellt wird, der anhand des aktuellen Gebietsschemas übersetzt wird und auf der Position des Parameters eingefügt wird. Dynamischen Segmenten wird ein :@ vorangestellt. Beim Zusammenbauen, wird der gegebene Parameter übersetzt und an der Position des Parameters eingefügt. Bei der Überprüfung, wird der übersetzte Parameter von der URL wieder in die Nachrichten ID umgewandelt.
Nachfolgend ist die einfachste Verwendung gezeigt um eine Standardroute für übersetzte Segmente zu Verwenden:
Dieses Beispiel zeigt die Verwendung von statischen Segmenten:
Man kann dynamische Segmente verwenden um eine Modul-Route, so wie die übersetzte Version, zu erstellen:
Man kann auch statische und dynamische Segmente mischen:
Zend_Controller_Router_Route_StaticDie oben angeführten Beispiele verwenden alle dynamische Routen -- Routen die einem Pattern entsprechen. Trotzdem wird manchmal eine spezielle Route in Stein gegossen, und das Starten der Regular Expression Maschine wäre ein Overkill. Die Lösung zu dieser Situation ist die Verwendung von statischen Routen:
Die obige Route passt zu einer URL von http://domain.com/login, und leitet weiter zu AuthController::loginAction().
Zend_Controller_Router_Route_RegexZusätzlich zu den standard statischen Routetypen, ist ein Regular Expression Routetyp vorhanden. Diese Route bietet mehr Power und Flexibilität als die anderen, aber auf leichten Kosten von Komplexität. Wärend der selben Zeit, sollte Sie schneller als die Standardroute sein. Wie die Standardroute, muß diese Route mit einer Routendefinition und einigen Standardwerten initialisiert werden. Lasst uns eine Archivroute als Beispiel erstellen, ähnlich der zuletzt definierten, nur das dieses Mal die Regex Route verwendet wird:
Jedes definierte Regex Subpattern wird in das Anfrageobjekt injiziiert. Mit dem obigen Beispiel, nachdem http://domain.com/archive/2006 erfolgreich geprüft wurde, kann das resultierende Wertearray so aussehen:
Die Inhalte von definierten Subpattern können auf dem üblichen Weg bekommen werden:
Diese Route wird jetzt noch nicht exakt gleich wie Ihr Gegenspieler, die Standardroute, arbeiten da der Standard für 'year' noch nicht gesetzt ist. Und was jetzt noch nicht offensichtlich ist, ist das wir ein Problem mit endenden Schrägstrichen haben, selbst wenn wir einen Standard für das Jahr definieren und das Subpattern optional machen. Die Lösung ist, den ganzen year Teil optional zu nachen zusammen mit dem Schrägstrich, aber nur den nummerischen Teil zu holen:
Jetzt betrachten wir das Problem das möglicherweise schon selbst gefunden wurde. Die Verwendung von Integer basierten Schlüsseln für Parameter ist keine einfach zu handhabende Lösung und kann, während einer langen Laufzeit, potentiell problematisch sein. Hier kommt der dritte Parameter ins Spiel. Dieser Parameter ist ein assoziatives Array das einer Karte von Regex Subpatterns zu Parametern benannten Schlüsseln entspricht. Betrachten wir ein einfacheres Beispiel: Als Ergebnis werden die folgenden Werte in die Anfrage injiziiert:
Die Karte kann in jede Richtung definiert werden damit Sie in jeder Umgebung funktioniert. Schlüssel können Variablennamen oder Indezes von Subpattern enthalten:
Es gilt zu beachten das der nummerische Index in den Anfragewerten jetzt weg ist und eine benannte Variable statt Ihm angezeigt wird. Natürlich können nummerische und benannte Variablen gemischt werden wenn das gewünscht ist: Das führt zu gemischten Werten die in der Anfrage vorhanden sind. Als Beispiel, wird die URL http://domain.com/archive/2006/page/10 zu folgenden Werte führen:
Da Regex Patterns nicht einfach rückgängig zu machen sind, muß eine umgekehrte URL vorbereitet werden wenn ein URL Helfer verwendet werden soll oder sogar eine Herstellungsmethode dieser Klasse. Dieser umgekehrte Pfad wird durch einen String dargestellt der durch sprintf() durchsucht werden kann und als vierter Parameter definiert wird: Da all das bereits etwas ist das durch die Bedeutung eines standardmäßigen Route Objektes möglich ist kommt natürlich die Frage aus worin der Vorteil einer regex Route besteht? Primär erlaubt Sie jeden Typ von URL zu beschreiben ohne irgendwelche Einschränkungen. Angenommen man hat einen Blog und will eine URL wie die folgende erstellen: http://domain.com/blog/archive/01-Using_the_Regex_Router.html, und muß das jetzt Pfad Element 01-Using_the_Regex_Router.html bearbeiten, in eine Artikel ID und eine Artikel Titel oder Beschreibung; das ist nicht möglich mit der Standardroute. Mit der Regex Route ist etwas wie die folgende Lösung möglich: Wie man sieht, fügt das ein enormes Potential von Flexibilität zur Stnadardroute hinzu. Zend_Controller_Router_Route_HostnameZend_Controller_Router_Route_Hostname ist die Hostname Route des Frameworks. Sie arbeitet ähnlich wie die Standardrouten, aber Sie arbeitet an und mit dem Hostnamen der aufgerufenen URL statt mit dem Pfad. Verwenden wir also ein Beispiel von der Standardroute und schauen wir uns an wie Sie auf einem Hostnamen basierenden Weg aussehen würde. Statt das der Benutzer über einen Pfad aufgerufen wird, wollen wir das der Benutzer http://martel.users.example.com aufrufen kann, um die Informationen über den Benutzer "martel" zu sehen:
Der erste Parameter in Konstruktor von Zend_Controller_Router_Route_Hostname ist eine Routerdefinition die zu einem Hostnamen passt. Routerdefinitionen bestehen aus statischen und dynamischen Teilen die durch ein Punkt ('.') Zeichen getrennt sind. Dynamische Teile, genannt Variablen, werden durch einen, dem Variablennamen vorangestellten Doppelpunkt, gekennzeichnet: :username. Statische Teile sind nur einfacher Text: user. Hostnamerouten können verwendet werden wie sie sind, sollten es aber nie. Der Grund dahinter ist, das Hostnamerouten alleine jedem Pfad entsprechen würden. Was man also tun muß, ist eine Pfadroute an die Hostnameroute zu ketten. Das wird, wie im Beispiel, getan indem $hostnameRoute->chain($pathRoute); aufgerufen wird. Indem das getan wird, wird $hostnameRoute nicht geändert, aber eine neue Route (Zend_Controller_Router_Route_Chain), welche dann dem Router übergeben werden kann, wird zurückgegeben. Zend_Controller_Router_Route_ChainZend_Controller_Router_Route_Chain ist eine Route die es erlaubt mehrere Routen miteinander zu verketten. Das erlaubt es Hostname-Routen und Pfad-Routen zu verketten, oder zum Beispiel mehrere Pfad-Routen. Verkettung kann entweder program-technisch oder mit einer Konfigurationsdatei durchgeführt werden.
Wenn Programmtechnisch verkettet wird, gibt es zwei Wege das zu tun. Der erste besteht darin eine neue Instanz von Zend_Controller_Router_Route_Chain zu erstellen und dann die chain() Methode mehrere Male mit allen Routen aufzurufen die zusammen verkettet werden sollen. Der andere Weg besteht darin die erste Route zu nehmen, z.B. eine Hostname Route, und die chain() Methode mit der Route auf Ihr aufzurufen, die angehängt werden soll. Das verändert die Hostname Route nicht, gibt aber eine neue Instanz von Zend_Controller_Router_Route_Chain zurück, die dann beide Routen verkettet hat:
Wenn Routen miteinander verkettet werden, ist Ihr Trennzeichen ein Schrägstrich. Es kann Fälle geben in denen man ein anderes Trennzeichen verwenden will:
Verkettete Routen über Zend_ConfigUm Routen in einer Config Datei miteinander zu verketten gibt es zusätzliche Parameter für die Konfiguration von Ihnen. Der einfachere Weg ist die Verwendung des chains Parameters. Dieser ist einfach eine Liste von Routen, die mit der Eltern-Route verkettet werden. Weder die Eltern-, noch die Kind-Routen werden dem Router direkt hinzugefügt sondern nur die resultierende verkettete Route. Der Name der verketteten Route im Router ist standardmäßig der Name der Eltern-Route und der Name der Kind-Route verbunden mit einem Bindestrich (-). Eine einfache Konfiguration würde in XML wie folgt aussehen:
Das führt zu den drei Routen www-language-index, www-language-imprint und users-language-profile die nur basierend auf dem Hostnamen und der Route misc passen, was wiederum mit jedem Hostnamen passt. Der alternative Weg der Erstellung einer verketteten Route ist der über den chain Parameter, was wiederum nur mit dem Chain-Route Typ direkt verwendet werden kann, und auch im Root Level funktioniert:
Man kann auch den chain Parameter als Array übergeben statt die Routen mit einem Komma zu seperieren:
Wenn man Chain-Routen mit Zend_Config konfiguriert und will dass das Trennzeichen ein anderes als ein Unterstrich ist, dann muss man dises Trennzeichen separat spezifizieren:
Zend_Rest_RouteDie Komponente Zend_Rest enthält eine RESTvolle Route für Zend_Controller_Router_Rewrite. Diese Route bietet ein standardisiertes Routing Schema das Routinganfragen durch Übersetzung der HTTP Methode und der URI zu einem Modul, Controller und einer Action. Die unten stehende Tabelle bietet eine Übersicht darüber wie Anfragemethoden und URI's geroutet werden.
Verwendung von Zend_Rest_RouteUm Zend_Rest_Route für eine komplette Anwendung einzuschalten muss diese ohne Konfigurationsparameter erstellt und als Standardroute dem Frontcontroller hinzugefügt werden:
Um Zend_Rest_Route für spezielle Module einzuschalten muss diese mit einem Array von Modulnamen als 3tes Argument des Constructors erstellt werden: Um Zend_Rest_Route für spezielle Controller einzuschalten muss ein Array von Controllernamen als Wert für jedes Modul (Arrayelement) hinzugefügt werden. Zend_Rest_Route mit Zend_Config_IniUm Zend_Rest_Route von einer INI Konfigurationsdatei aus zu verwenden muss man den "route" Typ Parameter verwenden und die Konfigurationsoptionen setzen:
Die 'type' Option benennt den RESTvollen Routing Konfigurationstyp. Die 'defaults' Option wird verwendet um gemeinsame Standardmodule zu spezifizieren, und oder Aktionen für die Route. Alle anderen Optionen in der Konfigurationsgruppe werden als RESTvolle Modulnamen behandelt, und deren Werte sind RESTvolle Kontrollernamen. Die beispielhafte Konfiguration definiert Mod_ProjectController und Mod_UserController als RESTvolle Controller. Dann ist die addConfig() Methode des Rewrite Router Objekts zu verwenden:
Zend_Rest_ControllerUm bei der Entwicklung von Controllern zu Hilfe zu sein die mit Zend_Rest_Route verwendet werden, müssen die Controller von Zend_Rest_Controller erweitert werden. Zend_Rest_Controller definiert die 5 am meisten benötigten Operationen für RESTvolle Ressourcen in der Form von abstrakten Actionmethoden.
Zend_Config mit dem RewriteRouter verwendenManchmal 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: Als Beispiel wird die folgende INI Datei angenommen:
Die oben angeführte INI Datei kann dann wie folgt in ein Zend_Config Objekt eingelesen werden:
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_Route_Static zu verwenden. Erben vom RouterDer Standard Rewrite Router sollte die meisten Funktionalitäten die benötigt werden zur Verfügung stellen; meistens wird es nur notwendig sein einen neuen Router Typen zu erstellen um neue oder modifizierte Funktionalitäten für die verfügbaren Routen zu bieten. So gesehen, wird man in einigen Fällen ein anderes Routing Paradigma verwenden wollen. Das Interface Zend_Controller_Router_Interface bietet die minimalen Information die benötigt werden um einen Router er erstellen und besteht aus einer einzigen Methode.
Das Routing findet nur einmal statt, wenn die Anfrage das erste Mal vom System erhalten wird. Der Zweck des Routers ist es, Controller, Aktion und optionale Parameter auf Basis der Anfrageumgebung zu ermitteln und im Request zu setzen. Das Request Objekt wird dann an den Dispatcher übergeben. Wenn es nicht möglich ist, eine Route auf einen Dispatch Token abzubilden, soll der Router nichts mit dem Request Objekt machen.
|
|