<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: 21826 -->
<sect1 id="zend.controller.request">
    <title>Das Request-Objekt</title>

    <sect2 id="zend.controller.request.introduction">
        <title>Einführung</title>

        <para>
            Das Request-Objekt ist eine einfaches Werteobjekt, das zwischen
            <classname>Zend_Controller_Front</classname> 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, sei es <acronym>HTTP</acronym>, <acronym>CLI</acronym> oder
            <acronym>PHP</acronym>-GTK.
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    Auf den Modulnamen kann über <methodname>getModuleName()</methodname> und
                    <methodname>setModuleName()</methodname> zugegriffen werden.
                </para>
            </listitem>

            <listitem>
                <para>
                    Auf den Controller-Namen kann über <methodname>getControllerName()</methodname>
                    und <methodname>setControllerName()</methodname> zugegriffen werden.
                </para>
            </listitem>

            <listitem>
                <para>
                    Auf den Namen der Aktion, die in diesem Controller aufgerufen wird, kann über
                    <methodname>getActionName()</methodname> und
                    <methodname>setActionName()</methodname> zugegriffen werden.
                </para>
            </listitem>

            <listitem>
                <para>
                    Parameter, die von der Aktion ansprechbar sind, bestehen aus einem assoziativen
                    Array mit Paaren von Schlüsseln und Werten, auf die komplett per
                    <methodname>getParams()</methodname> und <methodname>setParams()</methodname>
                    oder einzeln per <methodname>getParam()</methodname> und
                    <methodname>setParam()</methodname> zugegriffen werden kann.
                </para>
            </listitem>
        </itemizedlist>

        <para>
            Abhängig vom Typ der Anfrage können auch weitere Methoden verfügbar sein. Das
            verwendete Standard-Request-Objekt <classname>Zend_Controller_Request_Http</classname>
            stellt z.B. Methoden zum Abfragen der Request-<acronym>URI</acronym>, Pfadinformationen,
            den Parametern <varname>$_GET</varname> und <varname>$_POST</varname> usw. bereit.
        </para>

        <para>
            Das Request-Objekt wird an den FrontController ü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.
        </para>

        <para>
            Zusätzlich ist das Request-Objekt besonders beim Testen sehr nützlich. Der Entwickler
            kann die Anfrageumgebung von Hand erstellen, inklusive Controller, Aktion, Parameter,
            <acronym>URI</acronym> usw. und das Request-Objekt an den Front Controller übergeben, um
            den Ablauf der Applikation zu testen. Zusammen mit dem
            <link linkend="zend.controller.response">Response-Objekt</link> sind durchdachte und
            genaue UnitTests für eine <acronym>MVC</acronym>-Applikation möglich.
        </para>
    </sect2>

    <sect2 id="zend.controller.request.http">
        <title>HTTP-Anfragen</title>

        <sect3 id="zend.controller.request.http.dataacess">
            <title>Auf Request-Daten zugreifen</title>

            <para>
                <classname>Zend_Controller_Request_Http</classname> kapselt den Zugriff auf
                relevante Werte wie Schlüsselname und Wert für Controller und Action, Variablen des
                Routers und alle zusätzlichen Parameter, die aus der <acronym>URI</acronym>
                ermittelt wurden. Es erlaubt zusätzlich den Zugriff auf superglobale Werte als
                öffentliche Eigenschaften und verwaltet die aktuelle Basis-<acronym>URL</acronym>
                und Request-<acronym>URI</acronym>. Superglobale Werte können in einem
                Request-Objekt nicht gesetzt werden, stattdessen verwendet man die
                Methoden <methodname>setParam()</methodname> und <methodname>getParam()</methodname>
                um Benutzerparameter zu setzen oder zu erhalten.
            </para>

            <note>
                <title>Superglobale Daten</title>

                <para>
                    Beim Zugriff auf superglobale Daten über die öffentlichen Eigenschaften von
                    <classname>Zend_Controller_Request_Http</classname> ist es notwendig, darauf zu
                    achten, dass der Eigenschaftsname (der superglobale Arrayschlüssel) einem
                    superglobalen Wert in einer bestimmten Reihenfolge entspricht: 1.
                    <constant>GET</constant>, 2. <constant>POST</constant>, 3.
                    <constant>COOKIE</constant>, 4. <constant>SERVER</constant>, 5.
                    <constant>ENV</constant>.
                </para>
            </note>

            <para>
                Auf spezifische superglobale Werte kann alternativ über eine öffentliche Methode
                zugegriffen werden. Zum Beispiel kann auf den unverarbeiteten Wert von
                <varname>$_POST['user']</varname> durch Aufruf der
                Methode <methodname>getPost('user')</methodname> des Request-Objekts zugegriffen
                werden. Diese beinhalten <methodname>getQuery()</methodname>, um
                <varname>$_GET</varname>-Elemente zu erhalten und
                <methodname>getHeader()</methodname>, um Request-Header zu erhalten.
            </para>

            <note>
                <title>GET- und POST-Daten</title>

                <para>
                    Es ist Vorsicht geboten, wenn auf Daten eines Anfrageobjekts zugegriffen wird,
                    da diese in keiner Weise gefiltert werden. Der Router und Dispatcher prüfen und
                    filtern Daten für die Verwendung innerhalb ihrer Aufgabe, lassen diese Daten
                    aber unangetastet im Anfrageobjekt.
                </para>
            </note>

            <note>
                <title>Abfrage der unverarbeitetet ("raw") POST-Daten</title>

                <para>
                    Ab 1.5.0 können auch die rohen POST-Daten über die
                    Methode <methodname>getRawBody()</methodname> erhalten werden. Diese Methode
                    gibt <constant>FALSE</constant> zurück, wenn keine Daten auf diesem Weg
                    übermittelt wurden, andernfalls den kompletten Inhalt von POST.
                </para>

                <para>
                    Das ist grundsätzlich sinnvoll, um Inhalt zu akzeptieren, wenn eine RESTvolle
                    <acronym>MVC</acronym>-Anwendung entwickelt wird.
                </para>
            </note>

            <para>
                Im Anfrageobjekt können auch Benutzerparameter durch Verwendung von
                <methodname>setParam()</methodname> gesetzt werden und später durch
                verwenden von <methodname>getParam()</methodname> zurückgegeben werden. Der Router
                verwendet diese Funktionalität, um passende Parameter in der
                Anfrage-<acronym>URI</acronym> im Anfrageobjekt zu setzen.
            </para>

            <note>
                <title>getParam() empfängt mehr als Benutzerparameter</title>

                <para>
                    Um einfach seinen Job zu erledigen, sammelt <methodname>getParam()</methodname>
                    Daten von verschiedenen Quellen. Je nach Priorität enthalten diese:
                    Benutzerparameter, die über <methodname>setParam()</methodname> gesetzt wurden,
                    <constant>GET</constant>-Parameter und letztendlich
                    <constant>POST</constant>-Parameter. Seien Sie sich dieser Tatsache bewusst,
                    wenn Sie Daten mit dieser Methode holen.
                </para>

                <para>
                    Wenn man nur Parameter erhalten will, die vorher mit
                    <methodname>setParam()</methodname> gesetzt wurden, muß
                    <methodname>getUserParam()</methodname> verwendet werden.
                </para>

                <para>
                    Zusätzlich kann seit 1.5.0 abgesichert werden, welche Parameterquellen durchsucht
                    werden. <methodname>setParamSources()</methodname> erlaubt es, ein leeres Array
                    anzugeben oder ein Array mit einem oder mehreren Werten von '_GET' oder
                    '_POST' um zu zeigen, welche Parameterquellen erlaubt sind (standardmäßig sind
                    beide erlaubt); wenn der Zugriff nur auf '_GET' beschränkt werden soll, muß
                    <methodname>setParamSources(array('_GET'))</methodname> angegeben werden.
                </para>
            </note>

            <note>
                <title>Apache Quirks</title>

                <para>
                    Wenn der 404-Handler des Apache verwendet wird, um eingehende Anfragen an den
                    FrontController zu übergeben, oder ein PT Flag mit Rewrite Regeln verwendet wird,
                    enthält <varname>$_SERVER['REDIRECT_URL']</varname> die <acronym>URI</acronym>,
                    die benötigt wird, nicht <varname>$_SERVER['REQUEST_URI']</varname>. Wenn so ein
                    Setup verwendet wird und man ungültige Routen erhält, sollte man stattdessen die
                    Klasse <classname>Zend_Controller_Request_Apache404</classname> statt der
                    Standard-<acronym>HTTP</acronym>-Klasse für das Anfrageobjekt verwenden:
                </para>

                <programlisting language="php"><![CDATA[
$request = new Zend_Controller_Request_Apache404();
$front->setRequest($request);
]]></programlisting>

                <para>
                    Diese Klasse erweitert die Klasse
                    <classname>Zend_Controller_Request_Http</classname> und modifiziert einfach die
                    automatische Erkennung der Anfrage-<acronym>URI</acronym>. Sie kann als
                    einfache Ersetzung verwendet werden.
                </para>
            </note>
        </sect3>

        <sect3 id="zend.controller.request.http.baseurl">
            <title>Basis-Url und Unterverzeichnisse</title>

            <para>
                <classname>Zend_Controller_Request_Http</classname> erlaubt, dass
                <classname>Zend_Controller_Router_Rewrite</classname> in einem Unterverzeichnis
                verwendet werden kann. <classname>Zend_Controller_Request_Http</classname> versucht,
                die Basis-<acronym>URL</acronym> automatisch zu erkennen und entsprechend zu setzen.
            </para>

            <para>
                Wenn man zum Beispiel seine <filename>index.php</filename> in einem
                Webserverunterverzeichnis mit Namen <filename>/projects/myapp/index.php</filename>
                verwendet, sollte die Basis-<acronym>URL</acronym> (die Rewrite-Basis) auf
                <filename>/projects/myapp</filename> gesetzt werden. Dieser String wird dann vom
                Anfang des Pfades entfernt, bevor irgendwelche Routingtreffer ermittelt werden.
                Dies befreit einen davon, es am Anfang jeder Route setzen zu müssen. Eine Route
                <command>'user/:username'</command> passt auf <acronym>URI</acronym>s wie
                <filename>http://localhost/projects/myapp/user/martel</filename> und
                <filename>http://example.com/user/martel</filename>.
            </para>

            <note>
                <title>URL-Erkennung beachtet Groß- und Kleinschreibung</title>

                <para>
                    Die automatische Erkennung der Basis-<acronym>URL</acronym> beachtet die Groß-
                    und Kleinschreibung, weshalb man sicherstellen sollte, dass die
                    <acronym>URL</acronym> einem Unterverzeichnis im Dateisystem entspricht (sogar
                    auf einem Windows-Rechner). Andernfalls wird eine Ausnahme geworfen.
                </para>
            </note>

            <para>
                Sollte die Basis-<acronym>URL</acronym> falsch erkannt werden, kann man diese auch
                mit einem eigenen Pfad mit Hilfe der Methode <methodname>setBaseUrl()</methodname>
                der Klasse <classname>Zend_Controller_Request_Http</classname> oder der
                Klasse <classname>Zend_Controller_Front</classname> überschreiben. Die einfachste
                Methode ist die von <classname>Zend_Controller_Front</classname>, welche es an das
                Request-Objekt weiterleitet. Nun Beispiel, um eine eigene
                Basis-<acronym>URL</acronym> zu setzen:
            </para>

            <programlisting language="php"><![CDATA[
/**
 * Dispatch-Anfrage mit einer kundenbasierenden URL mit Zend_Controller_Front.
 */
$router     = new Zend_Controller_Router_Rewrite();
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./application/controllers')
           ->setRouter($router)
           ->setBaseUrl('/projects/myapp'); // Setze die Basis-URL!
$response   = $controller->dispatch();
]]></programlisting>
        </sect3>

        <sect3 id="zend.controller.request.http.method">
            <title>Erkennen der Anfragemethode</title>

            <para>
                <methodname>getMethod()</methodname> erlaubt es die
                <acronym>HTTP</acronym>-Anfragemethode zu erkennen, die verwendet wurde, um die
                aktuelle Ressource anzufragen.
                Zusätzlich existiert eine Vielzahl von Methoden, die es erlauben, boolsche Antworten
                zu erhalten, wenn gefragt wird, ob ein spezieller Typ von Anfrage durchgeführt wurde:
            </para>

            <itemizedlist>
                <listitem><para><methodname>isGet()</methodname></para></listitem>
                <listitem><para><methodname>isPost()</methodname></para></listitem>
                <listitem><para><methodname>isPut()</methodname></para></listitem>
                <listitem><para><methodname>isDelete()</methodname></para></listitem>
                <listitem><para><methodname>isHead()</methodname></para></listitem>
                <listitem><para><methodname>isOptions()</methodname></para></listitem>
            </itemizedlist>

            <para>
                Der grundsätzliche Verwendungszweck hierfür ist die Erstellung von RESTvollen
                <acronym>MVC</acronym>-Architekturen.
            </para>
        </sect3>

        <sect3 id="zend.controller.request.http.ajax">
            <title>Erkennen von AJAX-Anfragen</title>

            <para>
                <classname>Zend_Controller_Request_Http</classname> hat eine rudimentäre Methode für
                die Erkennung von <acronym>AJAX</acronym>-Anfragen:
                <methodname>isXmlHttpRequest()</methodname>. Diese Methode sucht nach einem
                <acronym>HTTP</acronym>-Anfrageheader <emphasis>X-Requested-With</emphasis> mit dem
                Wert 'XMLHttpRequest'; wenn er gefunden wird, gibt er <constant>TRUE</constant>
                zurück.
            </para>

            <para>
                Aktuell wird dieser Header standardmäßig mit den folgenden JS-Bibliotheken
                geschickt:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        Prototype und Scriptaculous (und von Prototype abgeleitete Bibliotheken)
                    </para>
                </listitem>

                <listitem><para>Yahoo! UI Library</para></listitem>
                <listitem><para>jQuery</para></listitem>
                <listitem><para>MochiKit</para></listitem>
            </itemizedlist>

            <para>
                Die meisten <acronym>AJAX</acronym>-Bibliotheken erlauben das Senden von eigenen
                <acronym>HTTP</acronym>-Anfrageheadern; wenn die eigene Bibliothek diesen Header
                nicht sendet, muß dieser einfach zum Anfrageheader hinzugefügt werden um
                sicherzustellen, dass die Methode <methodname>isXmlHttpRequest()</methodname>
                funktioniert.
            </para>
        </sect3>
    </sect2>

    <sect2 id="zend.controller.request.subclassing">
        <title>Vererben des Anfrageobjekts</title>

        <para>
            Die Basisanfrageklasse, die für alle Anfrageobjekte verwendet wird, ist die abstrakte
            Klasse <classname>Zend_Controller_Request_Abstract</classname>. Sie ist sehr
            grundsätzlich und definiert die folgenden Methoden:
        </para>

        <programlisting language="php"><![CDATA[
abstract class Zend_Controller_Request_Abstract
{
    /**
     * @return string
     */
    public function getControllerName();

    /**
     * @param string $value
     * @return self
     */
    public function setControllerName($value);

    /**
     * @return string
     */
    public function getActionName();

    /**
     * @param string $value
     * @return self
     */
    public function setActionName($value);

    /**
     * @return string
     */
    public function getControllerKey();

    /**
     * @param string $key
     * @return self
     */
    public function setControllerKey($key);

    /**
     * @return string
     */
    public function getActionKey();

    /**
     * @param string $key
     * @return self
     */
    public function setActionKey($key);

    /**
     * @param string $key
     * @return mixed
     */
    public function getParam($key);

    /**
     * @param string $key
     * @param mixed $value
     * @return self
     */
    public function setParam($key, $value);

    /**
     * @return array
     */
     public function getParams();

    /**
     * @param array $array
     * @return self
     */
    public function setParams(array $array);

    /**
     * @param boolean $flag
     * @return self
     */
    public function setDispatched($flag = true);

    /**
     * @return boolean
     */
    public function isDispatched();
}
]]></programlisting>

        <para>
            Das Anfrageobjekt ist ein Behälter für die Anfrageumgebung. Die Controller-Kette muß
            wirklich nur wissen, wie der Controller, die Aktion, die optionalen Parameter und der
            Dispatched-Status gesetzt und empfangen werden können. Standardmäßig durchsucht das
            Anfrageobjekt die eigenen Parameter, indem es die Schlüssel für Controller oder Aktion
            verwendet um den Controller und die Aktion zu ermitteln.
        </para>

        <para>
            Erweiteren Sie diese Klasse oder eine ihrer Derivate, wenn die Anfrageklasse mit einer
            speziellen Umgebung interagieren soll, um Daten für die obigen Aufgaben zu erhalten.
            Beispiele beinhalten <link linkend="zend.controller.request.http">die
                <acronym>HTTP</acronym>-Umgebung</link>, eine <acronym>CLI</acronym>-Umgebung, oder
            eine <acronym>PHP</acronym>-GTK-Umgebung.
        </para>
    </sect2>
</sect1>
