Anzeige
Anzeige
UX & Design
Artikel merken

Ein Tutorial zum Einstieg in das PHP-Framework: Anwendungsentwicklung mit Symfony

Symfony ist ein mächtiges Framework für die Entwicklung von Webanwendungen, das viele erprobte Komponenten und Design-Paradigmen der modernen Software-Architektur unterstützt. Das Arbeiten mit Codegenerator, MVC-Schichtmodell und objektrelationalem Mapping ist für viele PHP-Entwickler zuerst ungewohnt. In diesem Tutorial sollen die einzelnen Schritte zu einem ersten Symfony-Projekt beschrieben werden, jedoch nicht ohne gelegentlich tiefer in die Symfony-Strukturen abzutauchen.

7 Min. Lesezeit
Anzeige
Anzeige

Eine Symfony-Anwendung ist ein Projekt, das sich in Applikationen und Module aufteilt. Alle diese Einzelkomponenten lassen sich komfortabel mit dem Symfony-Kommando erzeugen. Eine typische Webanwendung besteht aus einer Frontend- und einer Backend-Applikation, die jeweils diverse Module enthalten können. Um die Architektur des Symfony-Frameworks anschaulich darzustellen,
werden wir als Beispielanwendung ein Blog implementieren. Der Einfachheit halber gehen wir hier von der Sandbox-Variante von Symfony [1] aus, in der schon ein Projekt mit einer Frontend-Anwendung vorinstalliert ist. Die Sandbox wird einfach im Webserver-Root-Verzeichnis entpackt. Da wir die Blogeinträge in einer Datenbank ablegen wollen, sollte eine MySQL-Datenbank vorhanden sein. Wir verwenden in diesem Tutorial eine Datenbank mit dem Namen „blog“. Username und Passwort sind ebenfalls „blog“. Die Datenbank legt man entweder über die Kommandozeile oder komfortabel mit phpMyAdmin an.

Das Datenmodell

Anzeige
Anzeige

Basis eines jeden datenbankbasierten Web-Projekts ist ein sauberes Datenmodell. Ein solches relationales Schema erstellt man üblicherweise im Texteditor oder mit einem visuellen Modellierungswerkzeug wie zum Beispiel DBDesigner 4 [2]. Die neben den eigentlichen Relationen im Schema enthaltenen Fremdschlüsselbeziehungen zwischen den Tabellen verwendet Symfony später intelligent in seinem Datenmodell. Das von Symfony genutzte Propel-XML für das DB-Schema ist unabhängig vom verwendeten Datenbanksystem, die erstellte Anwendung kann also problemlos auf jedes unterstützte DBMS portiert werden. Sollte im config-Verzeichnis bereits eine schema.yml-Datei liegen, so ist diese zu löschen, da wir auf die wesentlich komfortablere XML-Schemadatei setzen. Mit einem guten Editor (z. B. Eclipse) kann sie dank vorhandener DTD (liegt bei den Propel-Quellen) mit Code-Completion und Validierung effizient und fehlerfrei erstellt werden.

config/schema.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE database SYSTEM "../lib/symfony/vendor/propel-generator/resources/dtd/database.dtd" >
<database defaultIdMethod="native" name="blog">
  <table name="blog_entry">
    <column name="id" type="INTEGER" primaryKey="true" autoIncrement="true" />
    <column name="title" type="VARCHAR" size="255" required="true" />
    <column name="content" type="VARCHAR" size="2048" />
    <column name="deleted" type="BOOLEAN" default="0" />	
    <column name="created_at" type="TIMESTAMP"/>
    <column name="updated_at" type="TIMESTAMP" />    
  </table>
</database>

Listing 1

Aus diesen Informationen lassen wir den Codegenerator von Symfony nun ein Objektmodell erzeugen. Damit Symfony auch direkt eine Datenbank anlegen kann, muss diese zuerst in den Dateien databases.yml und propel.ini konfiguriert werden. Während in propel.ini die Werte für den ORM-Layer verwaltet werden, regelt die databases.yml den Datenbankzugriff für die eigentliche Symfony-Anwendung. In den meisten Fällen stehen in beiden Dateien die gleichen Parameter.

Anzeige
Anzeige
Ausschnitt: propel.ini
propel.targetPackage = lib.model
propel.packageObjectModel = true
propel.project = blog
propel.database = mysql
propel.database.createUrl = mysql://localhost/
propel.database.url = mysql://blog:blog@localhost/blog
propel.mysql.tableType = InnoDB

Listing 2

Die Datei databases.yml verwendet die Markup-Sprache YAML (Yet Another Markup Language), die Symfony-weit Verwendung für Konfigurationsdateien findet. Das Markup ist sehr empfindlich, denn Einrückungen mit Leerzeichen sorgen für die Semantik. Tipp: Benutzen Sie keine Proportionalschriftart und keine Tabulatoren im Editor!

Anzeige
Anzeige
databases.yml
all:
 propel:
 class: sfPropelDatabase 
 param:
 phptype: mysql
 phptype: mysql
 host: localhost
 database: blo
 username: blog

Listing 3

ORM – Object-Relational-Mapping

Danach sorgt das Kommando „symfony propel-build-all“ dafür, dass aus dem DB-Schema ein für die konfigurierte Datenbank passendes SQL-File erzeugt und direkt in die Datenbank geschrieben wird. Gleichzeitig erzeugt der Codegenerator etliche PHP-Klassen, die uns unter Verwendung des ORM-Layers (Object-Relational-Mapping) „Propel“ komfortablen Zugriff auf unsere Datenbank ermöglichen. Anders gesprochen: Jede in unserem DB-Schema definierte Relation bekommt eine eigene PHP-Klasse. Einen neuen Blog-Eintrag können wir jetzt komfortabel ohne SQL anlegen:

ORM in Aktion
$blog_entry = new BlogEntry();
$blog_entry->setTitle('Hallo!');
$blog_entry->setContent('Ich bin ein Inhalt!');
$blog_entry->save();

Listing 4

Keine Angst, das DB-Schema kann später problemlos erweitert werden. Der Codegenerator wird durch eine schlaue Vererbungsstruktur keine unserer manuellen Änderungen überschreiben, sondern nur die zugrundeliegenden Basisklassen manipulieren.

Anzeige
Anzeige

Im Dateisystem finden wir die erzeugten Klassen im Verzeichnis lib/model. Während die Basisklassen in den Verzeichnissen lib/model/om und lib/model/map nicht modifiziert werden dürfen, können die von den Basisklassen abgeleiteten Klassen direkt in lib/model den persönlichen Anforderungen angepasst werden. Sie werden vom Codegenerator nur angelegt, wenn sie noch nicht vorhanden sind, nie jedoch überschrieben. In Symfony teilen sich alle Anwendungen eines Projekts das gleiche Datenmodell.

Erste Schritte zur Webanwendung

Unser Blog wird eine Frontend-Anwendung mit nur einem Modul zur Anzeige und zum Bearbeiten von Blogeinträgen. Da die Sandbox-Installation bereits eine Frontend-Applikation mitbringt, müssen wir lediglich mit „symfony propel-generate-crud frontend blog BlogEntry“ ein Modul anlegen, das schon grundlegende Create-, Retrieve-, Update- und Delete-Mechanismen für unseren im Schema definierten Blog-Datentyp bietet. Mit anderen Worten: Symfony kann das komplette Gerüst einer Webanwendung erzeugen, die unseren Blog-Datentypen verwaltet.

Wenn man diese vorgefertigten CRUD-Operationen nicht braucht, kann man sich auch ein nacktes Modul anlegen und die Funktionalität manuell programmieren. Wir verlassen uns hier jedoch auf die Symfony-Komfortmerkmale und lassen uns die CRUDs mit obigem Kommando erzeugen. Nach dieser Operation hat uns der Codegenerator eine komplette Verzeichnisstruktur samt PHP-Klassen in MVC-Struktur angelegt, wir können unsere Anwendung sogar schon im Browser aufrufen:

Anzeige
Anzeige
URL
http://localhost/sf_sandbox/web/frontend_dev.php/blog

Listing 5

Bisher haben wir noch keine Zeile programmiert.

Environments für Entwicklung und Produktion

Um einfach zwischen Entwicklungsumgebung und Produktionsumgebung in der Webanwendung unterscheiden zu können, bietet Symfony unterschiedliche Environments an. Eine Entwicklungsumgebung der Webanwendung erreicht man über den Dispatcher „frontend_dev.php“, die Produktionsumgebung direkt über „index.php“. In der Entwicklungsumgebung stehen zahlreiche Diagnose- und Debugging-Funktionen in einer Toolbar auf der Weboberfläche zur Verfügung. Im Produktionsbetrieb werden keine Debugging-Informationen zur Verfügung gestellt, die Anwendung wird durch den Einsatz von Caching-Mechanismen deutlich performanter.

Wenn man sich die Dispatcher genauer ansieht, stellt man fest, dass das Environment lediglich durch eine Konstantendefinition festgelegt wird:

Anzeige
Anzeige
Environments definieren
define('SF_ENVIRONMENT', 'dev');
define('SF_DEBUG', true);

Listing 6

Doch zurück zu unserem Blog-Modul.

Model View Controller

Unser Modulverzeichnis „blog“ hat einige Unterverzeichnisse bekommen, welche die Grundstruktur einer MVC-Anwendung widerspiegeln. Im „actions“-Verzeichnis liegt der Controller-Teil der Anwendung, während im „templates“-Verzeichnis die dazugehörigen Views untergebracht sind. Jeder Action muss ein Template zugeordnet werden, zum Beispiel findet die Controller-Funktion executeShow() im Template showSuccess.php ihre View. Durch diese Aufteilung werden Logik (Controller) und Präsentation (View) strikt voneinander getrennt. Während die jeweiligen Actions direkten Zugriff auf das Datenmodell haben, sind die Templates nur für die Anzeige zuständig.

Da unser Blog bisher noch sehr hässlich ist (wir haben uns bisher nur Standard-Ansichten von Symfony erzeugen lassen), müssen wir also an den Dateien im templates-Verzeichnis arbeiten. Zuerst werfen wir einen Blick auf die Datei showSuccess.php. Der Name verrät, dass diese Datei das Ergebnis der „show“-Action darstellen soll. Die „show“-Action selbst kann durch einen Rückgabewert bestimmen, welches Template zur Anzeige verwendet werden soll. In unserem Beispiel bleiben wir beim Standard und lassen alle Actions „Success“ ausgeben. Wer möchte, kann einer Action auf diese Weise beliebig viele Templates zuordnen: „showError.php“ etwa ist ein Template der Action „show“ und wird angezeigt, wenn die Action „Error“ zurückgibt. Die Verwendung von Camel-Case ist an dieser Stelle obligatorisch, sonst kann Symfony Action und Template nicht zueinander in Verbindung bringen.
Um das Konzept zu verstehen, werfen wir einen Blick in die Datei actions.class.php:

Anzeige
Anzeige
Ausschnitt: actions.class.php
public function executeIndex() {
 return $this->forward('blog', 'list'); }
public function executeList() {
 $this->blog_entrys = BlogEntryPeer::doSelect(new Criteria()); }

Listing 7

In diesem Code-Ausschnitt werden zwei Actions definiert: Index und List. Index ist immer die Default-Action eines Moduls und verweist in diesem Beispiel einfach weiter auf die List-Action. Die „forward“-Funktion erwartet als Parameter den Namen des Moduls und den Namen der Action innerhalb dieses Moduls, die angesprungen werden soll. In der List-Action wiederum wird die Member-Variable „blog_entrys“ unter Verwendung des ORM-Layers mit einer Liste von Blog-Einträgen befüllt. Symfony fügt bei Variablennamen, die eine Liste von mehreren Objekten beinhalten, automatisch ein Plural-s am Ende an (daher steht hier im automatisch erzeugten Code nicht „blog_entries“, sondern „blog_entrys“). Das statische Objekt BlogEntryPeer wird von Propel bereitgestellt, um die eigentlichen BlogEntry-Objekte zu verwalten. Dementsprechend wird hier auf dem Peer-Objekt die Funktion „doSelect“ aufgerufen, um eine Liste von blog_entry-Objekten zu erhalten. Bisher befüllt die Action also lediglich eine Member-Variable mit einer Liste. Alles weitere findet im Template listSuccess.php statt:

Ausschnitt: listSuccess.php
<?php foreach ($blog_entrys as $blog_entry): ?>
<tr>
 <td><?php echo link_to($blog_entry->getId(), 'blog/show?id='.$blog_entry->getId()) ?></td>
 <td><?php echo $blog_entry->getTitle() ?></td>
 <td><?php echo $blog_entry->getContent() ?></td>
 <td><?php echo $blog_entry->getDeleted() ?></td>
 <td><?php echo $blog_entry->getCreatedAt() ?></td>
 <td><?php echo $blog_entry->getUpdatedAt() ?></td>
 </tr>
<?php endforeach; ?>

Listing 8

Hier steht die oben gefüllte Member-Variable im globalen Scope zur Verfügung und kann einfach durchiteriert werden. Die „link_to“-Helper-Funktion erzeugt in der Ausgabe einen Link auf den jeweiligen Blog-Eintrag. In den über den Softlink verfügbaren Quellen zu diesem Tutorial haben wir die Tabelle aus dem obigen Template verbannt und die Gesamterscheinung mit CSS ansehnlicher gestaltet.

Sessionverwaltung und Authentifizierung

In unser Blog soll nicht jeder schreiben dürfen, sondern nur ein authentifizierter Benutzer, der über ein Passwort identifiziert wird. Dazu machen wir uns die Symfony-eigene Sessionverwaltung zu Nutze. Zuerst legen wir in der Konfigurationsdatei security.yml fest, welche Anwendungsteile geschützt werden sollen:

Anzeige
Anzeige
apps/frontend/blog/config/security.yml
show:
 is_secure: on
create:
 is_secure: on
edit:
 is_secure: on
update:
 is_secure: on
delete:
 is_secure: on

Listing 9

Jede einzelne Action des Moduls kann mit Sicherheitsmerkmalen versehen werden, in unserem einfachen Beispiel mit „is_secure“. Eine dermaßen geschützte Action wird nur ausgeführt, wenn ein User-Objekt vorhanden ist und der Benutzer den Status „isAuthenticated“ aufweist. Auf die User-Credentials kann in einem Template einfach zugegriffen werden:

Auschnitt: listSuccess.php
<?php if($sf_user->isAuthenticated()) echo link_to ('new entry', 'blog/create'); ?>

Listing 10

Die Benutzerauthentifizierung selbst passiert üblicherweise in einer Action, die Login und Passwort etwa mit einer Datenbank abgleicht.

Ausschnitt: action.class.php
$this->getUser()->setAuthenticated(true);

Listing 11

Fazit

Das Symfony-Projekt gehört trotz seines vergleichsweise jungen Alters zu den bestdokumentierten Open-Source-Projekten überhaupt. Die Website des Projekts bietet neben einem kompletten Handbuch auch komplexere Tutorials zum Download an. So oder so erfordert jedoch die Software-Entwicklung mit Symfony, dass man sich mit grundlegenden Prinzipien der objektorientierten Programmierung und der MVC-Architektur auseinandersetzt. Letztendlich sorgt Symfony durch seine klaren Strukturen dafür, dass der erzeugte Programmcode sauber und einfach wartbar ist.

Mehr zu diesem Thema
Fast fertig!

Bitte klicke auf den Link in der Bestätigungsmail, um deine Anmeldung abzuschließen.

Du willst noch weitere Infos zum Newsletter? Jetzt mehr erfahren

Anzeige
Anzeige
Schreib den ersten Kommentar!
Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.

Bitte schalte deinen Adblocker für t3n.de aus!
Hallo und herzlich willkommen bei t3n!

Bitte schalte deinen Adblocker für t3n.de aus, um diesen Artikel zu lesen.

Wir sind ein unabhängiger Publisher mit einem Team von mehr als 75 fantastischen Menschen, aber ohne riesigen Konzern im Rücken. Banner und ähnliche Werbemittel sind für unsere Finanzierung sehr wichtig.

Schon jetzt und im Namen der gesamten t3n-Crew: vielen Dank für deine Unterstützung! 🙌

Deine t3n-Crew

Anleitung zur Deaktivierung
Artikel merken

Bitte melde dich an, um diesen Artikel in deiner persönlichen Merkliste auf t3n zu speichern.

Jetzt registrieren und merken

Du hast schon einen t3n-Account? Hier anmelden

oder
Auf Mastodon teilen

Gib die URL deiner Mastodon-Instanz ein, um den Artikel zu teilen.

Anzeige
Anzeige