| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 15156 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.front">
- <title>Der Front Controller</title>
- <sect2 id="zend.controller.front.overview">
- <title>Übersicht</title>
- <para>
- <classname>Zend_Controller_Front</classname> implementiert ein <ulink
- url="http://www.martinfowler.com/eaaCatalog/frontController.html">Front
- Controller-Entwurfsmuster</ulink>, das in <ulink
- url="http://de.wikipedia.org/wiki/Model_View_Controller">Model-View-Controller
- (MVC)</ulink>-Anwendungen verwendet wird. Seine Aufgabe ist, die Abfrage-Umgebung
- u initialisieren, die eingehende Abfrage zu routen und dann die Anfrage an alle
- angefragten Aktionen weiterzuleiten (das alles zusammen wird auch dispatchen
- genannt); er fasst alle Antworten zusammen und gibt sie zurück, wenn der Prozess
- beendet ist.
- </para>
- <para>
- <classname>Zend_Controller_Front</classname> implementiert auch das <ulink
- url="http://de.wikipedia.org/wiki/Einzelst%C3%BCck_%28Entwurfsmuster%29">Singleton-Entwurfsmuster
- </ulink>, das heißt nur eine einzige Instanz dieser Klasse darf zu jedem Zeitpunkt
- existieren. Das ermöglicht es auch, dass der Front-Controller als Registry fungiert, in
- der alle anderen Objekte des Prozesses Daten persistent speichern können.
- </para>
- <para>
- <classname>Zend_Controller_Front</classname> registriert einen <link
- linkend="zend.controller.plugins">Plugin-Broker</link> in der Registry, die er
- selber ist, was es erlaubt, verschiedene Events, die er auslöst, von den Plugins
- überwachen zu lassen. In den meisten Fällen gibt das dem Entwickler die Möglichkeit,
- einen maßgeschneiderten Dispatch-Prozess zu entwerfen, ohne den Front-Controller
- erweitern zu müssen um Funktionalität hinzuzufügen.
- </para>
- <para>
- Als ein absolutes Minimum, um zu funktionieren, braucht der Front-Controller den Pfad
- zu einem oder mehr Verzeichnissen, die
- <link linkend="zend.controller.action">Action-Controller</link> enthalten. Verschiedene
- Methoden können auch noch aufgerufen werden, um die Front-Controller-Umgebung und die
- seiner Hilfsklassen anzupassen.
- </para>
- <note>
- <title>Standardverhalten</title>
- <para>
- Standardmäßig lädt der Front-Controller sowohl das <link
- linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler</link>-Plugin
- als auch das <link
- linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>-Action-Helper-Plugin.
- Diese sind dafür geschrieben, Fehlerbehandlung bzw. das Rendern von Views in den
- Controllern zu vereinfachen.
- </para>
- <para>
- Um den <code>ErrorHandler</code> abzuschalten, kann der folgende Code an jeder
- Stelle vor dem Aufruf der <code>dispatch()</code>-Methode des Front-Controllers
- ausgeführt werden:
- </para>
- <programlisting role="php"><![CDATA[
- // Error-Handler-Plugin abschalten:
- $front->setParam('noErrorHandler', true);
- ]]></programlisting>
- <para>
- Um den <code>ViewRenderer</code> abzuschalten muss wiederum der folgende Code vor
- dem <code>dispatch()</code> ausgeführt werden:
- </para>
- <programlisting role="php"><![CDATA[
- // Den ViewRenderer Action-Helper deaktivieren:
- $front->setParam('noViewRenderer', true);
- ]]></programlisting>
- </note>
- </sect2>
- <sect2 id="zend.controller.front.methods.primary">
- <title>Grundlegende Methoden</title>
- <para>
- Der Front-Controller hat etliche Zugriffsmethoden, die benutzt werden können, um seine
- Umgebung zu konfigurieren. Jedoch gibt es drei grundlegende Methoden, die entscheidend
- für die funktionalität des Front-Controllers sind:
- </para>
- <sect3 id="zend.controller.front.methods.primary.getinstance">
- <title>getInstance()</title>
- <para>
- <code>getInstance()</code> wird benutzt, um eine Front-Controller-Instanz zu
- erhalten. Da der Front-Controller das Singleton-Entwurfsmuster implementiert, ist
- das auch die einzige Möglichkeit, ein Front-Controller-Objekt zu erhalten.
- </para>
- <programlisting role="php"><![CDATA[
- $front = Zend_Controller_Front::getInstance();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.setcontrollerdirectory">
- <title>setControllerDirectory() und addControllerDirectory()</title>
- <para>
- <code>setControllerDirectory()</code> wird benutzt, um <link
- linkend="zend.controller.dispatcher">dem Dispatcher</link>
- zu sagen, wo er nach <link
- linkend="zend.controller.action">Action-Controller</link>-Klassendateien suchen
- soll. Sie akzeptiert sowohl einen einzelnen Pfad als auch ein Array aus
- Modul/Pfad-Paaren.
- </para>
- <para>
- Ein Paar Beispiele:
- </para>
- <programlisting role="php"><![CDATA[
- // Standard-Controller-Verzeichnis setzen:
- $front->setControllerDirectory('../application/controllers');
- // Einige Modul-Ordner auf einmal setzen:
- $front->setControllerDirectory(array(
- 'default' => '../application/controllers',
- 'blog' => '../modules/blog/controllers',
- 'news' => '../modules/news/controllers',
- ));
- // Den Ordner für das Modul 'foo' hinzufügen:
- $front->addControllerDirectory('../modules/foo/controllers', 'foo');
- ]]></programlisting>
- <note>
- <para>
- Wenn <code>addControllerDirectory()</code> ohne einen Modulnamen verwendet wird,
- setzt sie den Ordner für das Modul <code>default</code> -- und überschreibt
- einen Pfad, der vorher gesetzt wurde.
- </para>
- </note>
- <para>
- Die aktuellen Einstellungen für den/die Controller-Ordner können mit
- <code>getControllerDirectory()</code> abgerufen werden; das gibt ein Array mit
- Modul/Verzeichnis-Paaren zurück.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.addmoduledirectory">
- <title>addModuleDirectory() und getModuleDirectory()</title>
- <para>
- Ein Aspekt des Frontcontrollers ist das man <link
- linkend="zend.controller.modular">eine modulare Verzeichnisstruktur definieren
- kann</link> für die Erstellung von alleinstehenden Komponenten; diese werden
- "Module" (modules) genannt.
- </para>
- <para>
- Jedes Modul sollte in seinem eigenen Verzeichnis sein und die Verzeichnisstruktur
- des Standardmoduls spiegeln -- z.B., sollte es mindestens ein "controllers"
- Unterzeichnis haben und typischerweise ein "views" Unterverzeichnis und andere
- Anwendungsverzeichnisse.
- </para>
- <para>
- <code>addModuleDirectory()</code> erlaubt es den Namen des Verzeichnisses zu
- übergeben der ein oder mehrere Modulverzeichnisse enthält. Er scannt dieses dann und
- fügt es den Controllerverzeichnissen des Frontcontrollers hinzu.
- </para>
- <para>
- Später, wenn man den Pfad zu einem speziellen Modul oder dem aktuellen Modul
- eruieren will, kann <code>getModuleDirectory()</code> aufgerufen werden und optional
- ein Modulname übergeben werden für das das spezielle Modulverzeichnis geholt werden
- soll.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.dispatch">
- <title>dispatch()</title>
- <para>
- <code>dispatch(Zend_Controller_Request_Abstract $request = null,
- Zend_Controller_Response_Abstract $response = null)</code>
- erledigt die Schwerstarbeit des Front-Controllers. Sie nimmt als Parameter optional
- ein <link linkend="zend.controller.request">Anfrage-Object</link> und/oder ein <link
- linkend="zend.controller.response">Antwort-Objekt</link> entgegen,
- was dem entwickler erlaubt, wahlweise eigene Objekte für diese beiden Aufgaben zu
- bestimmen.
- </para>
- <para>
- Wenn kein Anfrage- oder Antwort-Objekt angegeben werden, wird
- <code>dispatch()</code> nach vorher registrierten Objekten suchen und diese benutzen
- oder Standard-Versionen für seinen Prozess instanzieren (in beiden Fällen wird der
- HTTP-Dialekt als Standard benutzt).
- </para>
- <para>
- Auf ähnliche Art sucht <code>dispatch()</code> nach registrierten <link
- linkend="zend.controller.router">Router</link>- und <link
- linkend="zend.controller.dispatcher">Dispatcher</link>-Objekten und instanziert
- die Standard-Versionen wenn keine gefunden werden.
- </para>
- <para>
- Der Dispatch-Prozess hat drei verschiedene Schritte:
- </para>
- <itemizedlist>
- <listitem><para>Routing</para></listitem>
- <listitem><para>Dispatching</para></listitem>
- <listitem><para>Antwort</para></listitem>
- </itemizedlist>
- <para>
- Das Routing geschieht genau einmal, indem die Werte aus dem Anfrage-Objekt benutzt,
- die zum Zeitpunkt des Aufrufes von <code>dispatch()</code> vorhanden waren. Das
- Dispatchen geschieht in einer Schleife; eine Anfrage kann entweder melden, dass es
- mehrere Aktionen gibt, die ausgeführt werden sollen, oder der Controller oder ein
- Plugin können das Anfrage-Objekt zurücksetzen, um zu erzwingen, dass noch
- zusätzliche Aktionen ausgeführt werden sollen. Wenn alles erledigt ist, gibt der
- Front-Controller eine Antwort zurück.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.run">
- <title>run()</title>
- <para>
- <classname>Zend_Controller_Front::run($path)</classname> ist eine statische Methode,
- die einfach einen Pfad zu einem Verzeichnis, das Action-Controller enthält, als
- Parameter akzeptiert. Sie holt sich eine Front-Controller-Instanz (mit <link
- linkend="zend.controller.front.methods.primary.getinstance">getInstance()</link>,
- registriert den angegebenen Pfad mit <link
- linkend="zend.controller.front.methods.primary.setcontrollerdirectory">setControllerDirectory()</link>,
- und <link
- linkend="zend.controller.front.methods.primary.dispatch">dispatcht</link>
- schlussendlich.
- </para>
- <para>
- Im Grunde ist <code>run()</code> eine Komfort-Methode, die für Seitenkonstellationen
- benutzt werden kann, die keine Anpassung der Front-Controller-Umgebung benötigen.
- </para>
- <programlisting role="php"><![CDATA[
- // Front-Controller instanzieren, Controller-Verzeichnis setzen
- // und dispatchen in einem einfachen Schritt:
- Zend_Controller_Front::run('../application/controllers');
- ]]></programlisting>
- </sect3>
- </sect2>
- <sect2 id="zend.controller.front.methods.environment">
- <title>Methoden für Umgebungszugriff</title>
- <para>
- Zusätzlich zu den oben aufgelisteten Methoden gibt es eine Menge Zugriffsmethoden, die
- benutzt werden können, um die Front-Controller-Umgebung zu beeinflussen -- und damit die
- Umgebung der Klassen, an die der Front-Controller seine Arbeit weiterleitet.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>resetInstance()</code> wird benutzt, um alle aktuellen Einstellungen zu
- löschen. Ihr hauptsächlicher Nutzen sind Testfälle, aber sie kann auch für Fälle
- benutzt werden, in denen mehrere Front-Controller-Ausführungen aneinander
- gehängt werden sollen.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>(set|get)DefaultControllerName()</code> erlaubt es, dem Front-Controller
- einen anderen Namen für den Standard-Action-Controller mitzugeben (ansonsten
- wird 'index' benutzt), bzw. den aktuellen Wert herauszufinden. Diese Funktionen
- leiten die Anfragen an den <link
- linkend="zend.controller.dispatcher">Dispatcher</link> weiter.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>(set|get)DefaultAction()</code> erlaubt analog, den Standard-Aktionsnamen
- zu setzen - ohne Einstellung wird 'index' verwendet - und den aktuellen Wert
- auszulesen. Auch diese beiden leiten an den <link
- linkend="zend.controller.dispatcher">Dispatcher</link> weiter.
- </para>
- </listitem>
- <listitem>
- <para>
- Mit <code>(set|get)Request()</code> kann
- <link linkend="zend.controller.request">die Request</link> Klasse oder das
- Objekt, das während des Dispatch-Prozesses verwendet wird und um das aktuelle
- Objekt zu erhalten. Wenn das Requestobjekt gesetzt wird, kann ein
- Request-Klassenname übergeben werden, und in diesem Fall wird die Methode die
- Klassendatei laden und Sie initialisieren.
- </para>
- </listitem>
- <listitem>
- <para>
- Mit <code>(set|get)Router()</code> kann auf die gleiche Art der Klassenname bzw.
- das Objekt übergeben bzw. zurückgegeben werden, das beim dispatchen als
- <link linkend="zend.controller.router">Router</link> verwendet wird.
- </para>
- <para>
- Wenn nach dem Router-Objekt gefragt wird, wird erst überprüft, ob eines
- existiert. Wenn nicht, wird der Standard-Router (der Rewrite-Router) instanziert
- und zurückgegeben.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>(set|get)BaseUrl()</code> erlaubt es, die <link
- linkend="zend.controller.request.http.baseurl">Basis-URL</link> zu setzen,
- die beim Routen der Anfrage außen vor gelassen wird, sowie den aktuellen
- Wert dieser Einstellung zu erhalten. Diese URL wird dem Request-Objekt erst
- direkt vor dem Routing bekannt gemacht.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>(set|get)Dispatcher()</code> kann die <link
- linkend="zend.controller.dispatcher">Dispatcher</link>-Klasse/das
- Dispatcher-Objekt setzen, das den Dispatch-Prozess übernimmt. Wie oben, so kann
- auch hier ein Klassenname oder ein Objekt übergeben werden; die get-Methode gibt
- in jedem Fall ein Objekt zurück.
- </para>
- <para>
- Wenn das Dispatcher Objekt empfangen wird, wird erst überprüft, ob bereits ein
- Dispatcher existiert, wenn nicht, wird der Standard-Dispatcher instanziert und
- zurückgegeben.
- </para>
- </listitem>
- <listitem>
- <para>
- Über <code>(set|get)Response()</code> kann das <link
- linkend="zend.controller.response">Antwort-Objekt</link> gesetzt bzw. erhalten
- werden. Auch hier kann wieder ein Klassenname oder ein Objekt übergeben werden.
- </para>
- </listitem>
- <listitem>
- <para>
- Mit <code>registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex =
- null)</code> können
- <link linkend="zend.controller.plugins">Front-Controller-Plugins</link>
- registriert werden. Über den optionalen <code>$stackIndex</code> kann
- kontrolliert werden, in welcher Reihenfolge die Plugins ausgeführt werden.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>unregisterPlugin($plugin)</code> kann registrierte <link
- linkend="zend.controller.plugins">Plugin-Objekte</link> entfernen.
- <code>$plugin</code> kann entweder ein Plugin-Objekt oder eine Zeichenkette
- sein, die die Klasse des zu entfernenden Plugins angibt.
- </para>
- </listitem>
- <listitem>
- <para>
- Mit <code>throwExceptions($flag)</code> wird festgelegt, ob Exceptions
- (Ausnahmen), die während des Dispatch-Prozesses von Plugins, Controllern,
- Hilfsklassen etc. geworfen werden. Als Standardeinstellung werden Exceptions
- gefangen und im <link linkend="zend.controller.response">Antwort-Objekt</link>
- gespeichert. Das Einschalten von <code>throwExceptions()</code> überschreibt
- dieses Verhalten.
- </para>
- <para>
- Mehr Informationen gibt es hier: <xref
- linkend="zend.controller.exceptions" />.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>returnResponse($flag)</code> stellt ein, ob die Antwort nach
- <code>dispatch()</code> vom Front-Controller zurückgegeben werden soll
- (<code>true</code>) oder ob er sie automatisch ausgibt (<code>false</code>).
- In der Standardeinstellung wird die Antwort automatisch ausgegeben (durch
- Aufruf von
- <classname>Zend_Controller_Response_Abstract::sendResponse()</classname>); das
- Einschalten von <code>returnResponse()</code> ändert das.
- </para>
- <para>
- Gründe, die Antwort zurückzugeben, wären zum Beispiel der Wunsch, nach Fehlern
- zu suchen, bevor die Antwort ausgegeben wird, das Logging verschiedener Aspekte
- der Antwort (bspw. HTTP-Header), etc.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.front.methods.params">
- <title>Front Controller-Parameter</title>
- <para>
- In der Einführung haben wir erwähnt, dass der Front-Controller auch als eine Registry
- für die verschiedenen Controller-Komponenten fungiert. Das macht er über eine Gruppe von
- "param"-Methoden, de es erlauben, beliebige Daten -- Objekte und Variablen -- im
- Front-Controller zu registrieren, die dann zu jeder Zeit im Dispatch-Prozess abgerufen
- werden können. Diese Werte werden weitergegeben an den Router, den Dispatcher, und an
- die Aktions-Controller. Diese Methodengruppe besteht aus:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>setParam($name, $value)</code> setzt einen einzelnen Parameter mit dem
- Namen <code>$name</code> und dem Wert <code>$value</code>.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>setParams(array $params)</code> setzt mehrere Parameter auf einmal mit
- Hilfe eines assoziativen Arrays.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getParam($name)</code> gibt den Parameter <code>$name</code> zurück.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getParams()</code> gibt eine komplette Liste mit allen gesetzten
- Parametern zurück.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>clearParams()</code> kann einen Parameter löschen (wenn eine Zeichenkette
- mit einem gültigen Namen übergeben wird), mehrere benannte Parameter (wenn ein
- Array mit mehreren Parameter-Namen übergeben wird) oder alle (wenn nichts
- übergeben wird).
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Es gibt mehrere vordefinierte Parameter (die ebenfalls gesetzt werden können), die
- speziellen Einfluss auf den Dispatch-Prozess haben:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>useDefaultControllerAlways</code> wird benutzt, um dem <link
- linkend="zend.controller.dispatcher">Dispatcher</link> zu sagen, dass er,
- wenn er einen Fehler beim Dispatchen feststellt - also ein Modul / einen
- Controller / eine Aktionsmethode nicht findet, automatisch den
- Startseiten-Controller im Modul default benutzen soll. Standardmäßig
- ausgeschaltet.
- </para>
- <para>
- Siehe <xref linkend="zend.controller.exceptions.internal" />
- für detailliertere Informationen über die Benutzung dieser Einstellung.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>disableOutputBuffering</code> sagt dem <link
- linkend="zend.controller.dispatcher">Dispatcher</link>, dass er keinen
- Ausgabepuffer benutzen soll, um die Ausgabe, die von den Action-Controllern
- generiert wird, abzufangen. Standardmäßig werden sämtliche Ausgaben abgefangen
- und im Antwort-Objekt gespeichert.
- </para>
- </listitem>
- <listitem>
- <para>
- Wenn <code>noViewRenderer</code> auf true steht, wird der <link
- linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
- abgeschaltet.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>noErrorHandler</code> auf true schaltet das <link
- linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler-Plugin</link>
- ab.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.front.subclassing">
- <title>Erweitern des Front-Controllers</title>
- <para>
- Um den Front-Controller zu erweitern, muss als Minimalanforderung auf jeden Fall
- die Methode <code>getInstance()</code> überschrieben werden:
- </para>
- <programlisting role="php"><![CDATA[
- class My_Controller_Front extends Zend_Controller_Front
- {
- public static function getInstance()
- {
- if (null === self::$_instance) {
- self::$_instance = new self();
- }
- return self::$_instance;
- }
- }
- ]]></programlisting>
- <para>
- Das Überschreiben der <code>getInstance()</code>-Methode sorgt dafür, dass folgende
- Aufrufe von <classname>Zend_Controller_Front::getInstance()</classname> eine Instanz der
- neuen Subklasse zurückgeben anstatt einer
- <classname>Zend_Controller_Front</classname>-Instanz -- das ist speziell für einige der
- alternativen Router und View-Helfer nützlich.
- </para>
- <para>
- Typischerweise muss der Front-Controller nicht erweitert werden, es sei denn, es ist
- gewünscht, neue Funktionalität (wie zum Beispiel einen Plugin-Autoloader oder einen Weg,
- Action-Helper-Pfade anzugeben) hinzuzufügen. Einige Gelegenheiten, bei denen das
- Standard-Verhalten geändert werden könnte, wären zum Beispiel die Art, wie Controller
- geladen oder deren Pfade gespeichert werden, oder welcher Standard-Router und/oder
- Dispatcher benutzt werden.
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|