ZF2 – ein Cookbook

In 3 Schritten einen URL-Shortener mit dem neuen Zend Framework 2 bauen [Schritt 1]
Kommentare

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 Zhorty_TrimController. Dank Namespaces kann

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 Zhorty_TrimController. Dank Namespaces kann man das allerdings in ZF2 verkürzen auf TrimController. Natürlich muss der Namespace Zhorty gesetzt werden. Der Controller erbt auch nicht mehr von Zend_Controller_Action, sondern von AbstractActionController oder besser gesagt von ZendMvcControllerAbstractActionController. Und eine weitere Besonderheit der sonst leeren indexAction() fällt auf: Es gibt Return-Werte. Diese sind für die View gedacht. Das bedeutet, dass nichts einer View-Instanz zugewiesen werden muss. Das Framework macht genau das jetzt selbstständig über die Rückgabewerte. Diese können entweder ein assoziatives Array sein oder, wie in obigem Beispiel, eine Instanz von ViewModel. ViewModel bietet einige weitere Möglichkeiten mehr als das Zuweisen von Werten zum View-Objekt, z. B. auch das Angeben eines Nicht-Standard-View-Templates. Auch hier gilt wieder: mehr Flexibilität.

Das View-Template selbst wird natürlich auch noch benötigt. Also erstellen wir die Datei view/zhorty/trim/index.phtml mit Dummy-Inhalt.

Widmen wir uns wieder der Module.php. Die Klasse wird um eine Methode getAutoloaderConfig() erweitert. Wie bereits in der Skeleton-App beschrieben, wird ein Standard-Autoloader konfiguriert (Listing 3).

Listing 3

public function getAutoloaderConfig()
{
    return array(
        'ZendLoaderStandardAutoloader' => array(
            'namespaces' => array(
                __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
            ),
        ),
    );
}

Damit stellen wir sicher, dass unser TrimController auch gefunden wird. Dennoch müssen wir in der config/module.config.php konfigurieren, dass der Controller auch genutzt werden kann (Listing 4).

Listing 4

 array(
        'invokables' => array(
            'ZhortyControllerTrim' => 'ZhortyControllerTrimController'
        ),
    ), 
);

Das mag auf den ersten Blick wie unnötiger Mehraufwand erscheinen. Allerdings bedeutet es auch mehr Kontrolle über den Code. In ZF1 passierte diesbezüglich viel Magie: Klassen wurden volldynamisch geladen. Im ersten Schritt ist das sicherlich angenehm, im zweiten ist es aber auch wenig flexibel. Man musste es so nehmen, wie es kam. Das hat sich geändert: In der Config gibt es einen eigenen Abschnitt, der definiert, wie Klassen geladen werden. Dahinter steckt ein ServiceLocator (Kasten: „ServiceLocator vs. ServiceManager). Dieser positioniert sich irgendwo zwischen „selbst instanziieren“ und Dependency Injection. Vor allem ist er dafür verantwortlich, dass die Verwendung von Singletons obsolet wird. Obwohl Singletons vor einiger Zeit noch „the way to go“ waren, sind sie heute wegen der schwierigen Testbarkeit von Komponenten, die Singletons verwenden, zum Antipattern geworden. Der ServiceLocator ist also für das Liefern von Objekten verantwortlich. In der Regel sind es Objekte von Klassen, die nur einmal instanziiert werden sollen. Weiterhin macht der ServiceLocator Objektinstanzen global verfügbar. Außerdem können an unterschiedlichen Stellen diese Services beim ServiceLocator registriert werden. Unser erster Service wird der TrimController sein. Der ServiceLocator bietet verschiedene Wege an, wie ein Service registriert wird. Der einfachste ist, ihn als invokables zu definieren. Das bedeutet nichts anderes, als dass der ServiceLocator selbstständig ein „new ClassName“ macht. In unserem Beispiel: new ZhortyControllerTrimController. Das passiert natürlich erst dann, wenn die Klasse auch wirklich gebraucht wird. Der ServiceLocator speichert in diesem Fall dann auch die Objektinstanz zur Wiederverwendung unter dem Bezeichner ZhortyControllerTrim. Prinzipiell kann auch der Bezeichner frei gewählt werden. Als Best Practice hat sich jedoch eine ID, die dem Klassennamen entspricht, bewährt. Um das Aufrufen des TrimControllers kümmert sich die MVC-Implementierung des ZF2. Allerdings werden wir später den ServiceLocator selbst nutzen und auch sehen, wie wir Instanzen aus diesem herausholen.

ServiceLocator vs. ServiceManager

Etwas Verwirrung könnten diese beiden Namen stiften. Aus der Doku: „The ServiceLocator design pattern is implemented by the ServiceManager. The ServiceLocator is a service/object locator, tasked with retrieving other objects.“ [3]

Auch wenn in dem Artikel von ServiceLocator die Rede ist, eigentlich ist es ein ServiceManager-Objekt, das das Interface ServiceLocator implementiert.

Da wir gerade in der module.config.php arbeiten, können wir uns auch um das Routing kümmern. Auch hier war in ZF1 sehr viel Magie im Spiel, wenn es darum ging, den URL auf entsprechende Controller und Actions zu mappen. In ZF2 ist für das Routing zu Beginn ein wenig mehr Konfigurationsaufwand. Allerdings hat man auch viel mehr Kontrolle über das, was aufgerufen werden kann (Listing 5).

Listing 5

'router' => array(
    'routes' => array(
        'zhorty-trim' => array(
            'type' => 'ZendMvcRouterHttpLiteral',
            'options' => array(
                'route'    => '/trim',
                'defaults' => array(
                    'controller' => 'ZhortyControllerTrim',
                    'action'     => 'index',
                ),
            ),
        ),
    ),
),

Die Route selbst wird auch wieder in einem Array definiert. Sie muss auch einen Namen haben, der applikationsweit eindeutig sein soll, hier zhorty-trim. Der Name ist nur zur internen Verwendung, er hat keinen Einfluss darauf, über welchen URL ein Controller und eine Action aufgerufen werden. Als Router-Typ geben wir Literal an. Literal, weil wir nur dann einen RouteMatch haben wollen, wenn die Route exakt zutrifft. Einen so genannten RouteMatch haben wir, wenn der URL auf den Wert „route“ in den options passt. Hier ganz einfach ,/trim‘. Des Weiteren definieren wir die Defaults, also den Controller und die Action, die aufgerufen werden soll, wenn wir einen Match haben. Achtung: Der Controller ist nicht der Klassenname, sondern der Bezeichner, unter dem die Klasse im ServiceLocator registriert wurde (s. o.).

Zu guter Letzt weiß unser Modul noch nicht, unter welchem Basispfad die Views zu finden sind. Diese kann ebenfalls in der Konfiguration module.config.php eingetragen werden:

'view_manager' => array(
    'template_path_stack' => array(
        __DIR__ . '/../view',
    ),
), 

Da wir einen so genannten template_path_stack angeben, können wir erahnen, dass es über diesen Weg auch möglich ist, weitere Pfade anzugeben, in denen View Templates gefunden werden können.

Eine wichtige Kleinigkeit fehlt noch: In der Applikationskonfiguration config/application.config.php muss eingetragen werden, dass das Modul Zhorty aktiv ist:

'modules' => array(
    'Application',
    'Zhorty',
),

Als Nächstes kann getestet werden, ob unter dem URL http://zhorty.dev/trim auch wirklich unser Dummy-Text angezeigt wird.

Zugegeben: Für ein einfaches „Hello World“ ist das alles zu viel Aufwand. Aber ein „Hello World“ ist natürlich auch nicht der Maßstab für die Verwendung eines Frameworks. Es sollte klar geworden sein, dass man durch den etwas höheren Konfigurationsaufwand einiges an Flexibilität gewinnt. Sollen die View Teplates z. B. an anderer Stelle liegen, ist das kein Problem (siehe template_stack_path). Möchten wir eine andere Route auf den TrimController matchen, bedeutet das nur eine Anpassung in der config. Insgesamt wird man nicht mehr so bevormundet wie in ZF1. Dennoch gibt es klare Strukturvorgaben. Diese Ordnung orientiert sich an der Skeleton-Applikation, und die ist nach Matthew Weier O’Phinney (ZF-Projektleiter) das Maß aller Dinge. Hier werden die Best Practices im Umgang mit ZF2 aufgezeigt und auch zukünftig gepflegt.

Im November 2006 startete Jan Burkl als Training & System Engineer bei Zend Technologies in Stuttgart. Heute berät der studierte Informatiker als Senior Solution Consultant für Zend-Geschäftskunden in PHP-Softwareprojekten und ist verantwortlich für deutschsprachige Webinare und Konferenzbeiträge von Zend. Sie möchten auch eine Einladung zu phpcloud.com? Schreiben Sie eine E-Mail an jan@zend.com.
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -