ContextSwitch und AjaxContext
Der ContextSwitch Action Helfer ist vorgesehen für die Erleicherung
bei der Rückgabe von unserschiedlichen Antwortformaten oder Anfragen. Der
AjaxContext Helfer ist eine spezialisierte Version von
ContextSwitch welche die Rückgabe von Antworten zu XmlHttpRequests
erleichtert.
Um einen von Ihnen zu aktivieren, muß der Controller darauf hingewiesen werden welche
Aktion zu welchem Kontext antworten kann. Wenn eine hereinkommende Anfrage einen gültigen
Kontext für eine gegebene Aktion indiziert, dann wird der Helfer:
das Layout ausschalten wenn es eingeschaltet ist.
einen alternativen View suffix setzen, was effektiv ein separates View Skript für
den Kontext benötigt.
die richtigen Antwort Header für den gewünschten Kontext senden.
optional den spezifizierten Callback aufrufen um den Kontext zu definieren und/oder
anschließende Berechnungen durchführen.
Als Beispiel wird der folgende Controller angenommen:
_forward('list');
}
/**
* News Items auflisten
*/
public function listAction()
{
}
/**
* Ein News Item anzeigen
*/
public function viewAction()
{
}
}
]]>
Angenommen wir wollen das listAction() auch im
XML Format vorhanden ist. Statt der Erstellung einer anderen Aktion,
kann angezeigt werden das eine XML Antwort zurückgegeben wird:
_helper->getHelper('contextSwitch');
$contextSwitch->addActionContext('list', 'xml')
->initContext();
}
// ...
}
]]>
Was macht das:
Setzt den 'Content-Type' Antwort Header auf 'text/xml'.
Ändert den View Suffix auf 'xml.phtml' (oder, wenn ein
alternativer View Suffix verwendet wird, 'xml.[dein Suffix]').
Jetzt muß ein neues View Skript erstellt werden,
'news/list.xml.phtml', welches das XML erzeugt und
darstellt.
Um zu ermitteln ob eine Anfrage eine Kontextänderung initiiert, prüft der Helfer auf ein
token im Anfrage Objekt. Standardäßig schaut er auf den 'format' Parameter, durch den das
konfiguriert werden kann. Das bedeutet das, in den meisten Fällen, um eine Kontextänderung
zu triggern, ein 'format' Parameter in der Anfrage hinzugefügt werden kann:
über URL Parameter: /news/list/format/xml
(beachte, das Standard Routing Schema erlaubt übliche Schlüssel/Werte Paare nach
der Aktion)
über GET Parameter: z.B.,
/news/list?format=xml
ContextSwitch erlaubt es beliebige Kontexte zu spezifizieren,
inklusive welche Kontextänderung stattfinden wird (wenn überhaupt), jegliche Antwort
Header die gesendet werden sollen, und beliebige Callbacks für Initialisierung und folgende
Bearbeitung.
Vorhandene Standard Kontexte
Standardmäßig sind zwei Kontexte im ContextSwitch Helfer
vorhanden: json und XML.
JSON. Der JSON
Kontext setzt den 'Content-Type' Antwort Header auf
'application/json' und den View Skript Suffix auf
'json.phtml'.
Trotzdem wird standardmäßig kein View Skript benötigt. Es serialisiert einfach
alle View Variablen und sendet die JSON Antwort sofort aus.
Dieses Verhalten kann deaktiviert werden indem die automatische
JSON Serialisierung abgeschaltet wird:
_helper->contextSwitch()->setAutoJsonSerialization(false);
]]>
XML. Der XML Kontext
setzt den 'Content-Type' Antwort Header auf 'text/xml' und
den View Skript Suffix auf 'xml.phtml'. Es muß ein neues
View Skript für den Kontext erstellt werden.
Eigene Kontexte erstellen
Manchmal sind die Standardkontexte nicht genug. Zum Beispiel wenn man
YAML zurückgeben will, oder PHP serialisieren,
ein RSS oder ATOM Feed, usw.
ContextSwitch erlaubt es das zu tun.
Der einfachste Weg einen neuen Kontext hinzuzufügen ist über die
addContext() Methode. Diese Methoe nimmt zwei Argumente, den
Namen des Kontextes, und eine Array Spezifikation. Die Spezifikation sollte ein oder
mehrere der folgenden Dinge enthalten:
suffix: Der Suffix der dem Standard View Suffix angefügt
werden soll der im ViewRenderer registriert ist.
headers: Ein Array von Header zu Wert Paaren das als Teil
der Antwort gesendet werden soll.
callbacks: Ein Array das ein oder mehrere der Schlüssel
'init' oder 'post' enthält, die auf gültige PHP Callbacks
zeigen und die für die Initialisierung des Contextes und die Nachbearbeitung
verwendet werden können.
Initialisierungs Callbacks treten auf wenn der Kontext durch
ContextSwitch erkannt wird. Sie können verwendet werden um
spezielle Logik auszuführen die stattfinden soll. Als Beispiel verwendet der
JSON Kontext einen Callback um den ViewRenderer auszuschalten
wenn die automatische JSON Serialisierung eingeschaltet ist.
Nachbearbeitung tritt wärend der postDispatch()
Routine der Aktion auf, und kann verwendet werden um spezielle Logik
auszuführen. Als Beispiel verwendet der JSON Kontext einen
Callback um festzustellen ob die automatische JSON
Serialisierung eingeschaltet ist; wenn dem so ist, serialisiert es die View
Variablen zu JSON und sendet die Antwort, aber wenn dem nicht
so ist, schaltet es den ViewRenderer wieder ein.
Es gibt eine Vielzahl an Methoden für die Interaktion mit Kontexten:
addContext($context, array $spec): Fügt einen neuen
Kontext hinzu. Wirft eine Ausnahme wenn der Kontext bereits existiert.
setContext($context, array $spec): Fügt einen neuen
Kontext hinzu oder überschreibt einen bestehenden Kontext. Verwendet die gleiche
Spezifikation wie addContext().
addContexts(array $contexts): Fügt viele Kontexte auf
einmal hinzu. Das $contexts Array sollte ein Array von
Kontext zu Spezifikation Paaren sein. Wenn einer der Kontexte bereits existiert,
wird eine Ausnahme geworfen.
setContexts(array $contexts): Fügt neue Kontexte hinzu
und überschreibt bestehende. Verwendet die gleiche Spezifikation wie
addContexts().
hasContext($context): Gibt TRUE
zurück wenn der Kontext existiert, andernfalls FALSE.
getContext($context): Empfängt einen einzelnen Kontext
durch den Namen. Gibt ein Array zurück das der Spezifikation folgt die in
addContext() verwendet wird.
getContexts(): Empfängt alle Kontexte. Gibt ein Array
von Kontext zu Spezifikation Paaren zurück.
removeContext($context): Entfernt einen einzelnen
Kontext durch seinen Namen. Gibt im Erfolgsfall TRUE
zurück, und FALSE wenn der Kontext nicht gefunden wurde.
clearContexts(): Entfernt alle Kontexte.
Kontexte per Aktion setzen
Es gibt zwei Mechanismen für das Setzen vorhandener Kontexte. Es kann entweder manuell
ein Array im Controller erstellt werden, oder es können verschiedene Methoden in
ContextSwitch verwendet werden um Sie zu bauen.
Die prinzipielle Methode für das Hinzufügen von Aktion zu Kontext Relationen ist
addActionContext(). Sie erwartet zwei Argumente, die Aktion zu
welcher der Kontext hinzugefügt werden soll, und entweder den Namen des Kontextes oder
ein Array von Kontexten. Als Beispiel nehmen wir die folgende Controller Klasse an:
Angenommen wir sollen einen XML Kontext zu der 'list' Aktion
hinzufügen, und XML und JSON Kontexte zu der
'comments' Aktion. Wir können das in der init() Methode
machen:
_helper->contextSwitch()
->addActionContext('list', 'xml')
->addActionContext('comments', array('xml', 'json'))
->initContext();
}
}
]]>
Alternativ kann einfach die Array-Eigenschaft $contexts definiert
werden:
array('xml'),
'comments' => array('xml', 'json')
);
public function init()
{
$this->_helper->contextSwitch()->initContext();
}
}
]]>
Das obige ist weniger Overhead, aber enthält auch potentielle Fehler.
Die folgenden Methoden können verwendet werden um die Kontext-Mappings zu erstellen:
addActionContext($action, $context): markiert einen
oder mehrere Kontexte als in einer Aktion vorhanden. Wenn bereits Mapping
existieren wird einfach bei diesen Mappings angehängt.
$context kann ein einzelner Kontext sein, oder ein Array von
Kontexten.
Ein Wert von TRUE für den Kontext markiert alle vorhandenen
Kontexte als vorhanden für die Aktion.
Ein leerer Wert für $context deaktiviert alle Kontexte für
die gegebene Aktion.
setActionContext($action, $context): markiert einen
oder mehrere Kontexte als in einer Aktion vorhanden. Wenn bereits Mappings
existieren werden Sie mit den spezifizierten ersetzt.
$context kann ein einzelner Kontext sein, oder ein Array von
Kontexten.
addActionContexts(array $contexts): fügt mehrere
Aktion zu Kontext Paare auf einmal hinzu. $contexts sollte
ein assoziatives Array von Aktion zu Kontext Paaren sein. Es entspricht
addActionContext(), was bedeutet das wenn eine Paarung
bereits existiert, diese hinzugefügt wird.
setActionContexts(array $contexts): fungiert wie
addActionContexts(), überschreibt aber bestehende
Aktion zu Kontext Paare.
hasActionContext($action, $context): ermittelt ob eine
spezielle Aktion einen gegebenen Kontext hat.
getActionContexts($action = null): gibt entweder alle
Kontexte für eine gegebene Aktion zurück, oder alle Aktion zu Kontext Paare.
removeActionContext($action, $context): entfernt ein
oder mehrere Kontexte von einer gegebenen Aktion. $context
kann ein einzelner Kontext sein, oder ein Array von Kontexten.
clearActionContexts($action = null): entfernt alle
Kontexte von einer gegebenen Aktion, oder von allen Aktionen mit Kontexten.
Kontext Switching initialisieren
Um Kontext Switching zu initialisieren, muß initContext() im
Action Controller aufgerufen werden:
_helper->contextSwitch()->initContext();
}
}
]]>
In einigen Fällen, will man einen Kontext erzwingen der verwendet werden soll; zum
Beispiel wenn man nur den XML Kontext erlauben will wenn Kontext
Switching aktiviert ist. Das kann durch die Übergaben des Kontextes zu
initContext() getan werden:
initContext('xml');
]]>
Zusätzliche Funktionalitäten
Eine Vielzahl an Methoden kann verwendet werden um das Verhalten des
ContextSwitch Helfers zu verändern. Diese sind:
setAutoJsonSerialization($flag): Standardmäßig
serialisieren JSON Kontexte alle View Variablen in die
JSON Notierung und geben diese als Antwort zurück. Wenn man
seine eigene Antwort erstellen will, sollte das ausgeschaltet werden; das muß
vor dem Aufruf von initContext() geschehen.
setAutoJsonSerialization(false);
$contextSwitch->initContext();
]]>
Der Wert des Flags erhält man mit
getAutoJsonSerialization().
setSuffix($context, $suffix,
$prependViewRendererSuffix): Mit
dieser Methode kann ein anderer Suffix spezifiziert werden der für einen
gegebenen Kontext verwendet werden soll. Das dritte Argument wird verwendet um
anzuzeigen ob der aktuelle Suffix des ViewRenderers dem neuen Suffix
vorangestellt werden soll oder nicht; dieses Flag ist standardmäßig aktiviert.
Die Übergabe eines leeren Werte an den Suffix führt dazu das nur der Suffix des
ViewRenderers verwendet wird.
addHeader($context, $header, $content): Fügt einen
Antwort Header für einen gegebenen Kontext hinzu. $header
ist der Headername, und $content ist der Wert der an diesen
Header übergeben werden soll.
Jeder Kontxt kann mehrere Header haben; addHeader()
fügt zusätzliche Header in den Header Stack des Kontextes ein.
Wenn der spezifizierte $header bereits für diesen Kontext
existiert, wird eine Ausnahme geworfen.
setHeader($context, $header, $content):
setHeader() funktioniert wie
addHeader(), ausser das sie erlaubt das
existierende Kontext Header überschrieben werden.
addHeaders($context, array $headers): Fügt einen
gegebenen Kontext mehrere Header auf einmal hinzu. Entspricht
addHeader(), was bedeutet das eine Ausnahme geworfen
wird wenn der Header bereits existiert. $headers ist ein
Array von Header zu Kontext Paaren.
setHeaders($context, array $headers.): Wie
addHeaders(), nur das es
setHeader() entspricht und damit das Überschreiben
existierender Header erlaubt.
getHeader($context, $header): Enpfängt den Wert eines
Headers für einen gegebenen Kontext. Gibt NULL zurück wenn
dieser nicht gefunden wird.
removeHeader($context, $header): Entfernt einen
einzelnen Header für einen gegebenen Kontext.
clearHeaders($context, $header): Entfernt alle Header
für einen gegebenen Kontext.
setCallback($context, $trigger, $callback): Setzt
einen Callback bei einem gegebenen Trigger für einen gegebenen Kontext. Trigger
können entweder 'init' oder 'post' sein (was zeigt das der Callback entweder
bei der Initialisierung oder der Nachbearbeitung aufgerufen wird).
$callback sollte ein gültiger PHP
Callback sein.
setCallbacks($context, array $callbacks): Setzt
mehrere Callbacks für einen gegebenen Kontext. $callbacks
sollte ein Trigger zu Callback Paar sein. Aktuell sind die meisten Callbacks
die registriert werden können zwei, einer für Initialisierung und einer für die
Nachbearbeitung.
getCallback($context, $trigger): Empfängt einen
Callback für einen gegebenen Trigger in einem gegebenen Kontext.
getCallbacks($context): Empfängt alle Callbacks für
einen gegebenen Kontext. Gibt ein Array von Trigger zu Callback Paaren zurück.
removeCallback($context, $trigger): Entfernt einen
Callback für einen gegebenen Trigger und Kontext.
clearCallbacks($context): Entfernt alle Callbacks für
einen gegebenen Kontext.
setContextParam($name): Setzt den Anfrageparameter der
geprüft werden muß um zu entscheiden ob eine Kontextumschaltung angefragt wurde
oder nicht. Der Wert ist standardmäßig 'format', aber dieser Zugriffspunkt kann
verwendet werden um einen alternativen wert zu setzen.
getContextParam() kann verwendet werden um den
aktuellen Wert zu erhalten.
setAutoDisableLayout($flag): Standardmäßig sind
Layouts ausgeschaltet wenn eine Kontextumschaltung erfolgt; das ist weil
Layouts typischerweise dafür verwendet werden um normale Antworten
darzustellen, und Sie in alternativen Kontexten keine Bedeutung haben. Wenn man
trotzdem Layouts verwenden will (möglicherweise hat man ein Layout für einen
neuen Kontext), kann dieses Verhalten mit der Übergabe eines
FALSE Wertes an
setAutoDisableLayout() geändert werden. Das sollte
aber before dem Aufruf von
initContext() geschehen.
Um den Wert dieses Flags zu erhalten, kann der Zugriffspunkt
getAutoDisableLayout() verwendet werden.
getCurrentContext() kann verwendet werden um
festzustellen welcher Kontext erkannt wurde, wenn überhaupt. Er gibt
NULL zurück wenn keine Kontextumschaltung stattgefunden
hat, oder wenn er aufgerufen wurde bevor initContext()
stattgefunden hat.
AjaxContext Funktionalität
Der AjaxContext Helfer erweitert
ContextSwitch, sodas alle für ContextSwitch
gelisteten Funktionalitäten in Ihm vorhanden sind. Es gibt trotzdem ein paar wichtige
Änderungen.
Zuerst, verwendet es eine andere Action Controller Eigenschaft
$ajaxable um Kontexte festzustellen. Damit kann man verschiedene
Kontexte verwenden für AJAX gegenüber normalen
HTTP Anfragen. Die verschiedenen
*ActionContext()* Methoden von
AjaxContext schreiben in diese Eigenschaft.
Zweitens, wird nur dann getriggert wenn ein XmlHttpRequest stattgefunden hat, was durch
die isXmlHttpRequest() Methode den Anfrageobjektes
festgestellt wird. Deshalb wird, wenn der Kontextparameter ('format') in der Anfrage
übergeben wird, aber die anfrage nicht als XmlHttpRequest gemacht wurde, keine
Kontextumschaltung getriggert.
Drittens, fügt der AjaxContext einen zusätzlichen,
HTML, Kontext hinzu. In diesem Kontext setzt er den Suffix auf
'ajax.phtml' um diesen Kontext von einer normalen Anfrage zu
unterscheiden. Es werden keine zusätzlichen Header zurückgegeben.
Aktionen erlauben auf Ajax Anfragen zu antworten
In dem folgenden Beispiel erlauben wir Anfragen auf die Aktionen 'view', 'form' und
'process' auf AJAX Anfragen zu antworten. In den ersten zwei
Fällen, 'view' und 'form' wird ein HTML Teilstück zurückgegeben
mit dem die Seite aktualisiert werden soll; im letzteren wird
JSON zurückgegeben.
_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('view', 'html')
->addActionContext('form', 'html')
->addActionContext('process', 'json')
->initContext();
}
public function viewAction()
{
// Ein einzelnes Kommentar holen um es anzuzeigen.
// Wenn AjaxContext erkannt wurde, verwendet es das
// comment/view.ajax.phtml View Skript.
}
public function formAction()
{
// Stellt die "add new comment" Form dar.
// Wenn AjaxContext erkannt wurde, verwendes es das
// comment/form.ajax.phtml View Skript.
}
public function processAction()
{
// Bearbeitet einen neuen Kommentar
// Gibt das Ergebnis als JSON zurück; fügt die Ergebnisse einfach als
// View Variablen hinzu, und JSON wird zurückgegeben.
}
}
]]>
Auf der Seite des Clients, wird die AJAX Bibliothek einfach die
Endpunkte '/comment/view',
'/comment/form', und '/comment/process'
anfragen, und den 'format' Parameter übergeben:
'/comment/view/format/html',
'/comment/form/format/html',
'/comment/process/format/json'. (Oder der Parameter
kann über den Abfrage String übergeben werden: z.B. , "?format=json".)
Angenommen die Bibliothek übergibt den 'X-Requested-With: XmlHttpRequest'
Header, dann werden diese Aktionen das richtige Antwortformat zurückgeben.