Im Artikel zum Drupal-Symfony-Modul hatte ich darauf hingewiesen, dass es möglich ist, Symfony komplett schon in Drupal 7 zu integrieren und dass ich dies in einem späteren Artikel darstellen würde. Man muss also nicht Drupal 8 abwarten, um loslegen zu können.
Nun macht es aber Sinn, sich vorher zunächst einmal mit Symfony selbst zu befassen, um zumindest den grundlegenden Workflow bei der Entwicklung von Anwendungen kennenzulernen.
Im folgenden wird deshalb ein einfaches Symfony-CRUD-Bundle unabhängig von Drupal erstellt, das die grundlegenden Aktionen zur Manipulation einer Tabelle wie Create, Read, Update und Delete von Datensätzen enthält.
Ziel ist es, sich zunächst mit dem Konzept von Symfony vertraut zu machen, bevor es in einem späteren Artikel um die Integration in Drupal geht. Dort sind die Erkenntnisse dann von Nutzen.
Welches konkrete Problem kommt einer CRUD-Anwendung sehr nahe? Natürlich ein Blog! Es benötigt die vier grundlegenden Operationen Create, Read, Update und Delete und kommt mit einer einzigen Tabelle aus, solange man das Blog noch nicht um User-Verwaltung und anderes erweitert. Deshalb wird als Bundle - was im Synfony-Jargon nichts anderes ist als eine Modul-artige Anwendung - ein sehr simples Blog implementiert und zwar alleine mit den Scaffolding-Möglichkeiten von Symfony, also ohne eine Zeile Source-Code zu schreiben.
Installation von Symfony
Als erstes installiere ich mir ein frisches Symfony (zu diesem Zeitpunkt Version 2.4.4) in mein Webverzeichns htdocs. Abb. 1 zeigt die resultierende Verzeichnisstruktur.
Abb. 1: Verzeichnisstruktur eines frisch installierten Symfony-Frameworks
Dort finden wir dann im App-Verzeichnis die Anwendung app/console. Das ist ein Kommandozeilen-Interface für Symfony auf PHP-Basis. Damit kann man nach dem Scaffolding-Prinzip grundlegende Symfony-Strukturen, wie z.B. einen CRUD-Controller oder ähnliches, automatisch anlegen lassen.
Wenn wir PHP beispielsweise innerhalb der robusten Entwicklungsumgebung XAMPP installiert haben, müssen wir dafür sorgen, dass unser php.exe dort (im Verzeichnis php) aus jedem anderen Verzeichnis heraus unter anderem von app/console aufgerufen werden kann. Erst dann können wir das Interface app/console vernünftig einsetzen.
Dazu nehmen wir den Pfad zu php.exe in unsere Windows-Umgebungsvariablen auf. Unter Start / Systemsteuerung / System / Erweitert / Umgebungsvariablen finden wir unter Systemvariablen (Achtung: untere Box) die Variable PATH, in die wir den Dateipfad C:\xampp\php getrennt von den anderen Pfaden durch ein Semikolon mit aufnehmen, falls der Pfad nicht schon vorhanden ist.
Jetzt können wir testen, ob sich app/console verwenden lässt. Dazu gehen wir mit der Windows-Eingabeaufforderung in das Symfony-Root-Verzeichnis und geben dort folgendes Kommando ein:
php app/console --version
Wenn die console-App funktioniert, wird die Symfony Version ausgegeben. Damit ist die Installation des Symfony-Frameworks erfolgreich abgeschlossen. wir können nun mit der Einrichtung unseres kleinen Projekts beginnen.
Tipp: Um die Windows-Eingabeaufforderung für ein bestimmtes Verzeichnis direkt zu öffnen, drückt man die Shift-Taste und klickt mit der rechten Maustaste im Windows-Explorer in den Ordner, für den man die Eingabeaufforderung öffnen möchte. Nur in Verbindung mit der Shift-Taste findet man im Rechte-Maustaste-Menu den Link Eingabeaufforderung hier öffnen.
Unser installiertes Symfony-Framework starten wir in der Entwicklungsumgebung mit dieser Url:
- http://localhost/Symfony/web/app_dev.php/
Abb. 2: Startseite von Symfony nach Installation
Wir sehen jede Menge Links zu diversen Dokumentationen und sonstigen Entwickler-Ressourcen. Außerdem findet sich am unteren Rand ein Entwickler-Toolbar mit nützlichen Werkzeugen für die Entwicklung.
Implementierung des Blog-Bundles
Wikipedia liefert eine schöne Definition eines Symfony-Bundles:
"Bundles sind voneinander gelöste Einheiten einer Webapplikation. Ein Gästebuch-Bundle enthält demnach alle Daten, die zur vollständigen Lauffähigkeit des Gästebuchs dienen. Dazu gehören nicht nur die erforderlichen Klassen, sondern auch Ressourcen (Grafiken, Scripts etc.). Entwickler können entwickelte Bundles veröffentlichen, so dass andere Nutzer von Symfony 2 diese Applikationseinheiten ohne Codeänderungen implementieren können."
Bundles werden im Ordner src gespeichert (s. Abb. 1). Wer in diesen Ordner hineinschaut, findet dort das Acme/DemoBundle. Wir möchten nun analog unser simples Blog im Namespace WHR/BlogBundle mittels Scaffolding anlegen. Dabei beachten wir die WikiWord-Schreibweise, da Symfony intensiv das Autoloading von PHP nutzt und solche Konventionen wichtig sind.
Generieren des BlogBundles
Wir legen jetzt unser Bundle mit folgendem Konsolen-Kommano aus dem Root-Verzeichnis unserer frischen Symfony-Installation an:
php app/console generate:bundle
Das Konsolen-Interface stellt einige Fragen zur Einrichtung (hier verkürzt dargestellt):
Bundle namespace: WHR/BlogBundle
Bundle name [WHRBlogBundle]: WhrBlogBundle
Target directory [C:/xampp/htdocs/Symfony/src]:
Configuration format <yml, xl, php, or annotation>: yml
Do you want to generate the whole directory structure [no]: yes
Do you confirm generation [yes]:
Confirm automatic update of your Kernel [yes]:
Confirm automatic update of the Routing [yes]:
You can now start using the generated code!
Wir schauen in den Ordner src und finden dort unser BlogBundle im Ordner WHR. Das BlogBundle enthält schon einige typische Elemente einer MVC-Anwendungs-Architektur (MVC: Model View Controller), wie Controller und Views. Allerdings fehlt noch das Model (in Symfony: Entity). Das wird später mit der Einrichtung der Datenbank ergänzt.
Die abschließende Feststellung nach dem generate:bundle-Kommando: "You can now start using the generated code!" ist ziemlich vollmundig, denn genau genommen können wir mit dem Ergebnis noch gar nichts machen.
Als nächstes beschäftigen wir uns mit der Datenbank. Das simple Blog benötigt ja nur eine Tabelle mit etwas Source-Code drumrum, um Postings speichern zu können, also ein Model bzw. in Symfony eine Entität.
Einrichten der Datenbank
Wir erstellen eine eigene Datenbank für unsere Symfony-Anwendung. Die richten wir für dieses Tutorial mit Hilfe von phpMyAdmin frisch ein. Am einfachsten geht das über die Einrichtung eines neuen Benutzters (Benutzer hinzufügen). Diesen erzeugen wir mit folgenden Parametern:
- Benutzername: db112233_sym3,
- Host: localhost,
- Passwort: test,
- Erstelle eine Datenbank mit gleichem Namen und gewähre alle Rechte (Checkbox).
Schon ist unsere Datenbank eingerichtet.
Mit diesen Daten klicken wir jetzt auf den Button "Configure" (s. Abb. 2) unserer Symfony-Anwendung und übertragen sie in das Folgeformular. Dort bitte dann darauf achten, dass sowohl für den Datenbank-Nutzer als auch für den Namen der Datenbank db112233_sym3 eingestellt wird, da ja üblicherweise für eine solche Konfiguration Datenbankname und Nutzername identisch sind. Die übrigen Einstellungen belassen wir bei den Default-Werten (bzw. lassen sie leer). In einem Folgeformular wird dann noch eine Verschlüsselungsnummer generiert.
Zum Schluss werden uns die erzeugten Konfiguarationsdaten noch einmal im yml-Format präsentiert mit der Meldung: Your parameters.yml file has been overwritten with these parameters (in C:/xampp/htdocs/Symfony/app/config/parameters.yml). Eine gute Gelegenheit, sich diese Konfigurationsdatei einmal genauer anzuschauen. Darin findet man nicht nur die Datenbank-Verbindung, sondern auch die Zugangsdaten eines SMTP-Mail-Servers.
Wir müssen unserer Framework aber noch für die neue Datenbank einrichten. Dafür löschen wir mit dem folgendem Befehl alle bisherigen Tabellen, falls sich dort welche befunden haben sollten (was nicht der Fall ist, aber trotzdem):
php app/console doctrine:database:drop --force php app/console doctrine:database:create
Diese beiden Befehle sollte man immer zusammen ausführen, um eine saubere Konfigurationsgestützte Parametrisierung im Sinne von Symfony zu erreichen. Wenn man nur den Create-Befehl ausführt, kann es später zu Utf8-Problemen und ähnlichem kommen.
Als nächstes erzeugen wir in dieser Datenbank unsere erste Tabelle für unser BlogBundle.
Generieren der Entity "Post" (Datenbank-Tabelle)
Noch finden wir in unserem Ordner src keinen Unterordner Entity. Zur Generierung der Entity Post geben wir folgendes Kommando ein:
php app/console gen:doctrine:entity
Wir beantworten im Abfrage-Dialog die Fragen folgendermaßen (verkürzt):
The Entity shortcut name: WhrBlogBundle:Post
Determine the format to use for the mapping information: yml
You can add some fields now ...
New field name: title
Field type [string]:
Field length [255]:
New field name: body
Field type [string]: text
New field name: published_at
Field type [datetime]:
New field name <press <return> to stop adding fields>:
Do you want to generate an empty repository class [no]:
Do you confirm generation [yes]:
You can now start using the generated code!
Wenn wir jetzt wieder in unseren Ordner BlogBundle schauen, so finden wir dort endlich den bisher vermissten Unterordner Entity. Darin befindet sich eine Klasse Post, die unsere Feld-Definitionen aus der Abfrage oben enthält.
Schauen wir mit phpMyAdmin in die Datenbank, so ist diese immer noch leer. Mit einem Schema-Update erzeugen wir die Datenbank-Tabelle:
php app/console doctrine:schema:update --dump-sql php app/console doctrine:schema:update --force
Mit dem ersten Befehl lassen wir uns den Create-Befehl für die Tabelle post anzeigen und überprüfen ihn auf Stichhaltigkeit. Mit dem zweiten Befehl legen wir die Tabelle dann tatsächlich an, was wir durch einen Blick in die Datenbank mit phpMyAdmin überprüfen können.
Generieren der CRUD-Funktionalität für die Entität "Post"
Schaut man im Ordner BlogBundle in den Unterordner Controller, so findet man dort nur einen DefaultController. Wir brauchen dort zusätzlich einen PostController. Diesen erzeugen wir jetzt automatisch mit dem CRUD-Kommando, das diesen Controller mit den grundlegenden Aktionen Create, Read, Update und Delete inklusive zugehöriger Formulare implementiert. Dazu führen wir folgendes Kommando aus:
php app/console doctrine:generate:crud
Wir beantworten die angebotenen Fragen folgendermaßen (gekürzt):
The Entity shortcut name: WhrBlogBundle:Post
Do you want to generate the "write" actions [no]? yes
Configuration format [annotation]: yml
Routes prefix [/post]:
Do you confirm generation [yes]:
Confirm automatic update of the Routing [yes]:
The command was not able to configure everything automatically.You must do the following changes manually. Import the bundle's routing resource in the bundle routing file (C:\xampp\htdocs\Symfony\src\WHR\BlogBundle/Resources/config/routing.yml). WhrBlogBundle_post: resource: "@WhrBlogBundle/Resources/config/routing/post.yml" prefix: /post
Am Schluss erkennen wir, dass wir noch etwas manuell nacharbeiten müssen. Wir kopieren uns die letzten drei Zeilen in die Zwischenablage (Rechte Maustaste im Eingabefenster / Markieren auswählen, Markieren und mit Ctrl-C in die Zwischenablage übernehmen).
Diesen Inhalt aus der Zwischenablage kopieren wir dann in die angegebene Datei routing.yml.
Achtung: Dabei unbedingt darauf achten, dass die Abstände dort nicht durch Tabs sondern durch Blanks erzeugt werden.
Wir finden jetzt außerdem in unserem BlogBundle/Controller-Ordner die Datei PostController.php. Es lohnt sich für das Verständnis, sich diese Datei genauer anzuschauen.
Testen des Ergebnisses
Ist das geschafft, können wir das Ergebnis überprüfen, indem wir folgende Url aufrufen:
- http://localhost/Symfony/web/app_dev.php/post/
Sollten in routing.yml noch Tabs versehentlich enthalten sein, bekommen wir eine Menge Fehlermeldung, aber auch einen Hinweis auf dieses Problem, das wir leicht abstellen können. Einfach nochmal die Datei auf Tabs hin überprüfen.
Ansonsten sehen wir folgendes Fenster:
Abb. 3: Erfolgreicher Abschluss der Generierung des BlogBundle mittels Scaffolding
Man kann nun beliebige Blog-Postings erzeugen, anzeigen, ändern und löschen.
Zusammenfassung
Dieser Exkurs in die Welt von Symfony war notwendig, um einen späteren Artikel besser nachvollziehen zu können. Es werden die grundlegenden Schritte zur Erstellung einer Symfony-Modul-Applikation (Bundle) nach dem Scaffolding-Prinzip beschrieben.
In dem zukünftigen Artikel zur Integration von Symfony in Drupal 7 wird dann beschrieben, wie man aus dem Blog-Bundle ein vollwertiges Drupal-Modul erstellen und dabei alle Möglichkeiten von Symfony zur Entwicklung nutzen kann.