| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: 17583 -->
- <sect1 id="zend.controller.response">
- <title>Das Response-Objekt</title>
- <sect2 id="zend.controller.response.usage">
- <title>Verwendung</title>
- <para>
- Das Response-Objekt ist das logische Gegenstück zum <link
- linkend="zend.controller.request">Request-Objekt</link>. Sein Zweck ist es,
- Inhalte und/oder Header zu vereinigen, um sie in einem Rutsch zu versenden.
- Zusätzlich übergibt der FrontController alle aufgefangenen Ausnahmen an das
- Response-Objekt, um dem Entwickler das Verarbeiten von Ausnahmen zu ermöglichen.
- Diese Funktionalität kann durch Setzen von
- <methodname>Zend_Controller_Front::throwExceptions(true)</methodname> überschrieben
- werden.
- </para>
- <programlisting language="php"><![CDATA[
- $front->throwExceptions(true);
- ]]></programlisting>
- <para>
- Um die Ausgabe der Anwort inklusive der gesetzten Header zu senden, verwendet man
- <methodname>sendResponse()</methodname>:
- </para>
- <programlisting language="php"><![CDATA[
- $response->sendResponse();
- ]]></programlisting>
- <note>
- <para>
- Standardmäßig ruft der FrontController <methodname>sendResponse()</methodname> auf,
- wenn er die Anfrage fertig bearbeitet hat; nerweise wird es nie notwendig
- sein ihn aufzurufen. Wenn man trotzdem die Antwort manipulieren will oder sie beim
- Testen verwenden will, kann dieses Verhalten durch das Setzen des
- Flags <property>returnResponse</property> mit
- <methodname>Zend_Controller_Front::returnResponse(true)</methodname> geändert
- werden:
- </para>
- <programlisting language="php"><![CDATA[$front->returnResponse(true);
- $response = $front->dispatch();
- // ein bisschen mehr verarbeiten, wie z.B. loggen...
- // und dann die Ausgabe senden:
- $response->sendResponse();
- ]]></programlisting>
- </note>
- <para>
- Entwickler sollten das Response-Objekt in ihren Aktions-Controllern verwenden.
- Statt die Ausgabe direkt zu machen und Header zu versenden, sollten diese an das
- Response-Objekt übergeben werden:
- </para>
- <programlisting language="php"><![CDATA[
- // Innerhalb einer Controller Aktion:
- // Setze einen Header
- $this->getResponse()
- ->setHeader('Content-Type', 'text/html')
- ->appendBody($content);
- ]]></programlisting>
- <para>
- Dadurch werden alle Header in einem Rutsch versendet, genau vor der Anzeige des Inhalts.
- </para>
- <note>
- <para>
- Wenn die <link linkend="zend.controller.action.viewintegration">View
- Integration</link> des Aktions-Controllers verwendet wird, muss der bearbeitete
- Inhalt des View-Skripts im Response-Objekt nicht gesetzt werden, da die
- <methodname>Zend_Controller_Action::render()</methodname> das standardmäßig macht.
- </para>
- </note>
- <para>
- Sollte in der Anwendung eine Ausnahme auftreten, überprüft man den
- Schalter <methodname>isException()</methodname> des Response-Objekts und erhält die
- Ausnahme durch Verwendung von <methodname>getException()</methodname>. Zusätzlich kann
- man ein eigenes Response-Objekt erstellen, das zu einer Fehlerseite umleitet, die
- Nachricht der Ausnahme loggt, die Nachricht der Ausnahme schön formatiert ausgibt (für
- Entwicklungsumgebungen), usw.
- </para>
- <para>
- Man kann das Response-Objekt im Anschluss an die Methode <methodname>dispatch()</methodname>
- des FrontControllers erhalten oder den FrontController auffordern, das
- Response-Objekt zurückzugeben statt den Inhalt auszugeben.
- </para>
- <programlisting language="php"><![CDATA[
- // Erhalten nach dem Dispatch:
- $front->dispatch();
- $response = $front->getResponse();
- if ($response->isException()) {
- // log, mail, etc...
- }
- // Oder den FrontController-Dispatch-Prozess auffordern, es zurück zu geben
- $front->returnResponse(true);
- $response = $front->dispatch();
- // mach irgend was...
- // gib zum Schluß die Antwort aus
- $response->sendResponse();
- ]]></programlisting>
- <para>
- Standardmäßig werden Ausnahmenachrichten nicht ausgegeben. Dieses Verhalten kann durch
- den Aufruf von <methodname>renderException()</methodname> überschrieben werden oder
- indem der FrontController aufgefordert wird, die Exceptions durch
- <methodname>throwExceptions()</methodname> auszuwerfen, wie oben gezeigt:
- </para>
- <programlisting language="php"><![CDATA[
- $response->renderExceptions(true);
- $front->dispatch($request, $response);
- // oder:
- $front->returnResponse(true);
- $response = $front->dispatch();
- $response->renderExceptions();
- $response->sendResponse();
- // oder:
- $front->throwExceptions(true);
- $front->dispatch();
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.response.headers">
- <title>Header manipulieren</title>
- <para>
- Wie vorher besprochen, ist einer der Aspekte der Aufgaben des Response-Objekts das Sammeln und
- Abschicken der <acronym>HTTP</acronym>-Antwort-Header. Eine Vielzahl von Methoden
- existieren hierfür:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>canSendHeaders($throw = false)</methodname> wird verwendet,
- um zu ermitteln, ob bereits Header gesendet wurden. Ein optionaler Parameter bestimmt,
- ob eine Ausnahme geworfen werden soll oder nicht, wenn bereits Header gesendet
- wurden. Das kann durch das Setzen der Eigenschaft
- <property>headersSentThrowsException</property> zu <constant>FALSE</constant>
- überschrieben werden.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setHeader($name, $value, $replace = false)</methodname> wird
- verwendet, um einen individuellen Header zu setzen. Standardmäßig ersetzt das
- keinen bereits existierenden gleichnamigen Header im Objekt; allerdings wird das
- Setzen von <varname>$replace</varname> zu <constant>TRUE</constant> dies
- erzwingen.
- </para>
- <para>
- Vor dem Setzen des Headers wird mit <methodname>canSendHeaders()</methodname>
- geprüft, ob diese Operation zu diesem Zeitpunkt erlaubt ist
- und erzwingt, dass eine Ausnahme geworfen wird.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setRedirect($url, $code = 302)</methodname> setzt einen
- <acronym>HTTP</acronym> Location Header für eine Umleitung. Wenn ein
- <acronym>HTTP</acronym> Status Code angegeben wurde, wird dieser Status Code
- verwendet.
- </para>
- <para>
- Intern wird <methodname>setHeader()</methodname> mit dem
- <varname>$replace</varname>-Flag aufgerufen um sicherzustellen, dass nur ein
- solcher Header gesendet wird.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getHeaders()</methodname> gibt ein Array aller Header zurück. Jedes
- Array-Element ist ein Array mit den Schlüsseln 'name' und 'value'.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearHeaders()</methodname> löscht alle registrierten Header.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>setRawHeader()</methodname> kann verwendet werden um Header zu
- setzen, die keine Schlüssel-und-Werte-Paare sind, wie einen
- <acronym>HTTP</acronym> Status Header.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getRawHeaders()</methodname> gibt jeden registrierten rohen Header
- zurück.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearRawHeaders()</methodname> löscht jeden registrierten rohen
- Header.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearAllHeaders()</methodname> löscht beide, reguläre
- Schlüssel-und-Werte-Header genauso wie rohe Header.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Zusätzlich zu den obigen Methoden, gibt es Zugriffsmethoden für das Setzen und
- Empfangen der <acronym>HTTP</acronym>-Antwort-Codes für die aktuellen Anfrage,
- <methodname>setHttpResponseCode()</methodname> und
- <methodname>getHttpResponseCode()</methodname>.
- </para>
- </sect2>
- <sect2 id="zend.controller.response.namedsegments">
- <title>Benannte Segmente</title>
- <para>
- Das Response-Objekt unterstützt "benannte Segmente". Das erlaubt es den Inhalt des Bodys
- in verschiedene Segmente zu isolieren und diese Segmente zu reihen, damit die Ausgabe in
- einer spezifizierten Reihenfolge zurückgegeben wird. Intern wird der Inhalt der Bodys in
- einem Array gespeichert und die verschiedenen Zugriffsmethoden können verwendet werden,
- um die Platzierung und Benennung innerhalb des Arrays zu indizieren.
- </para>
- <para>
- Als Beispiel könnte ein <methodname>preDispatch()</methodname> Hook verwendet werden, um
- dem Response-Objekt einen Header hinzuzufügen, dann den Aktionscontroller einen Inhalt
- des Bodys hinzufügen zu lassen und einen <methodname>postDispatch()</methodname> Hook
- einen Footer hinzufügen zu lassen:
- </para>
- <programlisting language="php"><![CDATA[
- // Angenommen diese Plugin Klasse ist im Front Controller registriert
- class MyPlugin extends Zend_Controller_Plugin_Abstract
- {
- public function preDispatch(Zend_Controller_Request_Abstract $request)
- {
- $response = $this->getResponse();
- $view = new Zend_View();
- $view->setBasePath('../views/scripts');
- $response->prepend('header', $view->render('header.phtml'));
- }
- public function postDispatch(Zend_Controller_Request_Abstract $request)
- {
- $response = $this->getResponse();
- $view = new Zend_View();
- $view->setBasePath('../views/scripts');
- $response->append('footer', $view->render('footer.phtml'));
- }
- }
- // Ein Beispiel Aktion Controller
- class MyController extends Zend_Controller_Action
- {
- public function fooAction()
- {
- $this->render();
- }
- }
- ]]></programlisting>
- <para>
- Im obigen Beispiel wird ein Aufruf zu <filename>/my/foo</filename> den endgültigen
- Inhalt des Bodys des Antwortobjekts mit der folgenden Struktur verursachen:
- </para>
- <programlisting language="php"><![CDATA[
- array(
- 'header' => ..., // Header Inhalt
- 'default' => ..., // Body Inhalt von MyController::fooAction()
- 'footer' => ... // Footer Inhalt
- );
- ]]></programlisting>
- <para>
- Wenn das gerendert wird, wird es in der Reihenfolge gerendert, in der die Elements im
- Array angeordnet sind.
- </para>
- <para>
- Eine Vielzahl von Methoden kann verwendet werden, um die benannten Segmente zu
- manipulieren:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>setBody()</methodname> und <methodname>appendBody()</methodname>
- erlauben die Übergabe eines zweiten Werts <varname>$name</varname>, der ein
- benanntes Segment kennzeichnet. In jedem Fall wird bei der Übergabe das
- spezifizierte benannte Segment überschrieben oder es wird erstellt, wenn es
- nicht existiert (standardmäßig dem Array hinzugefügt). Wenn kein benanntes
- Segment an <methodname>setBody()</methodname> übergeben wird, setzt es den
- kompletten Inhalt des Body Arrays zurück. Wenn kein benanntes Segment an
- <methodname>appendBody()</methodname> übergeben wird, wird der Inhalt dem Wert
- im 'default' benannten Segment hinzugefügt.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>prepend($name, $content)</methodname> erstellt ein
- benanntes Segment <varname>$name</varname> und platziert dieses am Beginn des
- Arrays. Wenn das Segment bereits existiert, wird es vor der Operation entfernt
- (bzw. überschrieben und ersetzt).
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>append($name, $content)</methodname> erstellt ein
- benanntes Segment <varname>$name</varname> und platziert es am Ende des Arrays.
- Wenn das Segment bereits existiert, wird es vor der Operation entfernt (bzw.
- überschrieben und ersetzt).
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>insert($name, $content, $parent = null, $before =
- false)</methodname> erstellt ein benanntes Segment <varname>$name</varname>.
- Wenn ein <varname>$parent</varname>-Segment angegeben wurde, wird das
- neue Segment entweder vor oder nach diesem Segment im Array platziert (basierend
- auf dem Wert von <varname>$before</varname>). Wenn das Segment bereits
- existiert, wird es vor der Operation entfernt (bzw. überschrieben und
- ersetzt).
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>clearBody($name = null)</methodname> entfernt ein einzelnes
- benanntes Segment wenn ein <varname>$name</varname> angegeben wurde
- (andernfalls das komplette Array).
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getBody($spec = false)</methodname> kann verwendet werden, um ein
- einzelnes Array Segment zu erhalten, wenn <varname>$spec</varname> der Name des
- benannten Segments ist. Wenn <varname>$spec</varname> <constant>FALSE</constant>
- ist, gibt es einen String zurück, der durch Zusammenfügen aller benannten
- Segmente in ihrer Reihenfolge erstellt wird. Wenn <varname>$spec</varname>
- <constant>TRUE</constant> ist, gibt er das Array des Body Inhalts zurück.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.response.exceptions">
- <title>Testen auf Ausnahmen im Response-Objekt</title>
- <para>
- Wie vorher beschrieben werden Ausnahmen standardmäßig während des Dispatchens gefangen
- und im Response-Objekt registriert. Ausnahmen werden in einem Stack registriert, der es
- erlaubt alle geworfen Ausnahmen zu speichern -- Anwendungsausnahmen, Dispatch-Ausnahmen,
- Plugin-Ausnahmen, usw. Wenn man auf bestimmte Ausnahmen prüfen oder Ausnahmen
- loggen will, muß man die Ausnahme-<acronym>API</acronym> des Response-Objekts verwenden:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>setException(Exception $e)</methodname> erlaubt es, eine Ausnahme zu
- registrieren.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>isException()</methodname> sagt, ob eine Ausnahme bereits
- registriert wurde.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getException()</methodname> gibt den kompletten Ausnahme-Stack
- zurück.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>hasExceptionOfType($type)</methodname> erlaubt es festzustellen,
- ob eine Ausnahme einer speziellen Klasse im Stack vorhanden ist.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>hasExceptionOfMessage($message)</methodname> erlaubt es
- festzustellen, ob eine Ausnahme mit einer speziellen Nachricht im Stack
- vorhanden ist.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>hasExceptionOfCode($code)</methodname> erlaubt es festzustellen,
- ob eine Ausnahme mit einem bestimmten Code im Stack vorhanden ist.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getExceptionByType($type)</methodname> erlaubt es, alle Ausnahmen
- einer speziellen Klasse vom Stack zu erhalten. <constant>FALSE</constant> wird
- zurückgegeben wenn keine gefunden wurden, und andernfalls ein Array mit
- Ausnahmen.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getExceptionByMessage($message)</methodname> erlaubt es, alle
- Ausnahmen mit einer speziellen Nachricht vom Stack zu erhalten.
- <constant>FALSE</constant> wird zurückgegeben, wenn keine gefunden wurden, und
- andernfalls ein Array mit Ausnahmen.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>getExceptionByCode($code)</methodname> erlaubt es, alle Ausnahmen
- mit einem speziellen Code vom Stack zu erhalten. <constant>FALSE</constant> wird
- zurückgegeben, wenn keine gefunden wurden, und andernfalls ein Array mit
- Ausnahmen.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>renderExceptions($flag)</methodname> erlaubt es ein Flag zu setzen,
- das anzeigt, ob die Ausnahmen ausgegeben werden sollen, wenn die Antwort gesendet
- wurde oder nicht.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.response.subclassing">
- <title>Erben vom Response-Objekt</title>
- <para>
- Der Zweck des Response-Objekts ist es, Header und Inhalte von den verschiedenen Aktionen
- und Plugins zu sammeln und diese an den Client zurückzugeben; zweitens sammelt es in der
- Reihenfolge ihres Auftretens alle Fehler (Ausnahmen) und gibt diese zurück oder
- versteckt sie vor dem Endbenutzer.
- </para>
- <para>
- Die Basis-Antwortklasse ist <classname>Zend_Controller_Response_Abstract</classname>,
- und jede erbende Klasse, die erstellt wird, sollte von dieser Klasse oder eine ihrer
- Derivate erben. Die verschiedenen vorhandenen Methoden wurden im vorhergehenden
- Abschnitt aufgezählt.
- </para>
- <para>
- Die Gründe eine Subklasse des Response-Objekts zu erstellen beinhalten das Ändern wie eine
- Ausgabe zurückgegeben wird, basierend auf der Antwortumgebung (z.B., keine Header senden
- für <acronym>CLI</acronym> oder <acronym>PHP</acronym>-<acronym>GTK</acronym>-Anfragen),
- zusätzliche Funktionalitäten um eine endgültige Ansicht zurückzugeben, basierend auf
- Inhalt, der in benannten Segmenten gespeichert wurde, usw.
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|