Layeraufbau von DecoratorsWenn man dem vorigen Abschnitt gut gefolgt ist, hat man festgestellt das die render() Methode eines Decorators ein einzelnes $content Argument entgegen nimmt. Es wird erwartet das dies ein String ist. render() nimmt dann diesen String und entscheidet ob er ersetzt, vorangestellt, oder angehängt wird. Das erlaubt es eine Kette von Decorators zu haben -- was es erlaubt Decorators zu erstellen welche nur ein Subset der Metadaten des Elements darstellt, und diese Decorators übereinander legt um das volle Markup des Elements zu bauen. Schauen wir uns an wie das in der Praxis arbeitet. Für die meisten Typen an Formularelementen werden die folgenden Decorators verwendet:
Man wird feststellen das jeder dieser Decorators nur ein Ding tut, und auf einem speziellen Teil der Metadaten arbeitet die im Formularelement gespeichert sind: der Errors Decorator holt Prüffehler und stellt Sie dar; der Label Decorator holt die Überschrift und stellt Sie dar. Das erlaubt einzelnen Decorators sehr bündig, wiederholbar, und viel wichtiger, testbar zu sein. Hier kommt auch das $content Argument zum Einsatz: Jede render() Methode eines Decorators ist designt um Inhalte zu akzeptieren, und diesen dann entweder zu ersetzen (normalerweise indem er umhüllt wird), hinten anzuhängen, oder voranzustellen. Es ist also am Besten vom Prozess der Dekoration als Erstellung einer Zwiebel zu denken, von Innen nach Außen. Um den Prozess zu vereinfachen sehen wir in der Beispiel des vorherigen Abschnitts. Nochmals:
Jetzt entfernen wir die Funktionalität des Labels und bauen einen eigenen Decorator dafür.
Das könnte jetzt schön und gut aussehen, aber da ist ein Problem: wie gerade geschrieben gewinnt der letzte Decorator und überschreibt alles. Man endet nur mit der Eingabe oder nur dem Label, abhängig davon was als letztes registriert wurde. Um das zu verhindern, muss dass in $content übergebene irgendwie mit dem Markup verbunden werden: Das Problem mit dem obigen Ansatz kommt dann wenn man programmtechnisch wählen will ob der originale Inhalt das neue Markup angehängt oder vorangestellt werden soll. Glücklicherweise gibt es hierfür bereits einen Standardmechanismus; Zend_Form_Decorator_Abstract hat ein Konzept der Platzierung und definiert einige Konstanten um es anzusprechen. Zusätzlich erlaubt es die Spezifikation eines Separators der zwischen beide platziert wird. Verwenden wir Sie:
Es sollte beachtet werden das wir das Standardverhalten für jeden verändern; die Annahme besteht darin das die Überschrift dem Inhalt folgt und die Eingabe vorangestellt wird. Erstellen wir jetzt ein Formularelement das Sie verwendet:
Wie arbeitet das? Wenn wir render() aufrufen, wird das Element durch die verschiedenen angehängten Decorators iterieren, indem auf jedem render() aufgerufen wird. Er übergibt einen leeren String zu dem allerersten, und was auch immer für ein Inhalt erstellt wird, wird dieser an den nächsten übergeben, und so weiter:
Einen Moment! Wenn wir wollen das aus irgendeinem Grund die Überschrift nach der Eingabe kommt, was dann? Erinnern wir uns an das "placement" Flag? Man kann es als Option an den Decorator übergeben. Der einfachste Weg das zu tun ist die Übergabe eines Arrays an Optionen an den Decorator wärend der Erstellung des Elements:
Es sollte beachtet werden das der Decorator bei der Übergabe von Optionen in einem Array umhüllt werden muss; das zeigt dem Constructor das Optionen vorhanden sind. Der Name des Decorators ist das erste Element des Arraqs, und optionen welche in einem Array an das zweite Element des Arrays übergeben werden. Das oben stehende führt zum Markup <input id="bar-foo" name="bar[foo]" type="text" value="test"/>\n<label for="bar-foo">. Bei Verwendung dieser Technik kann man Decorators haben welche auf spezifische Metadaten eines Elements oder einem Formular abzielen und nur das für diese Metadaten relevante Markup erstellt; indem mehrere Decorators verwendet werden kann das komplette Markup des Elements gebaut werden. Unsere Zwiebel ist das Ergebnis. Es gibt Vor- und Nachteile für diesen Ansatz. Erst die Nachteile:
Die Vorteile sind wirklich überwältigend:
Wärend die oben stehenden Beispiele die geplante Verwendung der Decorators in Zend_Form zeigen, ist es oft hart zu erkennen wie Decorators untereinander interagieren um das endgültige Markup er bauen. Aus diesem Grund wurde in der Serie 1.7 etwas Flexibilität hinzugefügt um die Darstellung individueller Decorators zu ermöglichen -- das gibt eine Rails-artige Einfachheit der Darstellung von Formularen. Wir sehen uns das im nächsten Abschnitt an.
|