© DrHitch/Shutterstock.com
Zend Framework 2

3 Einen URL-Shortener mit dem neuen Zend Framework 2 bauen


Mit dem neuen Zend Framework hat sich doch einiges geändert. Grund genug, in diesem Cookbook zu beschreiben, wie mit ZF2 losgelegt werden kann. Als Beispielapplikation möchte ich einen einfachen URL-Shortener à la bit.ly implementieren. Der Funktionsumfang ist überschaubar, dennoch gibt es so einige spannende Punkte, die sehr elegant mit dem ZF2 gemeistert werden können. In diesem Kapitel werden zwar immer wieder Verweise auf die erste Version des Zend Frameworks zu finden sein, aber auch für ZF-Neulinge sollte das Nachimplementieren kein Problem darstellen.

Was ist der Use Case? Anstatt eines langen, beliebigen URL möchte ich nur einen kurzen Text, der an den Host-Namen gehängt wird, eingeben. Ein Beispiel: Wenn ich auf ein bestimmtes Webinar auf der Zend-Seite verknüpfen möchte, könnte der entsprechende URL wie folgt aussehen: http://www.zend.com/de/resources/webinars/php-and-cloud#PDitC. Schöner wäre es, einen kurzen Link zend.com/cloud zu verwenden. Der Pfad /cloud soll natürlich frei gewählt werden können und das Verhalten des CMS nicht verändert werden. Also brauchen wir ein Formular mit zwei Feldern (original_uri und der trim_path) zur Eingabe. Diese Werte sollten auch in einer Datenbank gespeichert werden können. Der Einfachheit halber nutzen wir SQLite. Eine Liste aller eingetragenen URLs wäre nicht schlecht, genauso wie die Möglichkeit, einzelne Einträge wieder zu löschen. Und natürlich der Redirect-Mechanismus der neuen, „virtuellen“ Pfade. Unsere App nennen wir Zhorty.

Installation und Skeleton-App

Bevor wir mit der Businesslogik von Zhorty beginnen können, müssen wir noch einige Kleinigkeit vorbereiten – im Wesentlichen brauchen wir natürlich auch den Zend-Framework-2-Code.

Zum einen brauchen wir den ZF2-Code, zum anderen möchte ich mit der offiziellen Skeleton-App arbeiten. Die eigene Applikation auf der Skeleton-App aufzusetzen, ist der empfohlene Weg, mit neuen Projekten im ZF2 zu starten. ZF2 kann man in der aktuellen Version unter [1] herunterladen. Die Skeleton-App liegt auf GitHub und wird als ZIP-Paket unter [2] bereitgestellt. Jetzt wird der eine oder andere denken: „Warum Download? Ich dachte, ZF unterstützt Composer und Pyrus?“. Das ist richtig. ZF2 stellt verschiedene Möglichkeiten bereit, ein Projekt anzulegen. Darunter auch das mittlerweile populäre Composer. Jedoch ist das auch eine Komponente, die vielleicht manch einem noch nicht geläufig ist und somit eine zusätzliche Hürde bei der Installation darstellen würde. Aus diesem Grund werden wir das Setup manuell durchführen. Und bei der Größe dieses Projekts ist dieser Aufwand auch überschaubar. Also, Skeleton-App und ZF2 herunterladen und entpacken. Die Skeleton-App könnte z. B. unter Linux im Pfad /var/www landen. Als Nächstes sollte der Webserver entsprechend konfiguriert werden. Hier gibt es selbstverständlich sehr viele Möglichkeiten, dies umzusetzen, abhängig von IDE, Betriebssystem und natürlich auch vom Webserver selbst. Ich selbst arbeite in der Regel mit einem Ubuntu-System, welches in einer virtuellen Maschine auf einem Windows-Host-System läuft. Über das „Shared Folder“-Feature mounte ich auf dem Linux-Gast-System den Ordner der Skeleton-App vom Windows Host. Als Webserver wird Apache verwendet, der idealerweise einen VirtualHost, der z. B. auf den Servernamen „zhorty.dev“ hört, so einsetzt, dass der DocumentRoot auf das public-Verzeichnis der Skeleton-App zeigt. Diese Anleitung ist mit Absicht sehr knapp gehalten, da die beschriebene Vorgehensweise keine Grundvoraussetzung für die Entwicklung mit ZF2 ist. Prinzipiell ist das initale Setup für ZF2 genau wie für ZF1. Bitte auch beachten, dass der Virtual Host das Auslesen der .htaccess-Datei unterstützt.

Die Skeleton-App weiß zu diesem Zeitpunkt noch nichts von ZF2. Das lässt sich ändern, indem das library-Verzeichnis des entpackten ZF2 in den vendor/ZF2-Ordner der Skeleton-App gelegt wird. Das vendor-Verzeichnis ist neu gegenüber ZF1 und prinzipiell für alle Librarys (auch Third-Party-Libraries) bzw. Module gedacht, die von der eigentlichen Applikation genutzt werden sollen. So auch der ZF2 Core.

ZF2 Workflow

Das war es schon für die Skeleton-App. Jetzt kann im Browser getestet werden, ob auch alles funktioniert hat (Abb. 3.1). Sieht alles schon ganz gut aus – das liegt mitunter an dem verwendeten Twitter Bootstrap Style, der standardmäßig für das Layout verwendet wird.

burkl_zf2_1.png

Abbildung 3.1: ZF2 Skeleton-App-Startseite

Aber was ist genau passiert? Schauen wir uns den Workflow etwas näher an. Die .htaccess-Datei sorgt dafür, dass jeder Request auf die index.php geroutet wird. Sie ist sehr leichtgewichtig. Als Erstes wird die init_autoloader.php inkludiert. Sie prüft, ob es den Pfad vendor/ZF2/library gibt bzw. dass dieser Ordner existiert. Dafür haben wir weiter oben gesorgt. Daher wird der StandardAutoloader registriert, der dafür sorgt, dass alle Klassen des ZF2 ohne require geladen werden. Wie beschrieben, ist das allerdings nicht der einzige Weg, das ZF2 einzubinden. Sehr einfach geht es zum Beispiel auch, wenn eine Environment-Variable ZF2_PATH in der Serverkonfiguration gesetzt wird. Natürlich kann die init_autoload.php nach Einsatzzweck frei gestaltet werden, der oben beschriebene Weg ist allerdings für den Anfang der schnellste.

Nach dem Setup des Autoloaders wird die Applikation initialisiert (Zend\Mvc\Application::init()). Als Parameter wird die Applikationskonfiguration als Array übergeben. Hier sehen wir auch direkt eine Besonderheit gegenüber ZF1: In der Vorgängerversion wurde primär mit ini-Konfigurationsdateien gearbeitet. Aus Performancegründen geht man wieder „back to the roots“: Assoziative Arrays sind schneller, da sie nicht erst in eine PHP-Struktur überführt werden müssen, und wirklich unleserlicher als ini-Dateien sind sie auch nicht. Das Konfigurations-Array wird auch nicht in einer Variablen gespeichert, sondern einfach mittels return zurückgegeben. Sehr pragmatisch. Dem Inhalt der Applikationskonfiguration werden wir uns später widmen.

Im Inneren der init()-Methode passiert jetzt natürlich eine Menge: Im Wesentlichen werden alle registrierten Module vorbereitet. Modul? Das gab es doch auch schon in ZF1. Korrekt, allerdings haben Module in ZF2 eine viel zentralere Bedeutung (Kasten: „Module“). Genauer gesagt: Ohne Modul geht gar nichts.

Module: „Zend Framework 2.0 introduces a new and powerful approach to modules. This new module system is designed with flexibility, simplicity, and re-usability in mind. A module may contain just about anything: PHP code, including MVC functionality; library code; view scripts; and/or public assets such as images, CSS, and JavaScript. The possibilities are endless.“ [3]
Gerade die einfache Wiederverendung ist ein riesiger Vorteil von Modulen. Unter [4] finden sich schon einige nützliche Module zur Verwendung in der eigenen Applikation, z. B. eine Userverwaltung oder Doctrine-Verknüpfung.

Natürlich besteht auch die Skeleton-App aus einem Modul, dieses heißt Application. Dieser Name ist prinzipiell frei gewählt, allerdings ist die Bezeichnung als zentraler Einstiegspunkt für eine Applikation auch ganz passend. Ein entsprechendes Verzeichnis finden wir im modules-Ordner der Skeleton-App. Die Grundidee eines Moduls ist dessen Autarkie. Im Wesentlichen sollte es möglich sein, ein Modul in jeder anderen Applikation unverändert nutzen zu können.

Besagtes Modul Application wird geladen, da in der Applikationskonfiguration config/application.php ein Eintrag modules' => array('Application') zu finden ist. Jedes Modul hat einen zentralen Einstiegspunkt: Module.php. Vergleichbar ist diese Datei vielleicht mit der Bootstrap.php aus ZF1 – allerdings ist die interne Verwendung doch grundverschieden. In der Datei Module.php wird eine Klasse Application\Module definiert. Diese Klasse hat eine Methode getConfig(), die, nun ja, ein Konfigurations-Array zurückgibt. Diese Methode wird automatisch von der internen MVC-Implementierung aufgerufen. In der Regel wird ein eigenes Konfigurationsfile erstellt. Hier ist es config/module.config.php. Analog zur Applikationskonfiguration wird auch in dieser Datei lediglich ein assoziatives Array zurückgegeben. Werfen wir einen kurzen Blick in die Konfiguration: Am Anfang mag die Konfiguration sehr komplex erscheinen, das ist alles halb so wild. Im Laufe des Kapitels wird noch Licht ins Dunkle gebracht. Kurz reingeschaut sehen wir aber solche Sachen wie Routing, Controller Definition, die View, einen Translator und manches mehr. Das lässt schon erahnen, dass das ZF2 sehr viel an Flexibilität dazugewonnen hat, wenn auch etwas mehr Konfigurationsaufwand notwendig geworden ist.

Zurück zur Klasse Module\Application. Da Module so aufgebaut werden, dass sie selbstständig arbeiten können, kann und sollte ein eigener Autoloader bzw. dessen Konfiguration implementiert werden. Dies geschieht in der Methode getAutoloaderConfig():

return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);

Der hier definierte Autolader ist ein so genannter StandardAutoloader, der über den Namespace definiert wird – in diesem Fall ist der Namespace Application. Dieser Namespace wird auch als interner Bezeichner für den Autoloader genutzt, deshalb der Array-Key __NAMESPACE__. Der Value bezeichnet den Basispfad für alle Dateien, die über den Autoloader gefunden werden sollen. Die Verwendung von __DIR__ stellt sicher, dass, egal wo dieses Modul eingesetzt wird, der korrekte, absolute Pfad zum Modul genutzt wird. Der Ordnername src ist – wie man an der Definition sieht – frei gewählt, hat sich aber auch als Best Practice herausgestellt. In dem besagten Ordner src bzw. src/Application (oder auch 'src/' . __NAMESPACE__) spielt sich das eigentliche Leben des Moduls ab. Hier befinden sich z. B. die Controller und die Models. Der Ordnername Application mag zu Anfang ungewöhnlich erscheinen, da wir uns ja im Modul Application befinden, ist aber dem einfacheren Umgang mit dem Namespace und den Autoloadern geschuldet. Andererseits spricht nichts dagegen, Application umzubenennen oder weitere Verzeichnisse in den src-Ordner zu stecken, eine entsprechende Konfiguration der Autoloader vorausgesetzt.

Die Controller wurden weiter oben bereits erwähnt. Diese kommen auch dem ZF1-Entwickler sehr bekannt vor. Der Controller hat weiterhin diverse action-Methoden, und die Views sind im Wesentlichen phtml-Dateien. Auch die Ordnerstruktur der View Templates ist analog zum dem aus ZF1, allerdings nicht (standardmäßig) im src-Ordner, sondern in einem eigenen Verzeichnis view auf gleicher Ebene wir src. Die Organisation der View Templates ist analog der aus ZF1, sprich view/<module_name>/<controller_name>/<action_name>.phtml. Hierbei ist – wie auch im ZF1 – unbedingt darauf zu achten, dass der Pfad inklusive <moduel_name> und <controller_name> komplett klein geschrieben wird.

Modul Zhorty

Jetzt wird es Zeit, das eigene Modul Zhorty zu entwickeln. Los geht’s mit einem neuen Verzeichnis module/Zhorty. Darin erstellen wir Verzeichnisse config, src und view. Des Weiteren wird die Basisdatei Module.php mit der Klasse Zhorty/Module benötigt, die die Module-Konfiguration ausliest (Listing 3.1).

<?php
namespace Zhorty;

class Module
{
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
}

Listing 3.1

Die Konfiguration selbst, also die Datei config/module.config.php, sollte erstellt werden, kann zu Beginn aber einfach ein leeres Array zurückgeben:

<?php
return array();

Jetzt geht es schon ans Eingemachte: Unser erster Controller Zhorty\TrimController kommt in die Datei src/Zhorty/Controller/TrimController.php (Listing 3.2).

<?php
namespace Zhorty\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class TrimController extends AbstractActionController
{
public function indexAction()
{
return new ViewModel();
}
}

Listing 3.2

Der TrimController wird alles Nötige zum Trimmen des URL bereitstellen. Der Klassenname des Controllers wäre in ZF1 auf Grund der Verwendung in einem Modul ...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang