Inhaltsverzeichnis
Zend_Controller
stellt das Fundament für den Aufbau einer Website auf
Basis des Model-View-Controller (MVC) Entwurfsmusters bereit.
Das Zend_Controller
System wurde leichtgewichtig, modular und erweiterbar
aufgebaut. Das Design ist einfach, um den Benutzern viel Flexibilität und reiheiten zu
ermöglichen. Dennoch bietet es ausreichend Struktur, damit Systeme, die auf den
Zend_Controller
aufbauen, gemeinsame Konventionen befolgen und einen
ähnlichen Code Aufbau verwenden.
Der Zend_Controller
Ablauf wurde mit Hilfe verschiedener Komponenten
implementiert. Während es für die Benutzung des Systems nicht notwendig ist, den
kompletten Unterbau all dieser Komponenten zu verstehen, ist es hilfreich, über den
Ablauf ausreichend Kenntnisse zu haben.
Zend_Controller_Front
steuert den gesamten Ablauf des Zend_Controller
Systems. Es
ist eine Interpretation des FrontController Entwurfsmusters.
Zend_Controller_Front
verarbeitet alle Anfragen, die der
Server erhält, und ist letztendlich dafür verantwortlich, die Anfragen
an die ActionController (Zend_Controller_Action
) zu deligieren.
Zend_Controller_Request_Abstract
repräsentiert die Umgebung
der Anfrage und stellt Methoden für das Setzen und Abfragen der Namen für
Controller und Aktion sowie jeder Anfrageparameter bereit. Zusätzlich
behält es die Übersicht darüber, ob die enthaltene Aktion von
Zend_Controller_Dispatcher
verarbeitet wurde oder nicht.
Erweiterungen dieses abstrakten Request Objektes können verwendet werden,
um die gesamte Anfrageumgebung zu kapseln und Routern zu erlauben,
Informationen aus der Anfrageumgebung abzufragen, um die Namen für
Controller und Aktion zu setzen..
Standardmäßig wird Zend_Controller_Request_Http
verwendet,
welches den Zugriff auf die komplette HTTP Anfrageumgebung ermöglicht.
Zend_Controller_Router_Interface
wird verwendet, um Router zu
definieren. Routing ist der Prozess, bei dem die Anfrageumgebung untersucht
wird, um zu ermitteln, welcher Controller und welche Aktion dieses
Controllers diese Anfrage verarbeiten soll. Dieser Controller, diese Aktion
und optionale Parameter werden dann im Request Object gesetzt, das vom
Zend_Controller_Dispatcher_Standard
verarbeitet wird. Das
Routing wird nur einmal ausgeführt: wenn die Anfrage erhalten wird und
bevor der erste Controller aufgerufen wird.
Der Standardrouter ist Zend_Controller_Router_Rewrite
.
Der Standardrouter Zend_Controller_Router_Rewrite
nimmt den
URI Endpunkt entgegen, der in Zend_Controller_Request_Http
angegeben ist, und zerlegt ihn in einen Controller, eine Aktion und die
Parameter basierend auf den Pfadinformationen der URL. Zum Beispiel würde
die URL http://localhost/foo/bar/key/value
übersetzt, um den
foo
Controller und die bar
Aktion zu verwenden und
einen Parameter key
mit dem Wert value
anzugeben.
Zend_Controller_Router_Rewrite
kann auch für beliebige Pfade
verwendet werden; man beachte die
Rewrite Router Dokumentation für weitere Informationen.
Zend_Controller_Dispatcher_Interface
wird verwendet, um
Dispatcher zu definieren. Dispatching ist der Prozess, den Controller und
die Aktion aus dem Request Objekt abzufragen und auf eine Controller Datei/
Klasse und eine Aktionsmethode in dieser Controller Klasse zu abzubilden.
Wenn der Controller oder die Aktion nicht existieren, ermittelt es den zu
verarbeitenden Standard Controller und Aktion.
Der aktuelle Dispatcher Prozess besteht aus dem Instanzieren der Controller Klasse und dem Aufrufen der Aktionsmethode in dieser Klasse. Anders als das Routing, welches immer nur einmal vorkommt, erfolgt das Dispatching in einer Schleife. Wenn der Verarbeitungsstatus des Request Objektes irgendwann zurück gesetzt wird, wird die Schleife wiederholt und die Aktion aufgerufen, die zu diesem Zeitpunkt im Request Objekt gesetzt ist. Das erste Mal, wenn ein Schleifendurchlauf mit gesetztem Verarbeitungsstatus (boolsches true) im Request Objekt beendet wird, wird der Prozess beendet.
Der Standarddispatcher ist Zend_Controller_Dispatcher_Standard
.
Er definiert Controller als CamelCasedClasses, die auf das Wort Controller
enden, und Aktionsmethoden als camelCasedMethods, die auf das Wort Action
enden: SomeFooController::barAction
. In diesem Fall wird auf
den Controller über somefoo
und auf die Aktion über
bar
zugegriffen.
Zend_Controller_Action
ist die elementare Controller
Komponente. Jeder Controller ist eine einzelne Klasse, welche die
Zend_Controller_Action
Klasse erweitert und Methoden für die
Aktionen enthält.
Zend_Controller_Response_Abstract
definiert eine grundlegende
Response Klasse, um Antworten der Aktion aus den Controllern zu sammeln und
zurück zu geben. Es sammelt Header und Inhalte und kann, weil es
__toString()
implementiert, direkt ausgegeben werden, um alle
Header und Inhalte zusammen zu senden.
Die Standard Response Klasse ist Zend_Controller_Response_Http
,
welches in einer HTTP Umgebung verwendet werden kann.
Der Ablauf vom Zend_Controller
ist relativ einfach. Eine Anfrage wird vom
Zend_Controller_Front
empfangen, der wiederum Zend_Controller_Router_Rewrite
aufruft, um zu ermitteln, welcher Controller (und welche Aktion in dem Controller)
ausgeführt werden soll. Zend_Controller_Router_Rewrite
zerteilt die URI um
den Namen des Controllers und der Aktion für den Request zu setzen.
Zend_Controller_Front
durchläuft dann eine Dispatcher Schleife. Er ruft
Zend_Controller_Dispatcher_Standard
auf und übergibt den Request, um den
Controller und die Aktion auszuführen, die im Request spezifiziert wurden (oder
verwendet die Standardwerte). Wenn der Controller fertig ist, wird die Kontrolle wieder an
Zend_Controller_Front
übergeben. Wenn der Controller durch das Zurücksetzen
des Dispatch Status des Requests angezeigt hat, dass ein weiterer Controller ausgeführt
werden soll, wird der Durchlauf fortgesetzt und ein weiterer Dispatcher Prozess wird
durchlaufen. Andernfalls endet der Prozess.
Das Request Objekt ist eine einfaches Wertobjekt, das zwischen
Zend_Controller_Front
und den Router, Dispatcher und Controller Klassen
übergeben wird. Es enthält sowohl die Definition des Controllers, der Aktion und der
Parameter, die an die Aktion übergeben werden sollen, als auch den Rest der
Anfrageumgebung, seit es HTTP, CLI oder PHP-GTK.
Auf den Controller Namen kann über getControllerName()
und
setControllerName()
zugegriffen werden.
Auf den Namen der Aktion, die in diesem Controller aufgerufen wird, kann über
accessed by getActionName()
und setActionName()
zugegriffen werden.
Parameter, die an diese Aktion übergeben werden, bestehen aus einem assoziativen
Array mit Schlüssel/Wert Paaren, auf die komplett per getParams()
und
setParams()
oder einzeln per getParam()
und
setParam()
zugegriffen werden kann.
Abhängig vom Typ der Anfrage können auch weitere Methoden verfügbar sein. Das
verwendete Standard Request Object Zend_Controller_Request_Http
stellt z.B.
Methoden zum Abfragen der Request URI, Pfadinformationen, $_GET und $_POST Parameter
usw. bereit.
Das Request Objekt wird an den Front Controller übergeben oder, wenn keines bereit gestellt wurde, am Anfang des Dispatcher Prozesses instanziert, bevor das Routing beginnt. Es wird an jedes Objekt in der Dispatcherkette übergeben.
Zusätzlich ist das Request Object besonders beim Testen sehr nützlich. Der Entwickler kann die Anfrageumgebung von Hand erstellen, inklusive Controller, Aktion, Parameter, URI usw. und das Request Objekt an den Front Controller übrgeben, um den Ablauf der Applikation zu testen. Zusammen mit dem Response Objekt sind durchdachte und genaue Unit Tests für eine MVC Applikation möglich.
Bevor dein erster Controller erstellt werden kann, musst du die Funkktionsweise des
Routing Prozesses verstehen, wie er in Zend_Controller_Router_Rewrite
implementiert worden ist. Denke daran, dass der Ablauf unterteilt ist in das Routing,
das nur einmal ausgeführt wird, und das Dispatching, welches danach in einer Schleife
durchlaufen wird.
Zend_Controller_Front
ruft Zend_Controller_Router_Rewrite
(oder einen anderen registrierten Router) auf, um die URI auf einen Controller (und
eine Aktion in diesem Controller) abzubilden.
Zend_Controller_Router_Rewrite
empfängt die URI fom Request Objekt und
übergibt sie an die Route Objekte in seiner Kette; standardmäßig verwendet er
Zend_Controller_Router_Route_Module
um eingehende URLs zu zuordnen.
Das Route Objekt zerteilt die URL dann, um den Controller, die Aktion und andere, im
Pfad übergebene URL Parameter zu ermitteln; der Router setzt diese dann im Request
Objekt.
Zend_Controller_Router_Route_Module
verwendet eine sehr einfache
Zuordnung, um den Namen des Controllers und den Namen der Aktion innerhalb dieses
Controllers zu ermitteln.
http://framework.zend.com/controller/action/
Beachte im obigen Beispiel, dass das erste Segment immer den Namen des Controllers und das zweite Segment immer den Name der Aktion enthält.
Optional können in der URI auch Parameter definiert werden, die an den Controller übergeben werden. Diese haben die Form eines Schlüssel/Wert Paares:
http://framework.zend.com/controller/action/key1/value1/
Wenn weder der Controller noch die Aktion im URI Pfad vorhanden sind, versucht
Zend_Controller_Dispatcher_Standard
die Werte aus des Parametern des Request
Objektes zu bekommen und, falls nicht erfolgreich, die Standardwerte zu verwenden. In
beiden Fällen sind die Standardwerte "index
". Dieses Beispiel illustriert
dies:
http://framework.zend.com/roadmap/future/ Controller: roadmap Action : future http://framework.zend.com/roadmap/ Controller: roadmap Action : index http://framework.zend.com/ Controller: index Action : index
Flexibilität | |
---|---|
Wenn man flexiblere Möglichkeiten benötigt, sollte man den die Rewrite Router Dokumentation anschauen. |
Der Name des Controllers und der Aktion innerhalb dieses Controllers sowie weitere
optionale Parameter werden im Request Objekt gesetzt. Wenn
Zend_Controller_Front
die Dispatcher Schleife startet wird das Request
Objekt an Zend_Controller_Dispatcher_Standard
übergeben.
Dispatching ist der Prozess, das Request Objekt
Zend_Controller_Request_Abstract
zu übernehmen, die dort enthaltenen
Controller und Aktion Namen sowie die optionalen Parameter zu extrahieren und dann den
Controller zu instanzieren und die Aktion dieses Controllers aufzurufen. Wenn kein
Controller oder keine Aktion gefunden wurde, werden dafür Standardwerte verwendet.
Zend_Controller_Dispatcher_Standard
legt index
für beide als
Standardwert fest, aber erlaubt dem Entwickler auch, diese durch Verwendung der
setDefaultController()
und
setDefaultAction()
Methoden zu verändern.
Dispatching läuft innerhalb einer Schleife im Front Controller ab. Vor dem Dispatching fragt der Front Controller den Request ab, um benutzerspezifizierte Werte für Controller, Aktion und optionale Parameter zu finden. Dann startet er die Dispatch Schleife, um die Anfrage zu verarbeiten.
Zu Beginn jeden Durchlaufes setzt er im Request Objekt einen Schalter, der angibt, dass die Aktion verarbeitet worden ist. Wenn eine Aktion oder ein pre/postDispatch Plugin diesen Schalter zurücksetzt, wird die Dispatch Schleife fortgesetzt und versucht, die Anfrage erneut zu verarbeiten. Durch Ändern des Controllers und / oder der Aktion im Request Objekt und Zuürcksetzen des Verarbeitungsstatus, kann der Entwickler eine zu durchlaufende Anfragekette definieren.
Die Controller Methode, die solch eine Verarbeitung kontrolliert lautet
_forward()
; rufe diese Methode von einer beliebigen pre/postDispatch() oder
Aktionsmethode auf und übergebe Controller, Aktion und beliebige optionale Parameter,
die du zur neuen Aktion übersenden möchtest.
public function myAction() { // do some processing... // forward to another action, FooController::barAction(), in the current module: $this->_forward('bar', 'foo', null, array('baz' => 'bogus')); }
Das Response Objekt ist das logische Gegenstück zum Request Objekt. Sein Zweck ist es,
Inhalte und / oder Header zu vereinigen, um sie in einem Rutsch zu versenden.
Zusätzlich übergibt der Front Controller alle aufgefangenen Ausnahmen an das Response
Objekt, um dem Entwickler das Verarbeiten von Ausnahmen zu ermöglichen. Dies
Funktionalität kann durch Setzen von
Zend_Controller_Front::throwExceptions(true)
überschrieben werden.
$front->throwExceptions(true);
Um die Ausgabe der Response, inklusiver der gesetzten Header, zu senden, verwendet man
sendOutput()
:
$response->sendOutput();
Entwickler sollten das Response Objekt in ihren Aktionscontrollern verwenden. Statt die Ausgabe direkt zu machen und Header zu versenden, sollten diese an des Response Objekt übergeben werden:
// Innerhalb einer Controller Aktion: // Setze einen Header $this->getResponse() ->setHeader('Content-Type', 'text/html') ->appendBody($content);
Dadurch werden alle Header in einem Rutsch versendet, genau vor der Anzeige des Inhalts.
Sollte in der Applikation eine Ausnahme auftreten, überprüft man den
isException()
Schalter des Response Objektes und erhält die Ausnahme durch
Verwendung von getException()
. Zusätzlich kann man ein eigenes Response
Objekt erstellen, dass zu einer Fehlerseite umleitet, die Nachricht der Ausnahme loggt,
die Nachricht der Ausnahme schön formatiert ausgibt (für Entwicklungsumgebungen), usw.
Man kann das Response Objekt im Anschluß an die dispatch() Methode des Front Controllers erhalten oder den Front Controller auffordern, dass Response Objekt zurückzugeben statt den Inhalt auszugeben.
// Erhalten nach dem Dispatch: $front->dispatch(); $response = $front->getResponse(); if ($response->isException()) { // log, mail, etc... } // Oder den Front Controller dispatch Prozess auffordern, es zurück zu geben $front->returnResponse(true); $response = $front->dispatch(); // mache irgend was... // zum Schluß, gebe die Antwort aus $response->sendResponse();
Standardmäßig werden Ausnahmennachrichten nicht ausgegeben. Dieses Verhalten kann durch
den Aufruf von renderException()
überschrieben werden oder indem der
Front Controller aufgefordert wird, die Exceptions durch throwExceptions() auszuwerfen,
wie oben gezeigt:
$response->renderExceptions(true); $front->dispatch($request, $response); // oder: $front->returnResponse(true); $response = $front->dispatch(); $response->renderExceptions(); $response->sendOutput(); // oder: $front->throwExceptions(true); $front->dispatch();