Neues von FLOW3

Neues von FLOW3: The final Countdown
Kommentare

Nach einer Entwicklungszeit von nahezu fünf Jahren verlässt FLOW3 seine Alphaposition und bewegt sich rasend schnell auf die erste finale Version zu. Das FLOW3-Team, eine Arbeitsgruppe innerhalb der TYPO3 Association [1] rund um Robert Lemke und Karsten Dambekalns, hat sich vorgenommen, ein modernes und zukunftsträchtiges PHP Enterprise Framework zu erschaffen, das den Vergleich mit Symphony, Ruby on Rails oder Spring nicht im Geringsten zu scheuen brauchen wird. Zunächst für die nächste Generation des Enterprise CMS TYPO3 entwickelt, kann FLOW3 davon völlig unabhängig verwendet werden, um moderne komplexe Webapplikationen zu erstellen. Der folgende Artikel soll eine Starthilfe zu FLOW3 geben.

FLOW3 vereint viele moderne Konzepte wie Domain-driven Design (DDD), Model View Controller (MVC), Aspect-oriented Programming (AOP), Dependency Injection (DI) und einige weitere [2] in einem ganzheitlichen Framework, das grundsätzlich mit dem Paradigma Convention over Configuration konzipiert wurde. Das beschleunigt die Entwicklung enorm, da bereits viele sinnvolle Annahmen getroffen wurden, um die sich der Entwickler zunächst nicht kümmern muss. Er kann sich zu jeder Zeit voll und ganz auf sein Problem und dessen Lösung konzentrieren. Wenn auch in der Einleitung viele Buzzwords den Eindruck erwecken, dass die Arbeit mit FLOW3 mit sehr viel Aufwand für den Programmierer von heute verbunden ist, so ist der Einstieg in das Framework dennoch einfach.

Installation von FLOW3

Vor der Installation von FLOW3 müssen folgende Systemvoraussetzungen erfüllt sein:

  • Ein Webserver (empfohlen wird Apache mit aktiviertem mod_rewrite-Modul)
  • PHP 5.3.2 oder höher (mit memory_size > = 128M und magic_quotes_gpc = Off)
  • Eine PDO-kompatible Datenbank wie MySQL
  • Zugriff zur Kommandozeile

Selbstverständlich versteht sich FLOW3 aber auch mit anderen Datenspeichern wie NoSQL (beispielsweise CouchDB [3] ). Laden Sie sich zunächst FLOW3 von der Projektwebsitehttp://flow3.typo3.org/download/ herunter und entpacken das Archiv auf Ihrem Webserver:

Build/
Configuration/
Data/
Packages/
Readme.txt
Upgrading.txt
Web/ <-- Das Document-Root muss auf das Verzeichnis Web zeigen
flow3
flow3.bat

Ihren Webserver richten Sie so ein, dass das Document Root auf das Verzeichnis Web zeigt. Alle für das Framework relevanten Teile liegen damit also außerhalb des Document-Root-Verzeichnisses, was für eine Basissicherheit sorgt. Nun müssen die Zugriffsrechte entsprechend gesetzt werden. Da man auf FLOW3 sowohl über die Konsole (eine Übersicht über alle möglichen Kommandos erhalten Sie mit ./flow3 help) als auch über den Webserver zugreift, gibt es einen eigenen Befehl, der beide Zugriffsberechtigungen entsprechend richtig setzt:

./flow3 core:setfilepermissions patricklobacher www www

Anstelle von „patricklobacher“ geben Sie Ihren Shell-Benutzer an, darauf folgend kommt der Webserveruser (www-data) und abschließend die Webservergruppe (www-data). Unter Mac OS X ist Webserveruser und -gruppe auch oft _www anstelle von www-data. Zusätzlich ist es sinnvoll, den eigenen User zur Webservergruppe zuzufügen: sudo usermod -a -G www-data patricklobacherbeziehungsweise sudo dscl . -append /Groups/_www GroupMembership patricklobacher für Mac OS X. Wenn Sie nun die Website aufrufen (im Folgenden wird von einem virtuellen Host mit dem Namen flow3 ausgegangen, also http://flow3/), sollten Sie den FLOW3 Welcome Screen sehen können (Abb. 1). Wenn Sie stattdessen eine Fehlermeldung sehen, so überprüfen Sie das PHP Error Log auf entsprechende Einträge. Eventuell wundern Sie sich über die Geschwindigkeit beim ersten Aufruf. Der Grund liegt daran, dass FLOW3 per Default im sogenannten Development Context startet, in diesem werden Fehler- und Debug-Meldungen ausgegeben und zudem wird der Cache viel loser verwendet. Zudem baut sich der Cache beim ersten Laden erst einmal auf.

Abb. 1: Der FLOW3 Welcome Screen

Sobald Ihre Webapplikation fertig gestellt ist, können Sie FLOW3 so konfigurieren, dass es im Production Context läuft. Dafür reicht ein entsprechender Eintrag in der vhost-Datei:

DocumentRoot /opt/local/apache2/htdocs/flow3/
ServerName flow3
SetEnv FLOW3_CONTEXT Production


Ein Package erstellen

Der Code einer Applikation inklusive ihrer Ressourcen (wie Bilder, Stylesheets, Templates etc.) wird in so genannte Packages gebündelt. Jedes Package wird durch einen eindeutigen Namen gekennzeichnet, der aus dem Firmen- beziehungsweise Domainnamen (Vendor-Name) und dem Package-Namen besteht. Wir verwenden im folgenden Acme [4] als Vendor-Name und Demo als Package-Namen, somit erhalten wir also den Package-Key ACME.Demo. Um das Package anzulegen, können wir den Kickstarter verwenden, der über das FLOW3-Kommandozeilentool erreichbar ist (Windows-Benutzer können hier die Datei flow3.bat verwenden):

$ ./flow3 kickstart:package Acme.Demo
Created .../Acme.Demo/Classes/Controller/StandardController.php
Created .../Acme.Demo/Resources/Private/Templates/Standard/Index.html

Der Kickstarter legt nun das Package inklusiver Controller, Template und einiger weiterer Dateien sowie Verzeichnisse unterhalb des Ordners Packages/Application/ an (Listing 1). Rufen Sie nun die Website unter http://flow3/Acme.Demo auf um die Default-Ausgabe zu erhalten. Wenn auf Ihrem Webserver mod_rewrite nicht funktionieren sollte, können Sie den folgenden URL verwenden:http://flow3/index.php/Acme.Demo.

Acme.Demo
Classes
Controller
StandardController.php
Package.php
Configuration
Settings.yaml.example
Documentation
Meta
Package.xml
Ressources
Private
Templates
Standard
Index.html
Tests
Functional
Unit


Model View Controller (MVC)

Prinzipiell richtet sich FLOW3 streng nach dem MVC Pattern. Der Controller (ohne weitere Konfiguration ist das der StandardController, das ist in der Datei Configuration/Routes.yaml so eingestellt) ruft seine Standard-Action (in unserem Fall index) auf. Das ist eine Methode mit dem Namen indexAction() innerhalb des Controllers. Dort wird der View, die bereits für uns initialisiert ist und unter dem Namen ->view zur Verfügung steht, mithilfe der Methode ->view->assign(,) ein Wert (hier ein Array) zugewiesen:

public function indexAction() {
$this->view->assign('foos', array(
'bar', 'baz'
));
}

Am Ende der Action wird die View implizit mit ->view->render() gerendert und ausgegeben (das Ergebnis wird mittels return zurückgegeben). Wird diese Zeile weggelassen, so geht FLOW3 davon aus, dass diese ausgeführt werden soll. Will man das vermeiden, so kann man beispielsweise mit einem Return-Wert ungleich NULL arbeiten. Dabei wird zunächst das Template ermittelt, das sich im Pfad Acme.Demo/Resources/Private/Templates/ befindet. Dort gibt es für jeden Controller ein gleichnamiges Verzeichnis (Standard), und darin befindet sich für jede Action eine ebenfalls gleichnamige Template-Datei (Index.html). Als Templating Engine wird dabei Fluid [5] verwendet, das nach langer Evaluierung der bestehenden Templating Engines von Grund auf neu geschrieben wurde (Kasten: „Die Templating Engine Fluid“).

Die Templating Engine Fluid Fluid wurde mit folgenden Zielen initial von Sebastian Kurfürst für FLOW3 entwickelt und wird darüber hinaus auch bei TYPO3 verwendet:

  • Einfache, elegante und vor allem intuitive Verwendung
  • Unterstützung des Template Autors (Autovervollständigung u. Ä. muss möglich sein)
  • Einfache und saubere Erweiterbarkeit
  • Wohlgeformtes, valides XML
  • Unterstützung vieler Ausgabeformate
  • Vollständige Objektorientierung

Im Template (Index.html) sehen wir nun, dass auf das vorher zugewiesene Array mittels einer Schleife, die durch einen so genannten Fluid ViewHelper realisiert wird, zugegriffen wird. Über den Objektzugriffsoperator {} kann also nun das Array angesprochen werden und wird über den for-ViewHelper iteriert. Dabei wird ein einzelnes Objekt mit dem Namen foo zur Verfügung gestellt, das wiederum über {foo}angesprochen werden kann:

  • {foo}
  • [ header = Seite 2: Hello World ]

    Hello World

    Um uns nun weiter durch die FLOW3-Welt zu tasten, erweitern wir den StandardController um eine weitere Action, die einen Input-Parameter aufnehmen kann und ihn direkt wieder ausgibt:

    /**
    * Hello action
    *
    * @param string $name Ein Name
    * @return string Enthält das Hallo
    */
    public function helloAction($name) {
    return "Hallo $name! Wie geht es Dir?";
    }
    

    Der URL für diese Action lautet nun http://flow3/Acme.Demo/Standard/hello?name=Leser. Es wird also an den Package Key der Name des Controllers und anschließend der Name der Action angehängt, und in diesem Fall zusätzlich ein GET-Parameter (name=Leser), der dann als in der Action zur Verfügung steht.

    Wie im vorherigen Beispiel zu erkennen ist, verwendet FLOW3 so genannte Annotations (/** …*/), um den Quellcode mit Metadaten auszustatten. So wird oben der Typ des Parameters (string) bestimmt und vor allem auch durch FLOW3 überprüft. Die Annotations werden daher auch für den Programmfluss eingesetzt und sind essenziell. Daher ist auch vor der Entwicklung mit FLOW3 zu überprüfen, ob gegebenenfalls ein PHP Accelerator verwendet wird, der diese Annotations entfernt.

    Verbindung zur Datenbank

    Eines der wichtigsten Designziele für FLOW3 war es, dass sich der Programmierer voll und ganz auf die Geschäftslogik konzentrieren und Infrastruktur wie Templating oder eben auch Datanbankzugriff völlig ignorieren kann. Das wird auch als Infrastructure Ignorance bezeichnet und ist eine der Säulen im Domain-driven Design (DDD). Folgerichtig merkt der Entwickler auch nichts mehr von der Datenbank, sobald er sie einmal eingerichtet hat. So wird kein SQL-Code geschrieben und selbst der Zugriff auf die in der Datenbank gespeicherten Daten erfolgt meist völlig automatisch und transparent an den benötigten Stellen. Bevor die Datenbank aber einsatzfähig ist, muss sie konfiguriert werden. Dafür kopiert man sich die Datei Configuration/Settings.yaml.example in Configuration/Settings.yaml um und editiert sie:

    TYPO3:
    FLOW3:
    persistence:
    backendOptions:
    driver: 'pdo_mysql'
    dbname: 'flow3' # Datenbank-Name
    user: 'root' # Datenbank-User
    password: 'password' # Datenbank-Passwort
    host: '127.0.0.1' # Datenbank-Host
    port: '3306' # Datenbank-Port
    
    

    In dieser YAML-Konfigurationsdatei [6] werden nun die Zugangsdaten für die MySQL-Datenbank eingetragen, die vorher schon existieren muss. Zuletzt muss das in FLOW3 integrierte Doctrine2-Framework angewiesen werden, die benötigte Datenbankstruktur aufzubauen:

    $ ./flow3 doctrine:migrate
    Migrating up to 20110824124935 from 0
    ++ migrating 20110613223837
    ...
    ++ finished in 0.47
    ++ 5 migrations executed
    ++ 28 sql queries
    
    

    Speichern von Objekten

    Mithilfe des Kickstarters können wir nun auch ein Domänenobjekt samt zugehörigem Controller, Repository (Zugriffseinheit für den Datenzugriff) und Templates für den CRUD-Prozess (Create, Read, Update, Delete) sowie ein Default-Layout (das von jedem Template geladen wird) anlegen lassen. Da ich genauso wie die FLOW3-Chefarchitekten kaffeesüchtig bin, verwende ich hier natürlich als Domänenobjekt die CoffeeBean (Listing 2), (Abb. 2). Sobald man ein neues Modell erstellt oder ein bereits erstelltes verändert, muss die Datenbankstruktur entsprechend angepasst werden. Das kann über die doctrine:update-Funktion in der Kommandozeile erledigt werden:

    $ ./flow3 kickstart:actioncontroller --generate-actions --generate-related Acme.Demo CoffeeBean
    Created .../Acme.Demo/Classes/Domain/Model/CoffeeBean.php
    Created .../Acme.Demo/Classes/Domain/Repository/CoffeeBeanRepository.php
    Created .../Acme.Demo/Classes/Controller/CoffeeBeanController.php
    Created .../Acme.Demo/Resources/Private/Layouts/Default.html
    Created .../Acme.Demo/Resources/Private/Templates/CoffeeBean/Index.html
    Created .../Acme.Demo/Resources/Private/Templates/CoffeeBean/New.html
    Created .../Acme.Demo/Resources/Private/Templates/CoffeeBean/Edit.html
    Created .../Acme.Demo/Resources/Private/Templates/CoffeeBean/Show.html
    
    
    
    $ ./flow3 doctrine:update
    Executed a database schema update.
    
    

    Der Aufruf zum Anlegen und Verwalten von CoffeBeans geht nun analog: http://flow3/Acme.Demo/CoffeeBean/.

    Abb. 2: Der CRUD-Prozess für das Domänenobjekt CoffeeBean

    [ header = Seite 3: Analyse des Codes ]

    Analyse des Codes

    Schauen wir uns nun den erhaltenen Code des Modells (CoffeeBean.php) und des Controllers (CoffeeBeanController.php) etwas genauer an, um zu verstehen, was unter der Haube von FLOW3 vor sich geht (Listing 3). Das Domänenobjekt CoffeeBean ist gemäß DDD eine Entity [7] (das wird durch die Annotation @entity gekennzeichnet) und besitzt die Eigenschaft name, die (wie im Übrigen alle Properties in FLOW3) als protected gekennzeichnet ist. Daher benötigt es öffentliche Getter und Setter, die ebenfalls mit erzeugt wurden. Sämtliche Zugriffe (schreibend und lesend) auf die Eigenschaften erfolgen innerhalb von FLOW3 und Fluid ausschließlich über diese Funktionen. So ist der Code des erzeugten Controllers schon etwas umfangreicher (Listing 4).

    name;
    }
    
    /**
    * Sets this Coffee bean's name
    *
    * @param string $name The Coffee bean's name
    * @return void
    */
    public function setName($name) {
    $this->name = $name;
    }
    }
    ?>
    
    view->assign('coffeeBeans', $this->coffeeBeanRepository->findAll());
    }
    
    /**
    * Shows a single coffee bean object
    *
    * @param AcmeDemoDomainModelCoffeeBean $coffeeBean The coffee bean to show
    */
    public function showAction(CoffeeBean $coffeeBean) {
    $this->view->assign('coffeeBean', $coffeeBean);
    }
    
    /**
    * Shows a form for creating a new coffee bean object
    */
    public function newAction() {
    }
    
    /**
    * Adds the given new coffee bean object to the coffee bean repository
    *
    * @param AcmeDemoDomainModelCoffeeBean $coffeeBean A new coffee bean to add
    */
    public function createAction(CoffeeBean $newCoffeeBean) {
    $this->coffeeBeanRepository->add($newCoffeeBean);
    $this->flashMessageContainer->add('Created a new coffee bean.');
    $this->redirect('index');
    }
    
    /**
    * Shows a form for editing an existing coffee bean object
    *
    * @param AcmeDemoDomainModelCoffeeBean $coffeeBean The coffee bean to edit
    */
    public function editAction(CoffeeBean $coffeeBean) {
    $this->view->assign('coffeeBean', $coffeeBean);
    }
    
    /**
    * Updates the given coffee bean object
    *
    * @param AcmeDemoDomainModelCoffeeBean $coffeeBean The coffee bean to update
    */
    public function updateAction(CoffeeBean $coffeeBean) {
    $this->coffeeBeanRepository->update($coffeeBean);
    $this->flashMessageContainer->add('Updated the coffee bean.');
    $this->redirect('index');
    }
    
    /**
    * Removes the given coffee bean object from the coffee bean repository
    *
    * @param AcmeDemoDomainModelCoffeeBean $coffeeBean The coffee bean to delete
    */
    public function deleteAction(CoffeeBean $coffeeBean) {
    $this->coffeeBeanRepository->remove($coffeeBean);
    $this->flashMessageContainer->add('Deleted a coffee bean.');
    $this->redirect('index');
    }
    
    }
    
    ?>
    
    

    Da beim Aufruf keine Action definiert wurde, sucht FLOW3 zunächst die Index-Action und ruft diese auf. Dort wird das CoffeeBeanRepository befragt, das wiederum alle >em>CoffeeBean-Objekte zurückliefert und an die View übergibt. Das Repository wird elegant mittels Dependency Injection über die Annotation @inject ein paar Zeilen darüber injiziert und ist selbst leer. FLOW3 hat hier bereits für ein paar vorgefertigte Methoden (wie eben ein findAll(), das alle Objekte findet) gesorgt. Sie lassen sich natürlich beliebig anpassen oder erweitern. Das Template zeigt nun die Objekte an und versieht die View über ViewHelper mit so genannten Action-Links zum Neuanlegen, Löschen und Editieren der Objekte.

    Klickt man „Create a new coffee bean“ an, landet man in der New Action, die ihrerseits ein Formular anzeigt, in das man den Namen eingeben kann. Abgeschickt wird es an die Create Action, die aus den POST-Daten automatisch ein CoffeeBean-Objekt erstellt und dieses dem Repository zufügt. Am Ende der Methode wird das Objekt dann automatisch persistiert, also in die Datenbank geschrieben. Zwischenzeitlich wird noch eine so genannte Flash Message zugefügt, die später im Template der Index-Action über einen entsprechenden ViewHelper wieder angezeigt wird. Da die Action ansonsten nichts weiter tun muss, erfolgt am Ende noch eine (vollwertige) Weiterleitung zur Index-Action.

    Auch die anderen Actions des CRUD-Prozesses sind einfach aufgebaut, so gibt es einfache Repository-Methoden zum Editieren (update) und Löschen (delete). Hier werden die zugehörigen Objekte automatisch ermittelt (beispielsweise beim Update) und das Update-Formular damit vorausgefüllt. Ebenso ist es beim Löschen, auch hier wird das Objekt automatisch aus dem Repository und damit aus der Datenbank gelöscht. Weiteren Einblick in den Code, die vielen Details und auch in die dahinterliegende Theorie finden Sie im FLOW3-Handbuch [8] .

    Validierung

    Auch die Validierung in FLOW3 ist elegant gelöst. So kann man zahlreiche Validatoren in das System bringen um damit jeden Aspekt zu kontrollieren. Wollen wir beispielsweise erreichen, dass der Name unsere CoffeeBean mindestens fünf aber höchsten zehn Zeichen umfassen darf, so können wir dafür eine Validator-Annotation direkt bei der Eigenschaft im Model (Packages/Application/Acme.Demo/Classes/Domain/Model/CoffeeBean.php) notieren:

    /**
    * The name
    * @var string
    * @validate StringLength(minimum = 5, maximum = 10)
    */
    protected $name;
    

    Sobald nun eine Action dieses Objekt als Parameter übergeben bekommt, wird die Eigenschaft name entsprechend validiert. Möglich sind hier die Ausgabe einer Fehlermeldung, die automatische Weiterleitung in eine eigene fehlerbehandelnde Action oder das Korrigieren der fehlerhaften Eigenschaft. Neben den eingebauten Validatoren gibt es zudem auch die einfache Möglichkeit individuelle Validatoren zu verwenden, um einzelne Eigenschaften oder das Objekt als Ganzes zu validieren. Schließlich lassen sich die Validatoren auch direkt gezielt in einer Action notieren, sodass sie nur dort wirksam sind. Damit lassen sich nahezu alle Szenarien der Validierung erschöpfend behandeln.

    Cheat Sheet

     Nachdem das Framework auf der Philosophie Convention over Confguration basiert, sind also viele Konventionen bereits getroffen worden, um die man sich dann nicht mehr kümmern muss. Allerdings muss man diese Konventionen irgendwann einmal auswendig lernen oder zumindest wissen, wo man sie nachschlagen kann. Der Autor hat daher die wichtigsten Dinge für FLOW3 und Fluid auf Cheat Sheets zusammengefasst, die man sich unter [9] kostenlos herunterladen kann.

    Ausblick

    Dieses kurze Tutorial, das grundsätzlich auf dem Quickstart Manual [10] des FLOW3-Teams basiert, kann natürlich nur einen groben Überblick über die zahlreichen Fähigkeiten von FLOW3 geben. Viele wichtige Aspekte, wie die Interaktive Shell, Routing, Signal Slots oder AOP hat der Artikel mangels Platz beispielsweise noch nicht einmal erwähnt, und andere Aspekte sind nur leicht gestreift worden. Tatsächlich soll der Artikel vor allem eines bewirken: die ersten Hürden nehmen und Appetit auf dieses neue, leistungsfähige und spannende Framework machen. Denn das Programmieren in oder mit FLOW3 macht einfach Spaß, das kann der Autor garantieren.

    Unsere Redaktion empfiehlt:

    Relevante Beiträge

    Meinungen zu diesem Beitrag

    X
    - Gib Deinen Standort ein -
    - or -