| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: 17175 -->
- <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
- zu 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 mehreren 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 <emphasis>ErrorHandler</emphasis> abzuschalten, kann der folgende Code an
- jeder Stelle vor dem Aufruf der <methodname>dispatch()</methodname>-Methode des
- Front-Controllers ausgeführt werden:
- </para>
- <programlisting language="php"><![CDATA[
- // Error-Handler-Plugin abschalten:
- $front->setParam('noErrorHandler', true);
- ]]></programlisting>
- <para>
- Um den <emphasis>ViewRenderer</emphasis> abzuschalten muss wiederum der folgende
- Code vor dem <methodname>dispatch()</methodname> ausgeführt werden:
- </para>
- <programlisting language="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>
- <methodname>getInstance()</methodname> 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 language="php"><![CDATA[
- $front = Zend_Controller_Front::getInstance();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.setcontrollerdirectory">
- <title>setControllerDirectory() und addControllerDirectory()</title>
- <para>
- <methodname>setControllerDirectory()</methodname> 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 und Pfadpaaren.
- </para>
- <para>
- Ein Paar Beispiele:
- </para>
- <programlisting language="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 <methodname>addControllerDirectory()</methodname> ohne einen Modulnamen
- verwendet wird, setzt sie den Ordner für das Modul <emphasis>default</emphasis>
- -- und überschreibt einen Pfad, der vorher gesetzt wurde.
- </para>
- </note>
- <para>
- Die aktuellen Einstellungen für den/die Controller-Ordner können mit
- <methodname>getControllerDirectory()</methodname> abgerufen werden; das gibt ein
- Array mit Modul- und Verzeichnispaaren zurück.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.addmoduledirectory">
- <title>addModuleDirectory() und getModuleDirectory()</title>
- <para>
- Ein Aspekt des Front-Controllers ist, dass man für die Erstellung von
- alleinstehenden Komponenten <link linkend="zend.controller.modular">eine modulare
- Verzeichnisstruktur definieren kann</link>; 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
- <filename>/controllers/</filename> Unterverzeichnis haben und typischerweise ein
- <filename>/views/</filename> Unterverzeichnis und andere Anwendungsverzeichnisse.
- </para>
- <para>
- <methodname>addModuleDirectory()</methodname> 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 Front-Controllers
- hinzu.
- </para>
- <para>
- Später, wenn man den Pfad zu einem speziellen Modul oder dem aktuellen Modul
- eruieren will, kann <methodname>getModuleDirectory()</methodname> aufgerufen werden
- und optional ein Modulname übergeben werden, für welches das spezielle
- Modulverzeichnis geholt werden soll.
- </para>
- </sect3>
- <sect3 id="zend.controller.front.methods.primary.dispatch">
- <title>dispatch()</title>
- <para>
- <methodname>dispatch(Zend_Controller_Request_Abstract $request = null,
- Zend_Controller_Response_Abstract $response = null)</methodname>
- 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 es dem Entwickler erlaubt, wahlweise eigene Objekte für diese beiden Aufgaben zu
- bestimmen.
- </para>
- <para>
- Wenn kein Anfrage- oder Antwort-Objekt angegeben werden, wird
- <methodname>dispatch()</methodname> nach vorher registrierten Objekten suchen und
- diese benutzen oder Standardversionen für seinen Prozess instanzieren (in beiden
- Fällen wird der <acronym>HTTP</acronym>-Dialekt als Standard benutzt).
- </para>
- <para>
- Auf ähnliche Art sucht <methodname>dispatch()</methodname> nach registrierten <link
- linkend="zend.controller.router">Router</link>- und <link
- linkend="zend.controller.dispatcher">Dispatcher</link>-Objekten und instanziert
- die Standardversionen 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 Anfrageobjekt benutzt,
- die zum Zeitpunkt des Aufrufes von <methodname>dispatch()</methodname> 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 Anfrageobjekt 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>
- <methodname>Zend_Controller_Front::run($path)</methodname> 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 <methodname>run()</methodname> eine Komfort-Methode, die für
- Seitenkonstellationen benutzt werden kann, die keine Anpassung der
- Front-Controller-Umgebung benötigen.
- </para>
- <programlisting language="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>
- <methodname>resetInstance()</methodname> 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>
- <methodname>setDefaultControllerName()</methodname> und
- <methodname>getDefaultControllerName()</methodname> erlauben 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>
- <methodname>setDefaultAction()</methodname> und
- <methodname>getDefaultAction()</methodname> erlauben 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 <methodname>setRequest()</methodname> und
- <methodname>setRequest()</methodname> 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 <methodname>setRouter()</methodname> sowie
- <methodname>setRouter()</methodname> 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>
- <methodname>setBaseUrl()</methodname> und
- <methodname>getBaseUrl()</methodname> erlauben es, die <link
- linkend="zend.controller.request.http.baseurl">Basis
- <acronym>URL</acronym></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>
- <methodname>setDispatcher()</methodname> und
- <methodname>getDispatcher()</methodname> kann die <link
- linkend="zend.controller.dispatcher">Dispatcher</link>-Klasse oder 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 <methodname>setResponse()</methodname> und
- <methodname>getResponse()</methodname> 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 <methodname>registerPlugin(Zend_Controller_Plugin_Abstract $plugin,
- $stackIndex = null)</methodname> können
- <link linkend="zend.controller.plugins">Front-Controller-Plugins</link>
- registriert werden. Über den optionalen <varname>$stackIndex</varname> kann
- kontrolliert werden, in welcher Reihenfolge die Plugins ausgeführt werden.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>unregisterPlugin($plugin)</methodname> kann registrierte <link
- linkend="zend.controller.plugins">Plugin-Objekte</link> entfernen.
- <varname>$plugin</varname> kann entweder ein Plugin-Objekt oder eine
- Zeichenkette sein, welche die Klasse des zu entfernenden Plugins angibt.
- </para>
- </listitem>
- <listitem>
- <para>
- Mit <methodname>throwExceptions($flag)</methodname> 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 <methodname>throwExceptions()</methodname> überschreibt dieses
- Verhalten.
- </para>
- <para>
- Mehr Informationen gibt es hier: <link
- linkend="zend.controller.exceptions">MVC Exceptions</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>returnResponse($flag)</methodname> stellt ein, ob die Antwort nach
- <methodname>dispatch()</methodname> vom Front-Controller zurückgegeben werden
- soll (<constant>TRUE</constant>) oder ob er sie automatisch ausgibt
- (<constant>FALSE</constant>). In der Standardeinstellung wird die Antwort
- automatisch ausgegeben (durch Aufruf von
- <methodname>Zend_Controller_Response_Abstract::sendResponse()</methodname>);
- das Einschalten von <methodname>returnResponse()</methodname> ä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>
- <methodname>setParam($name, $value)</methodname> setzt einen einzelnen
- Parameter mit dem Namen <varname>$name</varname> und dem Wert
- <varname>$value</varname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setParams(array $params)</methodname> setzt mehrere Parameter auf
- einmal mit Hilfe eines assoziativen Arrays.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getParam($name)</methodname> gibt den Parameter
- <varname>$name</varname> zurück.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getParams()</methodname> gibt eine komplette Liste mit allen
- gesetzten Parametern zurück.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearParams()</methodname> 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 und die
- speziellen Einfluss auf den Dispatch-Prozess haben:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>useDefaultControllerAlways</emphasis> 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 das Kapitel <link linkend="zend.controller.exceptions.internal">MVC
- Exceptions denen man begegnen kann</link> für detailliertere Informationen
- über die Benutzung dieser Einstellung.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>disableOutputBuffering</emphasis> 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 <emphasis>noViewRenderer</emphasis> auf <constant>TRUE</constant> steht,
- wird der <link
- linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
- abgeschaltet.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>noErrorHandler</emphasis> auf <constant>TRUE</constant> 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 <methodname>getInstance()</methodname> überschrieben werden:
- </para>
- <programlisting language="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 <methodname>getInstance()</methodname>-Methode sorgt dafür, dass
- folgende Aufrufe von <methodname>Zend_Controller_Front::getInstance()</methodname> 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
- Standardverhalten 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:
- -->
|