Einblicke in die neue Komponente: eZ Components lernt MVC
Lange Zeit lehnte das Entwickler-Team die Integration einer MVC-Komponente ab, da sie nicht in das Konzept einer reinen Komponenten-Bibliothek zu passen schien. In der Tat kann eine MVC-Komponente dazu führen, dem Benutzer eine Applikationsstruktur vorzugeben und ihm viele Freiheiten zu nehmen. Ein Nachteil, den viele Frameworks mit sich bringen und der innerhalb der eZ Components vermieden werden sollte. Erreicht wurde dies bislang, in dem die Komponenten für dedizierte Aufgaben und möglichst erweiterbar entwickelt wurden.
MVC-Komponente
Wie fügt sich nun die MVC-Komponente in dieses Bild? Am Anfang stand der Entwicklungsprozess, der bei eZ Components klar gegliedert ist, um die Qualität sicherzustellen [1]. Bei der MVC-Tools-Komponente wurde dieser Prozess noch etwas
ausgeweitet. Ein erstes Anforderungsdokument wurde auf der
Mailingsliste und im IRC-Channel
diskutiert. Nach diesen anfänglichen Überlegungen trafen sich die
Entwickler auf der Open-Nordic-Konferenz mit
Entwicklern von eZ Publish und externen Entwicklern, die Lust hatten,
sich an der Diskussion zu beteiligen, um die bereits besprochenen
Konzepte weiter zu diskutieren und ein Design zu entwerfen.
Herausgekommen ist ein Satz von Interfaces, der Anforderungen an die Schnittstellen zwischen Request-Handling, Controller und View festlegt. Beispielimplementierungen sollen sicherstellen, dass das Applikationsmodell nicht nur mit HTTP, sondern etwa auch mit Kommunikation über Jabber und E-Mail umgehen kann. Das bedingt eine vollständige Separation von Controller und View, so dass in der Ausgabe jederzeit zwischen JSON, XML und HTML gewechselt werden kann.
Zum Testen wurde bereits vor dem Release der ersten Alpha-Version eine Beispielapplikation entwickelt: Eine Messaging-Applikation, ähnlich Twitter, die bei eZ Systems zum Austausch von Status-Updates verwendet wird. Diese offen zur Verfügung stehende Applikation lässt sich über Jabber und HTTP bedienen.
Von der Anfrage bis zur Ausgabe
Der grundlegende Prozess der Behandlung einer Anfrage in MVC-Implementierungen ist bekannt, in der MVC-Tools-Komponente folgt er im wesentlichen folgendem Schema:
Der „request parser“ erhält die eingehenden Informationen. Das können bei HTTP die Informationen im $_SERVER-Array sein, etwa die URL oder eventuelle GET- und POST-Parameter. Beim Behandeln von E-Mails kann es der Empfänger, Absender und eventuell der Titel der E-Mail sein. Die daraus extrahierten Informationen werden in einer Struct gespeichert, die diese Informationen abstrahiert und durch Ableiten um eigene Informationen erweitert werden kann.
Structs sind ein simples wiederkehrendes Pattern in den eZ Components: einfache Klassen mit ausschließlich öffentlichen Eigenschaften ohne Methoden. Sie dienen dazu, Informationen strukturiert vorzuhalten. Der Hauptvorteil ist, dass sie sich effizienter dokumentieren lassen als Arrays, wohingegen sie geringfügig langsamer im Zugriff sind.
Die Struct wird dann dem verwendeten Router übergeben, der den richtigen Controller auswählt und damit die Zuordnung von URLs zur Applikationslogik vornimmt. Es gibt viele Wege, dies zu implementieren – zwei der bekannteren sind zum einen Router basierend auf regulären
Ausdrücken und zum anderen Router wie sie in Ruby on Rails verwendet werden. In beiden Fällen gibt es einfache Pattern, die die URLs „matchen“ müssen, denen dann jeweils eine Controller-Klasse zugeordnet ist. Sobald eines dieser Pattern „matcht“, wird die assoziierte Controller-Klasse instantiiert. Bevor der
Controller dann aufgerufen wird, können eine Reihe von Filtern angewendeten werden, die beispielsweise Request-Logging oder generelle Authentifizierung übernehmen können.
Der Controller greift auf die Applikationsmodelle zu und implementiert die Applikationslogik. Zurückgeben muss er eine Struct, die allerdings beliebige Informationen enthalten kann. Nachdem diese Struct durch einen Filterstack gelaufen ist, entscheidet die View über die Darstellung der vom Controller
generierten Inhalte. Dazu kann sie auf die Informationen in der Rückgabe des Controllers und des Requests zurückgreifen.
Gerade an dieser Stelle ist dem Entwickler die volle Freiheit gelassen, wie die Kommunikation zwischen Controller und View aussehen kann. In einer rein templatebasierten Applikation könnte gar der Name des Templates und eine Liste von Variablen übergeben werden – auch wenn damit der View-Logik eventuell
vorgegriffen wird und man sich leicht an ein spezielles Ausgabemedium bindet.
Ein anderes Modell wäre, dass der Controller nur „View-Structs“ erzeugt. Ein Struct der Klasse „myUserViewStruct“ könnte damit beispielsweise alle Benutzerinformationen enthalten. Der View-Manager wählt für die HTML-Präsentation dann ein spezielles Template: „templates/user.tpl“. Ein JSON- oder XML-View-Handler hingegen könnte das Objekt einfach entsprechend serialisieren und ausgeben.
In jedem Fall entscheidet der View-Handler über die letztendliche Darstellung der Inhalte. Die Art der Präsentation könnte beispielsweise über die Dateiendung in der Request-URL entschieden werden, so dass bei einer .html-URL der HTML-View-Handler vom View-Manager aufgerufen wird, und bei einer .js-Endung die Inhalte als JSON serialisiert werden.
Erneut ist es möglich, die Rückgabe der View mit einem Filter-Stack weiterzuverarbeiten. Mögliche Filter wären zum Beispiel eine Konvertierung in ein Character-Encoding, dass der Client des Besuchers versteht. Während des Entwicklungsprozesses ließe sich das generierte HTML auf Validität prüfen, wohingehend es im Produktivbetrieb komprimiert werden könnte.
Erst nach der Verarbeitung durch die Filter kommt der finale Schritt: die Ausgabe durch die Response-Writer. Auch hier ist eine protokollabhängige Abstraktion notwendig, weil im Falle von HTTP beispielsweise Character-Encoding- und Content-Type-HTTP-Header geschickt werden sollten, während der Aufbau einer E-Mail als Antwort auf einen E-Mail-Request diese Informationen anders verarbeitet. Jede der verwendeten Komponenten ist beliebig erweiterbar und die Anforderungen der Struct-Klassen sind äußerst flexibel. Mit den vorhandenen Implementierungen wird dem Benutzer trotzdem eine konzeptuelle Struktur mit auf den Weg gegeben und grundsätzliche Arbeit abgenommen.
Zusammenfassung
Der volle Prozess mag auf den ersten Blick komplex erscheinen, doch die Filter sind beispielsweise vollständig optional. Request-Parser und Response-Writer müssen bei der Entwicklung einer üblichen HTTP-Anwendung nicht angefasst werden. Die bereits implementierten Router entsprechen den bekannten und oft verwendeten Mechanismen und sollten zumindest für normale Web-Applikationen genügen. Damit ist lediglich die Implementierung von Controller und View notwendig. Alle anderen Bereiche können dann nach Bedarf erweitert werden, falls die eigenen Ansprüche über das Standardverhalten hinaus gehen.
Für die Zukunft ist eine Framework-Komponente innerhalb der eZ Components angedacht, die die bereits existierenden Komponenten wie Template für die Views oder Persistent Object für den Storage-Layer in den Business-Modellen integriert.
Weitere Neuigkeiten im Release
Auch wenn der Fokus auf der MVC-Komponente lag, gibt es eine Reihe von weiteren Neuigkeiten im aktuellen eZ-Components-Release. So kann die Document-Komponente nun zwischen den Dokumenten-Markup-Sprachen XHTML, Docbook, Wiki (Docbook-, Creole- und Confluence-Dialekt), ReStructured Text (RST) und dem eZ-Publish-eigenen „eZ XML“ konvertieren. Dazu wurden für RST und die Wiki-Sprachen Parser implementiert. Die XHTML-Konvertierungen hingegen verwenden einen konfigurierbaren Filter-Stack, um abhängig von den eingehenden Dokumenten Erkennungsheuristiken ab- oder anschalten zu können.
Die Webdav-Komponente [2], mit der sich einfach Webdav-Server für Daten im Dateisystem oder in eigenen Backends implementieren lassen, unterstützt nun sowohl Authentification als auch Locking. Erfolgreich getestet wurde der Server damit nicht nur mit den standardkonformen Clients wie Cadaver oder Nautilus, sondern auch mit den Webdav-Implementierungen der verschiedenen Windows-Versionen. In nahezu allen anderen Komponenten sind dazu noch weitere Features implementiert worden, die man in den Release-Notes nachlesen kann [3].