<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 15156 -->
<!-- Reviewed: no -->
<sect1 id="zend.controller.action">
    <title>Action Kontroller</title>

    <sect2 id="zend.controller.action.introduction">
        <title>Einführung</title>
        <para>
            <classname>Zend_Controller_Action</classname> ist eine abstrakte Klasse die verwendet werden kann um Aktion
            Kontroller zu implementieren die mit dem Front Kontroller verwendet werden können um eine WebSeite
            zu erstellen die auf dem Model-View-Controller (MVC) Pattern basiert.
        </para>

        <para>
            Um <classname>Zend_Controller_Action</classname> zu verwenden, muß von dieser in der eigenen aktuellen
            Aktions Kontroller Klasse ererbt werden (oder von dieser erben um eine eigene Basisklasse für Aktion
            Kontroller zu erstellen). Die grundsätzlichste Operation ist es von Ihr zu erben und Aktions Methoden
            zu erstellen die den verschiedenen Aktionen entsprechen die der Kontroller der eigenen Seite handhaben
            soll. Das Handhaben von Routen und Dispatchen des <classname>Zend_Controller</classname>'s wird automatisch jegliche Methode
            die in der eigenen Klasse auf 'Action' endet, als potentielle Kontroller Aktion herausfinden.
        </para>

        <para>
            Soll unsere Klasse, zum Beispiel, wie folgt definiert sein:
        </para>

        <programlisting role="php"><![CDATA[
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        // mach irgendwas
    }

    public function bazAction()
    {
        // mach irgendwas
    }
}
]]></programlisting>

        <para>
            Die obige <code>FooController</code> Klasse (Kontroller <code>foo</code>) definiert zwei Aktionen,
            <code>bar</code> und <code>baz</code>.
        </para>

        <para>
            Da gibt es viel mehr das damit getan werden kann als das, wie eigene Initialisierungs Aktionen,
            Standardaktionen die aufgerufen werden wenn keine Aktion (oder eine ungültige Aktion) spezifiziert
            wird, pre- und post Dispatch Hooks, und eine Vielzahl von Helfer Methoden. Dieses Kapitel arbeitet als
            eine Übersicht der Aktion Kontroller Funktionalitäten.
        </para>

        <note>
            <title>Standardverhalten</title>

            <para>
                Standardmäßig aktiviert der <link linkend="zend.controller.front">Front Kontroller</link> den
                Aktion Helfer des <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>'s.
                Dieser Helfer übernimmt das Einfügen des View Objekts in den Kontroller, sowie das automatische
                Rendern der View. Er kann innerhalb des Aktion Kontrollers mit einer der folgenden Methoden
                ausgeschaltet werden:
            </para>

            <programlisting role="php"><![CDATA[
class FooController extends Zend_Controller_Action
{
    public function init()
    {
        // Lokal nur bei diesem Kontroller; beeinflußt alle Aktionen die mit
        // init geladen wurden:
        $this->_helper->viewRenderer->setNoRender(true);

        // Global:
        $this->_helper->removeHelper('viewRenderer');

        // Auch global, muß aber in Verbindung mit der Lokalen Version sein um
        // für diesen Kontroller zu gelten:
        Zend_Controller_Front::getInstance()
            ->setParam('noViewRenderer', true);
    }
}
]]></programlisting>

            <para>
                <code>initView()</code>, <code>getViewScript()</code>, <code>render()</code>, und
                <code>renderScript()</code> handeln alle in Vertretung zum <code>ViewRenderer</code> solange der
                Helfer nicht im Helfer Broker ist oder das <code>noViewRenderer</code> Flag nicht gesetzt wurde.
            </para>

            <para>
                Das rendern kann für individuelle Views auch ganz einfach ausgeschaltet werden durch setzen des
                <code>noRender</code> Flags des <code>ViewRenderer</code>'s:
            </para>

            <programlisting role="php"><![CDATA[
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        // Nur für diese Aktion das automatische Rendern ausschalten:
        $this->_helper->viewRenderer->setNoRender();
    }
}
]]></programlisting>

            <para>
                Der primäre Grund um den <code>ViewRenderer</code> auszuschalten ist, wenn einfach kein View Objekt
                benötigt wird, oder wenn nicht über ein View Skript gerendert werden soll (zum Beispiel wenn ein
                Aktion Kontroller  verwendet wird um Web Service Protokolle wie SOAP, XML-RPC oder REST anzubieten.
                In den meisten Fällen wird man den <code>ViewRenderer</code> nie global ausschalten müssen, nur
                selektiv innerhalb einzelner Kontroller oder Aktionen.
            </para>
        </note>
    </sect2>

    <sect2 id="zend.controller.action.initialization">
        <title>Objekt Initialisierung</title>

        <para>
            Wärend man immer den Konstruktor des Aktion Kontroller's überschreiben kann ist das nicht notwendig.
            <classname>Zend_Controller_Action::__construct()</classname> führt einige wichtige Aufgabe aus, wie das registrieren der Anfrage
            und Antwort Objekte, sowie alle eigene einleitenden Argumente die von Front Kontroller übergeben wurden.
            Wenn der Konstruktor überschrieben werden muß, muß sichergestellt sein das
            <code>parent::__construct($request, $response, $invokeArgs)</code> aufgerufen wird.
        </para>

        <para>
            Der bessere Weg als die Instanzierung zu ändern ist die Verwendung der <code>init()</code> Methode,
            welche nach der letzten Aufgabe von <code>__construct()</code> aufgerufen wird. Zum Beispiel wenn  man
            sich zu einer Datenbank bei der Instanzierung verbinden will:
        </para>

        <programlisting role="php"><![CDATA[
class FooController extends Zend_Controller_Action
{
    public function init()
    {
        $this->db = Zend_Db::factory('Pdo_Mysql', array(
            'host'     => 'myhost',
            'username' => 'user',
            'password' => 'XXXXXXX',
            'dbname'   => 'website'
        ));
    }
}
]]></programlisting>
    </sect2>

    <sect2 id="zend.controller.action.prepostdispatch">
        <title>Pre- und Post-Dispatch Hooks</title>

        <para>
            <classname>Zend_Controller_Action</classname> spezifiziert zwei Methoden die aufgerufen werden können um
            eine angefragte Aktion fertigzustellen, <code>preDispatch()</code> und <code>postDispatch()</code>.
            Diese können auf viele Wege nützlich sein: zum Beispiel um Authentifizierungen und ACLs prüfen bevor
            eine Aktion ausgeführt wird (durch Aufruf von <code>_forward()</code> in <code>preDispatch()</code>
            wird die Aktion übersprungen), oder erzeugte Inhalte in einem seitenweiten Template zu plazieren
            (<code>postDispatch()</code>).
        </para>
    </sect2>

    <sect2 id="zend.controller.action.accessors">
        <title>Zugriffe</title>

        <para>
            Eine Anzahl von Objekten und Variablen werden im Objekt registriert, und jede hat Zugriffsmethoden.
        </para>

        <itemizedlist>
            <listitem><para>
                <emphasis>Anfrage Objekt</emphasis>: <code>getRequest()</code> kann verwendet werden um das
                Anfrage Objekt zu erhalten das verwendet wurde um die Aktion aufzurufen.
            </para></listitem>

            <listitem>
                <para>
                    <emphasis>Antwort Objekt</emphasis>: <code>getResponse()</code> kann verwendet werden um das
                    Antwort Objekt zu erhalten das die letztendliche Antwort erzeugt. Einige typische Aufrufe
                    können wie folgt aussehen:
                </para>

                <programlisting role="php"><![CDATA[
$this->getResponse()->setHeader('Content-Type', 'text/xml');
$this->getResponse()->appendBody($content);
]]></programlisting>
            </listitem>

            <listitem>
                <para>
                    <emphasis>Aufgerufene Argumente</emphasis>: Der Front Kontroller kann Parameter in den Router,
                    Dispatcher und Aktion Kontroller einfügen. Um diese zu erhalten kann
                    <code>getInvokeArg($key)</code> verwendet werden; alternativ kann man die komplette Liste mit
                    <code>getInvokeArgs()</code> erhalten.
                </para>
            </listitem>

            <listitem>
                <para>
                    <emphasis>Anfrage Parameter</emphasis>: Das Anfrage Objekt liefert die Anfrage Parameter, wie
                    alle _GET oder _POST Parameter, oder Benutzer Parameter die in der Information des
                    URL Pfades spezifiziert sind. Um diese zu erhalten kann <code>_getParam($key)</code> oder
                    <code>_getAllParams()</code> verwendet werden. Es können auch Anfrage Parameter gesetzt werden
                    indem <code>_setParam()</code> verwendet wird; das ist nützlich wenn an zusätzliche Aktionen
                    weitergeleitet werden soll.
                </para>

                <para>
                    Um zu Testen ob ein Parameter existiert (nützlich für logische Auswahlen), kann
                    <code>_hasParam($key)</code> verwendet werden.
                </para>

                <note>
                    <para>
                        <code>_getParam()</code> kann ein optionales zweites Argument nehmen das einen Standardwert
                        enthält der verwendet wird wenn der Parameter nicht gesetzt oder leer ist. Wenn er
                        verwendet wird ist es nicht mehr notwendig <code>_hasParam()</code> vor dem Empfangen eines
                        Wertes aufzurufen:
                    </para>

                    <programlisting role="php"><![CDATA[
// Verwende des Standardwert 1 wenn id nicht gesetzt wurde
$id = $this->_getParam('id', 1);

// Statt:
if ($this->_hasParam('id') {
    $id = $this->_getParam('id');
} else {
    $id = 1;
}
]]></programlisting>
                </note>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.action.viewintegration">
        <title>View Integration</title>

        <note id="zend.controller.action.viewintegration.viewrenderer">
            <title>Standard View Integration über den ViewRenderer</title>

            <para>
                Der Inhalt dieses Kapitel ist nur gültig wenn man den
                <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link> explizit
                deaktiviert hat. Andernfalls kann man dieses kapitel ohne Bedenken überspringen.
            </para>
        </note>

        <para>
            <classname>Zend_Controller_Action</classname> bietet einen rudimentären und flexiblen Mechanismus für View
            Integration. Zwei Methoden machen das möglich, <code>initView()</code> und <code>render()</code>;
            die erste Methode lädt die öffnetliche Eigenschaft <code>$view</code> träge, und die zweite
            rendert eine View basierend auf der aktuell angefragen Aktion, wobei die Verzeichnis Hirarchie
            verwendet wird um den Pfad des Skripts zu ermitteln.
        </para>

        <sect3 id="zend.controller.action.viewintegration.initview">
            <title>View Initialisierung</title>

            <para>
                <code>initView()</code> initialisiert das View Objekt. <code>render()</code> ruft
                <code>initView()</code> auf um das View Objekt zu erhalten, aber es kann jederzeit initialisiert
                werden; standardmäßig wird die <code>$view</code> Eigenschaft mit einem <classname>Zend_View</classname>
                Objekt bekanntgegeben, aber jede Klasse die <classname>Zend_View_Interface</classname> implementiert kann
                verwendet werden. Wenn <code>$view</code> bereits initialisiert wurde, wird diese Eigenschaft
                einfach zurückgegeben.
            </para>

            <para>
                Die Standardimplementation macht die folgenden Annahmen über die Verzeichnisstruktur:
            </para>

            <programlisting role="php"><![CDATA[
applicationOrModule/
    controllers/
        IndexController.php
    views/
        scripts/
            index/
                index.phtml
        helpers/
        filters/
]]></programlisting>

            <para>
                In anderen Worten, wird angenommen das View Skripte im <code>views/scripts/</code> Unterverzeichnis
                sind, und das <code>views</code> Unterverzeichnis weitere Funktionalitäten enthält
                (helpers, filters). Wenn der Name und der Pfad des View Skripts ermittelt wird, wird das
                <code>views/scripts/</code> Verzeichnis als Basispfad verwendet, mit einem Verzeichnis das nach
                dem individuellen Kontroller benannt ist und eine Hierarchie von View Skripten bietet.
            </para>
        </sect3>

        <sect3 id="zend.controller.action.viewintegration.render">
            <title>Rendern von Views</title>

            <para>
                <code>render()</code> hat die folgende Signatur:
            </para>

            <programlisting role="php"><![CDATA[
string render(string $action = null,
              string $name = null,
              bool $noController = false);
]]></programlisting>

            <para>
                <code>render()</code> rendert ein View Skript. Wenn keine Argumente übergeben werden, wird angenommen
                das das angefragte Skript <code>[controller]/[action].phtml</code> ist (wobei <code>.phtml</code>
                der Wert der <code>$viewSuffix</code> Eigenschaft ist). Wenn ein Wert für <code>$action</code>
                angegeben wird, wird das Template im <code>[controller]</code> Unterverzeichnis gerendert. Um
                die Verwendung des <code>[controller]</code> Unterverzeichnisses zu überschreiben kann ein
                true Wert für <code>$noController</code> übergeben werden. Zuletzt werden templates in das
                Antwort Objekt gerendert; wenn zu einem spezifischen
                <link linkend="zend.controller.response.namedsegments">benannten Segment</link> im Antwort Objekt
                gerendert werden soll, kann ein Wert an <code>$name</code> übergeben werden.
            </para>

            <note><para>
                    Da Kontroller- und Aktionsnamen Wort Begrenzer Zeichen enthalten können wie z.B. '_', '.' und
                    '-', normalisiert <code>render()</code> diese zu '-' wenn der Skript Name eruiert wird. Intern werden die
                    Wort- und Pfadbegrenzer vom Dispatcher verwendet um die Normalisierung durchzuführen. Deshalb
                    wird eine Anfrage auf <code>/foo.bar/baz-bat</code> das Skript auf
                    <code>foo-bar/baz-bat.phtml</code> rendern. Wenn eine Aktionsmethode camelCase Zeichen enthält,
                    muß beachtet werden das diese in '-' seperierten Wörter umgewandelt werden wenn der Dateiname
                    des View Skripts eruiert wird.
            </para></note>

            <para>
                Einige Beispiele:
            </para>

            <programlisting role="php"><![CDATA[
class MyController extends Zend_Controller_Action
{
    public function fooAction()
    {
        // Rendert my/foo.phtml
        $this->render();

        // Rendert my/bar.phtml
        $this->render('bar');

        // Rendert baz.phtml
        $this->render('baz', null, true);

        // Rendert my/login.phtml in das 'form' Segment des Antwort Objektes
        $this->render('login', 'form');

        // Rendert site.phtml in das 'page' Segmetn des Antwort Objektes;
        // verwendet nicht das 'my/' Unterverzeichnis
        $this->render('site', 'page', true);
    }

    public function bazBatAction()
    {
        // Rendert my/baz-bat.phtml
        $this->render();
    }
}
]]></programlisting>
        </sect3>
    </sect2>

    <sect2 id="zend.controller.action.utilmethods">
        <title>Nützliche Methoden</title>

        <para>
            Neben den Zugriffs- und View Integrationsmethoden, hat <classname>Zend_Controller_Action</classname> verschiedene
            nützliche Methoden für die Durchführung üblicher Aufgaben von innerhalb der Aktionsmethoden (oder vom
            Pre-/Post-Dispatch).
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <code>_forward($action, $controller = null, $module = null, array $params = null)</code>:
                    führt eine weitere Aktion aus. Wenn in <code>preDispatch()</code> aufgerufen, wird die aktuelle
                    aufgerufene Aktion übersprungen zugunsten der neuen. Andererseits, wenn die aktuelle Aktion
                    durchgeführt wurde, wird die Aktion die in _forward() angefragt wird, ausgeführt.
                </para>
            </listitem>

            <listitem>
                <para>
                    <code>_redirect($url, array $options = array())</code>: leitet zu einem anderen Ort um. Diese
                    Methode nimmt eine URL und ein optionales Set von Optionen. Standardmäßig führt Sie eine
                    HTTP 302 Umleitung durch.
                </para>

                <para>
                    Diese Optionen können ein oder mehrere der folgenden enthalten:
                </para>

                <itemizedlist>
                    <listitem>
                        <para>
                            <emphasis>exit:</emphasis> ob oder ob nicht sofort ausgestiegen werden soll. Wenn
                            angefragt, wird jede offene Session sauber beendet und die Umleitung durchgeführt.
                        </para>

                        <para>
                            Diese Option kann global im Kontroller gesetzt werden indem der
                            <code>setRedirectExit()</code> Zugriff verwendet wird.
                        </para>
                    </listitem>

                    <listitem>
                        <para>
                            <emphasis>prependBase:</emphasis> ob oder ob nicht, die im Anfrage Objekt registrierte
                            Basis URL, dem angebotenen URL angehängt wird.
                        </para>

                        <para>
                            Diese Option kann gobal im Kontroller gesetzt werden indem der
                            <code>setRedirectPrependBase()</code> Zugriff verwendet wird.
                        </para>
                    </listitem>

                    <listitem>
                        <para>
                            <emphasis>code:</emphasis> welche HTTP Code für die Umleitung verwendet wird.
                            Standardmäßig wird ein HTTP 302 erstellt; jeder Code zwischen 301 und 306 kann
                            verwendet werden.
                        </para>

                        <para>
                            Diese Option kann global im Kontroller gesetzt werden indem der
                            <code>setRedirectCode()</code> Zugriff verwendet wird.
                        </para>
                    </listitem>
                </itemizedlist>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.action.subclassing">
        <title>Erweitern des Aktion Kontrollers</title>

        <para>
            Vom Design her muß <classname>Zend_Controller_Action</classname> erweitert werden um einen Aktion Kontroller
            zu erstellen. Als Minimum, muß eine Aktions Methode definiert werden die der Kontroller aufrufen kann.
        </para>

        <para>
            Neben dem erstellen von nützlichen Funktionalitäten für Web Anwendungen, wird auch die Notwendigkeit
            bestehen das vom gleichen Setup oder von den nützlichen Funktionen vieles in verschiedenen
            Kontrollern wiederholt wird; wenn dem so ist, löst die Erstellung einer gemeinsamen Basis Kontroller
            Klasse die <classname>Zend_Controller_Action</classname> erweitert zu einer Lösung dieser Redundanz.
        </para>

        <example id="zend.controller.action.subclassing.example-call">
            <title>Behandeln nicht-vorhandener Aktionen</title>

            <para>
                Wenn eine Anfrage an einen Kontroller durchgeführt wird die eine undefinierte Aktions Methode
                enthält, kommt <classname>Zend_Controller_Action::__call()</classname> zum Einsatz. <code>__call()</code>
                ist natürlich PHP's magische Methode für das Überladen von Methoden.
            </para>

            <para>
                Standardmäßig wirft diese Methode eine <classname>Zend_Controller_Action_Exception</classname> die anzeigt
                das die angefragte Aktion nicht im Kontroller gefunden werden konnte. Wenn die angefragte
                Methode mit 'Action' endet, wird angenommen das eine Aktion angefragt wurde die nicht existiert;
                solch ein Fehler resultiert in einer Ausnahme mit dem Code 404. Alle anderen Methoden resultieren
                in einer Ausnahme mit dem Code 500. Das erlaubt die einfache Differenzierung zwischen Seiten
                die nicht gefunden wurden und Anwendungsfehlern in der Fehlerbehandlung.
            </para>

            <para>
                Diese Funktionalität sollte überschrieben werden wenn eine andere Operation ausgeführt werden
                soll. Wenn zum Beispiel eine Fehlermeldung angezeigt werden soll kann etwas die das folgende
                geschrieben werden:
            </para>

            <programlisting role="php"><![CDATA[
class MyController extends Zend_Controller_Action
{
    public function __call($method, $args)
    {
        if ('Action' == substr($method, -6)) {
            // Wenn die Aktionsmethode nicht gefunden wurde,
            // das error Template darstellen
            return $this->render('error');
        }

        // Alle anderen Methoden werfen eine Ausnahme
        throw new Exception('Invalid method "'
                            . $method
                            . '" called',
                            500);
    }
}
]]></programlisting>

            <para>
                Eine andere Möglichkeit ist das man zu einer standardmäßigen Kontroller Seiten weiterleiten will:
            </para>

            <programlisting role="php"><![CDATA[
class MyController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $this->render();
    }

    public function __call($method, $args)
    {
        if ('Action' == substr($method, -6)) {
            // Wenn die Aktionsmethode nicht gefunden wurde,
            // leite zur Index Aktion weiter
            return $this->_forward('index');
        }

        // Alle anderen Methoden werden eine Ausnahme
        throw new Exception('Invalid method "'
                            . $method
                            . '" called',
                            500);
    }
}
]]></programlisting>
        </example>

        <para>
            Neben dem überschreiben von <code>__call()</code>, kann jede der Initialisierungs-, Utility-, Zugriffs-,
            View- und Dispatch-Hook Methoden die vorher in diesem Kapitel beschrieben wurden, überschrieben werden
            um eigene Kontroller anzupassen. Wenn man, als Beispiel, die View Objekte in der Registry speichert,
            kann es gewünscht sein die <code>initView()</code> Methode mit Code zu Ändern der das folgende
            zusammensetzt:
        </para>

        <programlisting role="php"><![CDATA[
abstract class My_Base_Controller extends Zend_Controller_Action
{
    public function initView()
    {
        if (null === $this->view) {
            if (Zend_Registry::isRegistered('view')) {
                $this->view = Zend_Registry::get('view');
            } else {
                $this->view = new Zend_View();
                $this->view->setBasePath(dirname(__FILE__) . '/../views');
            }
        }

        return $this->view;
    }
}
]]></programlisting>

        <para>
            Hoffentlich kann man anhand der Informationen in diesem Kapitel ersehen wie flexibel diese spezielle
            Komponente ist und wie Sie in eigene Anwendungen oder den Notwendigkeiten von Seiten damit erfüllt
            werden kann.
        </para>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
