Die Webanwendung DailyBusiness auf dem PHP-Framework Symfony, Teil 1

Die Webanwendung DailyBusiness auf dem PHP-Framework Symfony, Teil 1

Meine Begeisterung für das PHP-Framework Symfony ist ungebrochen. Die Lektüre des Getting Started-Dokuments war im ersten Durchlauf zwar noch nicht sehr aufschlussreich, aber inzwischen habe ich die wichtigsten Kapitel des sehr viel ausführlicheren The Symfony Book durch: die Kapitel über Controller, das Routing, Templating mit twig, Datenbankmapping mit Doctrine und die Erstellung von Formularen. Mich begeistert ehrlicherweise nicht nur das PHP-Framework selbst, sondern auch die Qualität der frei verfügbaren Dokumentation. Neben den bereits angesprochenen Dokumenten gibt es noch zahlreiche weitere Dokumente, wie z.B. das Symfony Cookbook, in dem konkrete Anforderungen und ihre Umsetzung besprochen werden.

Die Erkenntnisse aus der Lektüre von The Symfony Book habe ich parallel in einer eigenen kleinen Anwendung umgesetzt, eine Art einfache Fallstudie, bei der ich die gängigsten Anforderungen einer Webanwendung mit Symfony umsetzen möchte. Die Anwendung soll DailyBusiness heißen und eine Art Todo-Liste für meine täglichen Aufgaben darstellen. Die Anwendung soll später auf einem Server laufen, so dass ich auf meine Todo’s von überall her zugreifen und diese pflegen kann.

Worum soll es in diesem kleinen Symfony-Tutorial gehen?

Die Erstellung dieser kleinen Webanwendung, die mir zur eigenen Einarbeitung in das Framework Symfony dient, dokumentiere ich mit dieser mehrteiligen Beitragsserie hier auf meinem Blog. In diesem ersten Teil geht es um folgende Themen:

  • Das PHP-Framework Symfony installieren und einrichten
  • Organisation eines Projekts mit Bundles und Namespaces
  • Einen ersten Controller einrichten
  • Eine Route für diesen Controller einrichten
  • Eine erste View auf Basis eines twig-Templates erstellen

Wie startet man mit dem PHP-Framework Symfony?

Als erstes zieht man sich den Symfony Installer symfony.phar in ein eigenes Verzeichnis und führt ihn über die Kommandozeile aus. Der Installationsprozess ist für die verschiedenen Betriebssysteme auf symfony.com ausführlich beschrieben. Ich nutze dabei die aktuelle Version Symfony 2.6, meine Entwicklungsumgebung läuft auf Windows 7 und bei PHP nutze ich die Version 5.5.11.

c:\> php -r "readfile('http://symfony.com/installer');" > symfony.phar
c:\> php symfony.phar

Sind diese Schritte durchgeführt, legt man mit folgendem Befehl sein erstes Projekt an:

c:\> php symfony.phar new myproject

Nun erstellt Symfony die Struktur des Frameworks, in dem man die zukünftige Webanwendung erstellen wird.

  • /app: Im /app-Ordner liegen die Verzeichnisse und Dateien für den Cache, die Konfigurationsdateien, Logfiles und Ressourcen wie Templates für die Standard-Views.
  • /bin: Dieses Verzeichnis scheint erst mal nicht wichtig zu sein, da liegt nicht viel drin.
  • /src: Das Verzeichnis, in dem wir uns vermutlich am meisten aufhalten werden, denn dort ist der Ort für den eigenen Code, in sogenannten Bundles organisiert.
  • /vendor: Im Verzeichnis /vendor liegen Bundles von Symfony selbst, aber auch von Drittanbietern wie das Bundle Doctrine, welches für das Mapping von Objekten auf Tabellen relationaler Datenbanken zuständig ist.
  • /web: Das Verzeichnis /web ist der Einstiegspunkt (root) der Webanwendung mit dem eigentlichen Frontend-Controllern (z.B. app.php und app_dev.php).

Wie im Beitrag Die Qual der Wahl bei der Suche nach einem PHP-Framework beschrieben, fand ich die Idee, den über Symfony mitgelieferten PHP-Webserver zu nutzen erst etwas befremdlich. Letztlich bietet dieser aber zahlreiche kleine Helferlein, um den Entwicklungsprozess mit Symfony zu unterstützen. Diese Hilfsmittel habe ich inzwischen sehr zu schätzen gelernt. Wie dann das Deployment der Anwendung auf dem Server meines Providers aussehen wird, wird sich noch zeigen und wird Thema eines späteres Beitrags.

Symfony Startseite nach der Installation

Symfony Startseite nach der Installation

Hat mit der Installation von Symfony alles geklappt und startet man den mitgelieferten PHP-Server aus dem neu erstellten Projektverzeichnis heraus, sollte man die Startseite des Frameworks sehen. In meinem Fall scheinen die eingebundenen Stylesheets aber nicht gefunden zu werden. Die Startseite sollte eigentlich etwas schöner aussehen. Ich habe den Fehler allerdings nicht weiter nachverfolgt, da ansonsten alles reibungslos funktioniert.

Wie organisiert man nun die eigene Symfony-Anwendung?

Es gibt zwei Möglichkeiten: entweder man arbeitet im Bundle AppBundle und passt dort die bestehenden Dateien an und erweitert dieses Verzeichnis um weitere Routen, Controller, Entitäten oder andere Ressourcen. Die andere Möglichkeit besteht darin, ein eigenes Bundle anzulegen. Dieser Weg bietet sich an, wenn man seine Anwendung als eigene Einheit kapseln möchte und später tatsächlich einmal ausliefern möchte.

Für meine kleine Anwendung DailyBusiness habe ich den zweiten Weg gewählt, also ein eigenes Bundle kreiert, obwohl das für meine Bedürfnisse eigentlich völlig unnötig ist. Im ersten Moment erschien mir dieser Weg sinnvoller, um meinen Quellcode in einem eigenen Bundle zu organisieren. In diesem Fall muss man aber einige Dinge hinsichtlich des Namespaces beachten, z.B. wie man Objekte oder Ressourcen adressiert.

Ein Bundle legt man wieder über die Konsole an, in meinem Fall mit:

$ php app/console generate:bundle –namespace=vc/DailyBusinessBundle

Damit wird nun im Verzeichnis vc/dailybusinessbundle im /src-Ordner eine Struktur mein eigenes Bundle angelegt, in welches ich dann meine Webanwendung anlegen werde. vc steht dabei für VirtualCommerce, also mein eigener Namensraum, den ich später für weitere Bundles nutzen möchte.

Es gibt zahllose weitere Optionen für den generate:bundle-Befehl wie z.B. –format=yml, mit dem man dem Generator über die Console mitteilt, in welchem Format man seine Anwendung konfigurieren möchte. Neben dem YAML-Format, wie in diesem Fall, stehen unter anderem noch PHP und XML zur Verfügung. Die Ausführung dieses Befehls registriert nun das eigene Bundle in der Datei app/AppKernel.php, in der nun diese zusätzliche Zeile zu finden ist:

// app/AppKernel.php
public function registerBundles()
{
    $bundles = array(
        // ...
        new vc\DailyBusinessBundle\DailyBusinessBundle(),
    );
    // ...

    return $bundles;
}

Aber wie soll die Anwendung DailyBusiness nun aussehen?

Es soll ja ein webbasiertes Tool werden, mit dem ich meine täglichen Aufgaben (= Task) verwalten möchte. Die Aufgaben sollen nach Thema (= Topic) geordnet werden. Für eine erste Version genügt es außerdem, dass die Aufgaben einen Status (= Status) haben und priorisiert (= Priority) werden können. Später sollen die Themen außerdem noch einem Kunden zugeordnet werden können.

Klassenmodell Dailybusiness

Das Klassenmodell der Anwendung DailyBusiness (mit argouml erstellt)

Aber für diesen ersten Beitrag soll es genügen, für die Anwendung eine erste Route anzulegen und statt der Welcome-Seite des mitgelieferten DemoBundles (Acme/DemoBundle) über einen neuen Controller eine eigene Startseite anzuzeigen. Diese Startseite soll bereits mit der Template-Engine twig erzeugt werden. Dem Anlegen der oben beschriebenen Objekte sowie deren Abbildung in einer relationalen Datenbank widme ich dann einen späteren Beitrag.

Die Route für eine Startseite anpassen

Möchten wir die Route auf eine eigene Startseite ändern, müssen wir die bestehende Route auf den WelcomeController des Acme\DemoBundles ändern. Da wir dieses mitgelieferte Demo-Paket eh‘ nicht benötigen, können wir dieses ganz rausnehmen. Dazu kommentieren wir die Regstrierung dieses Bundles in der Datei app/AppKernel.php einfach aus:

//new Acme\DemoBundle\DemoBundle(),

Weiterhin kommentieren wir den Verweise in der zentralen Routing-Datei app/config/routing.yml aus. Damit steht diese Resource nicht mehr zur Verfügung:

# app/config/routing.yml
#acme_website:
#    resource: "@AcmeDemoBundle/Resources/config/routing.yml"
#    prefix:   /

Im Gegenzug verweise ich für das Routing auf meine eigene Ressourcen, d.h. ich verweise auf die Controller im Verzeichnis /src/vc/DailyBusiness/Controller.

vc_daily_business:
    resource: "@vcDailyBusinessBundle/Controller/"
    type:     annotation

Als Type nutze ich nun Annotationen, d.h. die eigentlichen Routen definiere ich wie in The Symfony Book beschrieben direkt in meinen Controller-Klassen. Dort werden die Routen als Annotation direkt über den Actions eingebunden. Dazu muss allerdings ein zusätzliches Bundle use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; im Controller eingebunden werden, schauen wir uns also den Controller an.

Einen eigenen Controller mit indexAction anlegen

Ich lege nun den Controller an, der den Einstieg in meine Webanwendung bilden soll: /src/vc/DailyBusinessBundle/Controller/MainController.php. Dort definiere ich eine indexAction(), bestimme also die Aktion, die mein Controller ausführen soll, wenn ich den Request an den Server http://localhost:8000/ sende und eine Antwort (= Response) erwarte, in diesem Fall die zukünftige Startseite der Anwendung.

// src/vc/DailyBusinessBundle/Controller/MainController.php
namespace vc\DailyBusinessBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class MainController extends Controller
{
    /**
     * @Route("/")
     */
    public function indexAction()
    {
        return new Response(
            '<html><body><h1>Hello DailyBusiness</h1></body></html>'
        );
    }
}

Um nun die Route zu diesem Controller und zur indexAction() zu definieren, verwende ich die bereits angesprochenen Annotationen: @Route(„/“). Um zu überpüfen, ob diese Route korrekt eingetragen wurde und auch genutzt werden kann, nutze ich einen weiteren Befehl, den ich über die Console ausführe:

php app/console debug:router

Als Ausgabe erscheint nun unter anderem die über meine Annotation erzeugte Route auf die indexAction() des MainControllers:
vc_daily_business_main_index.
Um Annotationen nutzen zu können, muss wie schon erwähnt ein zusätzliches Bundle im Controller eingebunden sein:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

Starten wir den Server der Entwicklungsumgebung über die Console mit:

php app/console server:run

Sollten wir im browser über die Adresse http://localhost:8000/ bereits die Startseite mit dem Header Hello DailyBusiness angezeigt bekommen.

Eine Antwort (= Response) mit twig-Template erzeugen

Aber ich wollte die Anzeige der Startseite noch an ein twig-Template delegieren. Dazu nutzen wir die render-Funktion des Controllers. Da ich die Controller-Klasse mit extends von einem bereits bestehenden Controller-Objekt ableite, steht mir diese Funktion zur Verfügung. Außerdem packe ich meinen Header in die Variable $title und übergebe sie dem twig-Template.

public function indexAction()
{
    $title ='Hello DailyBusiness';
    return $this->render('vcDailyBusinessBundle:Main:index.html.twig', array('title'=>$title));
}

Um das von mir entworfene Template index.html.twig zu nutzen, muss ich über meinen Namensraum adressieren: Bundle:Action:Template, denn sonst sucht Symfony die entsprechende Ressource im Verzeichnis /app/Resources/views und nicht in meinem Bundle.

{# src/vc/DailyBusinessBundle/Resources/views/Main/index.html.twig #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% block body %}
<div id="header">
	<h1>{{ title }}</h1>
<div>
<div id="content">
	<p>Anzeige über twig-Template</p>
<div>
</body>
</html>

Auf die Variable $title, die ich mit der render-Funktion des Controllers dem Template übergeben habe, kann ich nun via {{ title }} zugreifen und so den Wert in die Seite einbinden. Das Ergebnis sieht nun so aus:

Die eigene Startseite mit einem twig-Template

Die eigene Startseite mit einem twig-Template


Screenshot Startseite

Zusammenfassung

Das war’s erst mal mit dem ersten Teil meines kleinen Symfony-Tutorials. Da ich mich zur Zeit in Symfony einarbeite, dient mir ein solcher Beitrag zur eigenen Dokumentation meiner Arbeit. Ich hoffe, dass mir dabei keine Fehler unterlaufen sind. Über Anregungen und Anmerkungen wie z.B. alternative Vorgehensweisen bin ich sehr dankbar.

Im zweiten Teil dieser Serie soll es darum gehen, ein Objekt Task anzulegen, dieses via dem OR-Mapper Doctrine in eine Datenbank zu speichern und eine Liste mehrerer solcher Tasks auf der Startseite anzuzeigen. Außerdem sollen diese Task-Objekte einzeln angezeigt, bearbeitet und auch wieder gelöscht werden können.

Weitere Beiträge zum PHP-Framework Symfony

Allgemeine Lesetipps über PHP-Frameworks (Partnerlink):

1 Kommentar

  1. Nettes Tutorial, ich hoffe das bald ein weiterer Teil erscheint :-).

    Eine kleine Anmerkung habe ich allerdings, im UML-Klassendiagramm sind sämtliche Assoziationen falsch herum eingetragen. Bsp.: Topic zu Task soll doch 1:n sein. Was Du angegeben hast ist aber n:1 :-)

    P.S. weiter so!

    Antworten

Trackbacks/Pingbacks

  1. Die Qual der Wahl bei der Suche nach einem PHP Framework | virtual-commerce.de - […] Die Webanwendung DailyBusiness auf dem PHP-Framework Symfony, Teil 1 […]

Kommentar absenden

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *