Die Klassen des f9-Frameworks sind vor dem Hintergrund einen bestimmten Anwendungsarchitektur entworfen. Das heißt nicht, dass man seinen Anwendungen unbedingt so strukturieren muss; es heißt vielmehr, dass es wahrscheinlich ist, dass eine Anwendung, die auf eine bestimmte Art organisiert ist, vom f9-Design am meisten profitieren dürfte. Dieser Artikel beschreibt eine beispielhafte Anwendungsarchitektur einer Anwendung; ein ausführlicher Beitrag mit einem Beispiel, in dem alle f9-Klassen mindestens einmal benutzt werden, folgt, wenn alle Klassen im Detail vorgestellt wurden.
- 10 subjektive Kriterien für ein gutes PHP (micro-) Framework
- f9 – noch ein neues PHP-Micro-Framework
- Eine beispielhafte f9-Anwendungsarchitektur
- Der f9-RequestDispatcher
- Die f9-View-Klassen
- Ein erstes Mini-Beispiel mit f9
- Die f9-Datenbank-Klasse
- Sessions in f9
- Der f9-Dependency-Injection-Container
- Views und Request mit dem Bean-Container verbinden
Im Artikel über Kriterien für ein gutes php-Micro-Framework stand die Forderung danach, dass das Framework keine Anwendungsarchitektur vorschreiben solle, sehr weit oben. Trotzdem jetzt also erstmal ein Beitrag über eine Anwendungsarchitektur? Ja, weil jedes Framework mit dem Design der zur Verfügung gestellten Klassen und mit den unterstützten Patterns bestimmte Architekturen zumindest bevorzugt. Diese Bevorzugung kann man wahrscheinlich nicht umgehen, man kann aber versuchen, das Framework so zu gestalten, dass es nicht bei der einen Architektur bleiben muss und Anwender auch für ihre Vorlieben und Vorstellungen Unterstützung finden.
Model-View-Controller – natürlich, Dependency Injection – möglich
Die Frameworks, die sich nicht an der Model-View-Controller-Architektur (MVC) orientieren, kann man an einer Hand abzählen. Und so legt auch f9 eine solche Architektur nahe. f9 orientiert sich an MVC-Architekturen zunächst insofern, als mit dem RequestDispatcher
ein Front-Controller für die (na was wohl?) Controller-Ebene zur Verfügung steht. Aber auch für die View-Ebene sind Klassen vorhanden. Und das Modell? Dafür sind eben keine Klassen vorhanden, denn in einem guten Framework sollte man das Daten-Modell unabhängig von Patterns wie MVC entwerfen können.
Und mit der Controller- und View-Unterstützung wars das auch schon mit den expliziten Vorgaben. Denn eine zweite ‚Vorgabe‘, die f9 für die Anwendungsarchitektur macht, ist eigentlich keine: Man muss sie nicht nutzen. Dieser zweite ‚Vorgabe‘ ist der BeanContainer
, ein Dependency Injection-Container. Für kleinere Anwendungen könnte es durchaus Overkill sein, Dependency Injection zu nutzen. Dann geht es auch gut ohne, denn keine andere f9-Klasse ist vom BeanContainer
abhängig.
Vier Schichten – eine beispielhafte Architektur
Die im Folgenden beschriebene Architektur sieht vier Schichten vor, die sich im einfacheren Falle auf drei reduzieren lassen. Das ganze ist wie gesagt nur als Vorschlag gedacht und soll hier eher zeigen, von welcher Architektur-Vorstellung ich bei f9 ausgegangen bin.
Die erste Schicht: Requests und Controller
Die erste Schicht, die Controller-Schicht des MVC-Patterns wird von f9 durch den RequestDispatcher
unterstützt. Der RequestDispatcher
ist selbst ein Controller, der die eingehenden Requests an ‚Sub-Controller‘ verteilt. Während der Dispatcher nur konfiguriert werden muss, müssen die ‚Sub-Controller‘, d.h. die eigentlichen Controller, die die eigentliche Arbeit leisten, im Zuge der Anwendungsentwicklung tatsächlich selbst geschrieben werden. f9 macht hier aber keine Vorgaben, wie die Controller auszusehen haben: Es können Funktionen oder Methoden sein; die Signatur, Namen oder bestimmte Parameter sind nicht vorgegeben.
Die Controller checken die übergebenen Parameter und bauen daraus die Aufrufe für die nächste Schicht zusammen: Die Service-Ebene. Dann entscheiden sie (z.B. durch Auswertung des Requests) darüber, welcher View zur Anwendung kommt, übergeben die Daten, die von Service-Methode zurückgegeben wurden an den View und senden die Ausgabe des Views zurück an den den Client.
Möglich, aber nicht nötig: Die Service-Schicht
Die zweite Schicht, die Service-Schicht, ist bei größeren Projekten sinnvoll, bei kleinen dagegen kann es ein wenig zuviel des Guten sein. Hat man sich entschieden, auf eine eigene Service-Schicht zu verzichten, kann man alles auch bereits im Controller erledigen. Da das aber recht schnell unübersichtlich wird, sollte das nur gemacht werden, wenn die Zahl der Controller sehr klein ist.
In der Service-Schicht findet die eigentliche inhaltliche Arbeit statt. Man kann sie auch als Business-Schicht bezeichnen, denn hier werden die eigentlichen inhaltlichen Entscheidungen getroffen und die Business-Abläufe einer Anwendung umgesetzt. Wenn in einem Web-Shop für jede Neuanmeldung eines Kunden eine interne Mail an den Vertrieb gehen soll oder bei jedem Kauf über 500€ weitere Checks vorgesehen sein sollen, dann ist die Service-Ebene der Ort, solche Anforderungen umzusetzen.
Von f9 wird die Service-Ebene nicht nur nicht explizit vorgesehen (das sowieso nicht), sondern auch nicht weiter unterstützt. Wie beim Modell sollte der Code hier vom Framework völlig unabhängig sein.
Die dritte Schicht: Persistenz
Die Service-Ebene erzeugt Daten, fällt Entscheidungen auf der Basis von Daten usw., aber sie sorgt nicht dafür, dass diese Daten gelesen, gespeichert oder dauerhaft geändert werden. Dies leistet die Persitenz-Schicht, die man auch als Datenbank-Ebene bezeichnen könnte, wenn durch den Begriff nicht die unnötige Vorgabe gemacht würde, dass die Daten-Speicherung in einer Datenbank und z.B. nicht im Datei-System gemacht wird. Die Persistenz-Methoden werden von den Service-Methoden aufgerufen. Die Auslagerung des Persistenz-Codes in einen eigene Schicht hat den Vorteil, dass man sich in der Service-Ebene auf die inhaltlichen Dinge (das Was) konzentrieren kann, das Wie erledigt die Persistenz-Schicht. Oft wird als Vorteil dieser Auslagerung auch genannt, dass man z.B. leichter die Datenbank austauschen könne — ich habe aber noch nie gehört, dass dies in einem echten Projekt auch wirklich gemacht wurde. Der genannte Grund, das Was und das Wie zu trennen, scheint mir praxisnäher zu sein.
Und schließlich: Die-View-Schicht
Oben, beim Thema Controller hatte ich schon mal angerissen, wie der Informationsfluss in der hier vorgeschlagenen Architektur läuft. Vom Controller zum Service, dessen Rückgabe-Daten der Controller dem View übergibt, dessen Rückgabe der Controller an den Client zurücksendet.
Wir sind also jetzt bei der letzten Schicht angelangt, dem View, d.h. der Schicht, die die berechneten und gelesenen Daten in ein bestimmtes Format für die Anzeige beim Client bringt.
Die View-Schicht wird in f9 durch mehrere Klassen unterstützt. Zum einen von einer View
-Klasse selbst, die das View-Template (meist die HTML-Datei) mit den Daten aus dem Model versorgt. Zum anderen aber auch durch einen ViewResolver
, der dem Controller dabei hilft, den richtigen View überhaupt erst auszuwählen und zu finden. Richtig interessant wird dies z.B. dann, wenn für die gleichen Daten Views mit unterschiedlichen Ausgabeformaten (z.B. HTML und JSON) zur Verfügung stehen.
Mit der Auswahl des passenden View (durch den Resolver) kann also ganz leicht ein Set an Sichten auf die Daten bereitgestellt und ausgewählt werden — und das unabhängig voneinander und vor allem: So, dass alle anderen Schichten von der Wahl des Formats völlig unberührt bleiben.
Schluss
Noch einmal: Man muss eine Anwendung, die Klassen aus f9 nutzt, nicht so umsetzen. Aber die hier beschriebene Architektur stand im Hintergrund, als ich den Code geschrieben bzw. integriert habe. Die folgenden Artikel werden die einzelnen Klassen beschrieben und am Schluss ein umfassendes Beispiel bringen.
Downloads
Das komplette f9-Framework mit allen Klassen und Beispielen:
[download id=“12″]