Kapitel 5. Ein gar nicht so simples "Hallo Welt"-Tutorial

Inhaltsverzeichnis

5.1. Einleitung
5.2. Schritt 1: Eine neue lokale Domain erstellen
5.3. Schritt 2: Die Projektverzeichnisstruktur erstellen
5.4. Schritt 3: Application-Bootstrapping implementieren
5.5. Schritt 4: Der einzige Weg hinein: die Index-Datei
5.6. Schritt 5: Standard-Controller und -View hinzufügen
5.7. Fazit

5.1. Einleitung

Es ist zu einer Tradition in Programmierbüchern geworden, das allereinfachste Beispiel vorzustellen, egal welche Programmiersprache, welches Framework oder welche Bibliothek behandelt wird. Üblicherweise heißt das, dass gerade genug getan wird, um "Hallo Welt" auf dem Bildschirm auszugeben, damit man die grundlegende Funktionsweise kennenlernen kann. Das ist für Frameworks nicht gerade das realistischste Beispiel, aber es ist genau so ein guter Startpunkt wie jeder andere auch!

5.2. Schritt 1: Eine neue lokale Domain erstellen

Bevor wir uns auf den Quelltext stürzen, sei allgemein empfohlen, bei der Entwicklung eine Umgebung zu verwenden, die der Produktionsumgebung möglichst nahe kommt. Ich werde in diesem Buch Anwendungen zumeinst innerhalb des "Document Root" des Webservers und nicht in einem Unterverzeichnis entwickeln. Sie können ein Unterverzeichnis verwenden, aber das wird etwas mehr Arbeit erfordern, wenn URI-Referenzen innerhalb der Anwendung angelegt werden - darauf gehe ich später genauer ein.

Fürs erste werfen Sie einen Blick in Anhang A: Eine lokale Domain mittels Apache Virtual Hosts erstellen, der erklärt, wie Sie für dieses Beispiel eine lokale Domain mit einem eigenen Document Root anlegen. Mit dieser Domain und einem Apache Virtual Host können wir das Beispiel auf unserem Entwicklungssystem von der Domain http://helloworld.tld aus ausliefern.

5.3. Schritt 2: Die Projektverzeichnisstruktur erstellen

Als nächster Punkt auf unserer Liste steht die Verzeichnisstruktur des Beispielprojekts. Zuerst legen Sie ein neues Verzeichnis an, das (ausgenommen das führende Unterverzeichnis /public) dem Pfad entspricht, das Sie vorher als Document Root für den helloworld-Virtual-Host angegeben haben. Hier werden alle unsere Projektdateien gespeichert. Unter Ubuntu könnte ich also das Verzeichnis in /home/padraic/www/helloworld erstellen oder unter Windows in C:\projects\helloworld.

Es gibt immer zahlreiche Diskussionen darum, wie die Verzeichnisstruktur aussehen soll, aber vieles davon wird jetzt unter der Führung von Ralph Schindler durch die laufenden Bemühungen rund um Zend_Tool formalisiert. Daraus wird ein stabiles, vollständiges Kommandozeilen-Werkzeug zum Erzeugen und Manipulieren von Projekten entstehen. Solange es nicht richtig stabil und dokumentiert ist, werden wir es hier nicht verwenden, also ist etwas Routinearbeit nötig, um die Verzeichnisstruktur von Hand anzulegen.

Verzeichnisstruktur der Anwendung

Das ist mein Vorschlag für die Verzeichnisstruktur. Sie ist aber keinesfalls verpflichtend - Sie können sie ganz Ihren Wünschen und anderen Anwendungen entsprechend anpassen. Für unser Beispiel brauchen wir zum Start nur einen Teil dieser Struktur.

Wie Sie sehen können, wird der gesamte Quelltext für Controller und Views im Verzeichnis /application abgelegt. Controllers und Views haben frameworkspezifische Konventionen, was das Laden anbelangt; daher macht es Sinn, dieser Konvention zu folgen. Hier speichern wir auch Module, die eigentlich eigenständige Sammlungen von Controllern und Views sind (und optional Models sowie anwendungsspezifische, nicht wiederverwendbare Helfer). Von der Dokumentation sind Sie vielleicht gewohnt, hier ein Verzeichnis /application/models zu sehen. Ich verwende ein solches momentan nicht, da Models so unglaublich vielseitig in ihrer Implementierung sind, dass eine einzelne, eindeutige Ladekonvention für Models nicht existiert. Deswegen behandle ich Models als Teil meiner allgemeinen Anwendungsbibliothek, /library, gemeinsam mit anderen für diese Anwendung spezifischen Klassen. Es ist aber trotzdem möglich, Models in /application/models abzuspeichern. Sie ziehen es vielleicht vor, Models an einem spezifischer benannten Ort zu speichern, aber denken Sie daran, dass jedes weitere Verzeichnis zum Speichern von Quelltext einen weiteren Eintrag in Ihrem include_path verlangen könnte. Später in diesem Buch werden wir mit Models arbeiten, die so wie im Referenzhandbuch beschrieben abgespeichert werden, da es uns die Einführung von Zend_Loader_Autoload ermöglicht, in dieser Hinsicht flexibler zu sein.

Alles andere existiert auf der übergeordneten Verzeichnisebene. Der ganze zukünftige Anwendungscode außerhalb von Controllern, Views und nicht wiederverwendbaren Klassen wird entweder im Verzeichnis /library oder /vendor abgelegt. Im Verzeichnis library speichere ich alle allgemeinen Klassen, die in dieser Anwendung verwendet werden. Das Verzeichnis vendor ist allgemein für nicht-spezifische Klassen oder Third-Party-Bibilotheken da, die ich verwenden möchte. Die Unterscheidung zwischen diesen beiden ist rein willkürlich - ich trenne einfach gerne meine eigenen Klassen und Bibliotheken von Dritten. Ich lege auch Zend Framework dort ab, falls es nicht bereits an einer zentraleren Stelle des Servers abgelegt wurde und über include_path erreichbar ist.

Die restlichen Verzeichnisse bergen keine Geheimnisse. Das Verzeichnis "config" beinhaltet die Konfigurationsdateien. Nach jüngsten Tendenzen könnte es auch unter /application/configs zu finden sein. Im Verzeichnis "data" können Daten in Dateien abgespeichert werden, zum Beispiel Caches oder andere Informationen. Das Verzeichnis public enthält alle Dateien, die für einen Besucher unserer Website erreichar sind. Das Verzeichnis scripts schließlich beherbergt alle Skripts zum allgemeinen Brauch, zum Beispiel solche, die mittels cron aufgerufen werden.

5.4. Schritt 3: Application-Bootstrapping implementieren

Unter Bootstrapping ist zu verstehen, dass wir für unsere Anwendung die Konfiguration der Umgebung und des Zend Framework sowie dessen Initialisierung vornehmen. Diese Datei zu erstellen ist nicht schwer, doch mit zunehmender Komplexität der Anwendung wächst sie immer weiter an. Um die Ordnung aufrecht zu erhalten, empfehle ich wärmstens, den Bootstrap als Klasse mit handlichen, übersichtlichen Methoden zu erstellen. Die Aufgaben des Bootstrap in Methoden zu zerlegen, wird Wunder für Ihre (seelische) Gesundheit bewirken! Später in diesem Buch werden wir die Lösung von Zend Framework für dieses Komplexitätsproblem kennenlernen: Zend_Application, das mit Zend Framework 1.8 eingeführt wurde.

Da es sich beim Bootstrap um eine Klasse handelt, ist der offensichtlich geeignete Ort für die Aufbewahrung /library. Natürlich können Sie ihn in /application ablegen, aber das würde einen weiteren Include-Path verlangen (außer Sie verwenden Zend_Application, das den absoluten Pfad zur Klasse verwendet), und wenn wir kreuz und quer Klassen ablegen, landen wir irgendwann beim include_path aus der Hölle! Wenn wir annehmen, dass Sie vorerst nicht Zend_Loader_Autoloader verwenden, dann vermeiden wir zwei Einträge in include_path, indem wir Models und die Bootstrap-klasse innerhalb von /library ablegen. Wir werden den neuen Bootstrap als anwendungsspezifische Datei im Namespace ZFExt abspeichern, was heißt, dass die Klasse unter /library/ZFExt/Bootstrap.php zu finden sein wird.

Tja, nun erkennen Sie wahrscheinlich, warum dieses Kapitel das gar nicht so simple Tutorial ist!

Obwohl Sie sich vermutlich gerade erst im Lernprozess befinden, ist der obige Bootstrap weitaus komplexer gestaltet als das minimale Beispiel, das Sie im Referenzhandbuch finden. Ich habe im Code oben zwei Dinge getan. Erstens habe ich den Bootstrap als Klasse mit getrennten Methoden für verschiedene Bootstrap-Aufgaben und -Abschnitte aufgebaut. Zweitens habe ich Standardeinstellungen für alles vorgenommen, was von der Anwendung ausgegeben wird, indem ich Einstellungen von Zend_View (das die Ausgabe der Anwendung mittels des Einsatzes von Templates generiert) und Zend_Controller_Response_Http (das sich um die Header und die Abläufe beim tatsächlichen Senden der Antworten an den Client kümmert) modifiziert habe.

Die ersten Setup-Abschnitte sind ziemlich einfach zu verstehen. Unser Setup der Umgebung, welches in Zukunft durch die Konfiguration gesteuert werden sollte, bereitet PHP mit einigen Einstellungen auf die Anwendung vor: gesetzt werden das Level für die Anzeige von Fehlermeldungen, Informationen zur Zeitzone (wird nicht benötigt, falls sie in php.ini definiert wurde) und eine autoloader-Funktion, so dass wir require_once nicht in unserem Quelltext verwenden müssen. Der angepasste Autoloader steht dem häufiger verwendeten Zend_Loader gegenüber, doch er ist wesentlich schlanker als die Implementierung von Zend_Loader, die eine Menge normalerweise unnötiger Schritte durchführt (siehe Anhang B). Das momentane Umgebungs-Setup ist auf die Entwicklung ausgerichtet, daher werden Fehler angezeigt.

Der nächste Schritt in der Methode prepare() bereitet den Front-Controller vor. Wie erwähnt existiert in Model-View-Controller üblicherweise ein einziger Eintrittspunkt in die Anwendung, eine Stelle, die alle Anfragen passieren müssen. In Zend Framework ist das der Front-Controller, der durch die Klasse Zend_Controller_Front repräsentiert wird. Zends Front-Controller-Klasse ist ein Singleton (ihr lästigstes "Feature" - Singletons sollten vermieden werden, falls sie nicht unbedingt nötig sind). In der Methode setupFrontController() setzen wir einige Flags, um sicherzustellen, dass der Front-Controller ein Response-Objekt zurückgibt, anstatt einfach die Antwort auszugeben, ohne dass wir darauf Einfluss nehmen können, und dass er es ermöglicht, Ausnahmen sichtbar zu werfen, anstatt nach einem ErrorController zu suchen, der zu diesem Zeitpunkt nicht existiert. Der nächste wichtige Schritt ist dem Front-Controller mitzuteilen, wo er die Controller und Views unserer Anwendung findet.

Der letzte Schritt, in dem wir eine eigenständige Instanz des Request-Objekts (z.B. Zend_Controller_Http_Response) erzeugen, existiert, um einen standardmäßigen Content-Type-Header für die Rückmeldungen der Anwendung zu setzen. Das garantiert, dass alle Ausgaben - falls nicht anders festgelegt - dem Client automatisch einen Content-Type-Header "text/html" mit dem Zeichensatz UTF-8 senden. Mit dieser bewährten Vorgangsweise vermeiden wir potentielle Unklarheiten in Fällen, in denen wir die Werte nicht explizit in der Anwendung setzen. Wird dieser Wert nicht festgelegt, wird der standardmäßige Content-Type aus der php.ini verwendet.

Sind die Umgebung und der Front-Controller einmal definiert, fügen wir im letzten Schritt ähnliche Standardwerte für unsere Views hinzu. Momentan verwendet Zend_View im völligen Gegensatz zu anderen Komponenten ISO-8859-1 als Standardzeichensatz (was auch View-Helfer tun), was nicht funktionieren wird, wenn Sie Multibyte-Zeichen ausgeben (wie den in meinem Namen!). Dieser ärgerliche und schon lange bestätigte Bug wird beibehalten, um Problemen mit der Rückwärtskompatibilität bei älteren Zend-Framework-Versionen vorzubeugen. Um diese Standardeinstellung zu ändern, sollten wir eine neue Instanz von Zend_View erzeugen, als angemesseneres Encoding UTF-8 einstellen und dieses veränderte View-Objekt dem ViewRenderer-Action-Helfer einpflanzen. Dieser Helfer wird automatisch von allen Controllern verwendet, um Views zu erfassen und verwalten. Indem wir das zu verwendende View-Objekt explizit festlegen, vermeiden wir, dass wir die unmodifizierte View-Instanz verwenden müssen. Unter der Annahme, dass wir standardmäßig HTML ausgeben, ist es auch stark anzuraten, einen standardmäßigen HTML-Doctype festzulegen, da diese Einstellung auch von anderen Komponenten (z.B. Zend_Form) übernommen wird, wenn diese gerendert werden. Auch hier kann es ärgerlich sein, falls Sie darauf vergessen - zum Beispiel, wenn Formulare unter Einsatz eines anderen Doctype generiert werden. Klarerweise bevorzugen wir es, wenn alles, was als HTML gerendert wird, dem von der View bevorzugten DOCTYPE entspricht.

Wie Sie sehen können, ist das Schreiben eines Bootstrap ein wenig wie Krieg führen. Der Bootstrap überlebt den ersten Kontakt nie und Sie werden sich ständig dabei ertappen, wie Sie von Zeit zu Zeit Pfade, Konfigurationen und andere Optimierungen hinzufügen. Das obige Beispiel stellt eine mögliche Grundlage dar, aber im nächsten Kapitel lernen wir Zend_Application kennen, das einen standardisierteren Ansatz ermöglicht.

5.5. Schritt 4: Der einzige Weg hinein: die Index-Datei

Wir haben einen Bootstrap parat, aber er ist nur nützlich, wenn wir ihn auch wo ausführen. Wie bereits besprochen haben alle Model-View-Controller-Anwendungen (MVC) einen einzigen Eintrittspunkt in die Anwendung. Im Fall von PHP ist das unausweichlich eine Datei namens index.php, die Index-Datei.

Da diese Datei von nahezu jedem Webserver mit PHP-Unterstützung automatisch geladen wird, wenn kein Pfad zu einer anderen Datei angegeben wurde, ist das der Ort, an dem unsere Anwendung zuerst geladen wird. Das ist auch die Stelle, an der wir manuelle Änderungen an include_path vornehmen, die für die lokale Serverumgebung notwendig sind (für Pfade, die unser Bootstrap nicht durch den Autoload-Mechanismus laden kann). Da ich aber nicht vorhabe, ohne gewichtigen Grund gegen die PEAR-Konventionen zu verstoßen, müssen wir in index.php nichts anderes tun, als den Bootstrap zu starten!

Erstellen Sie im Verzeichnis /public Ihres Projekts eine Datei index.php mit folgendem Inhalt:

Falls Sie Bibliotheken mit nicht-konventionellen Include-Pfaden verwenden, müssen Sie diese Include-Pfade hier hinzufügen oder sie über die Bootstrap-Klasse konfigurieren. Momentan kann aber alles, was wir verwenden, automatisch vom Bootstrap geladen werden.

[Anmerkung] Anmerkung

Die PEAR-Konvention ist einfach. Sie verlangt, dass der Name einer Klasse ihren relativen Pfad widerspiegelt. Die Klasse Zend_Controller_Front sollte in einer Datei mit dem relativen Pfad Zend/Controller/Front.php irgendwo in Ihrem include_path gespeichert werden.

Ein kleines Problem haben wir mit unserem theoretisch einzelnen Eintrittspunkt - HTTP funktioniert in der Praxis anders. Wie können wir vermitteln, welchen Teil der Anwendung wir erreichen wollen, wenn die einzig erreichbare Datei index.php ist? Wir müssen in der Lage sein, eine URL zu verwenden, die standardmäßig der Form http://domain.tld/controllername/actionname folgt, damit der Router der Anwendung die korrekte Action-Methode der korrekten Controller-Klasse aufrufen kann. Dieser Ansatz ist auf jedem Webserver zum Scheitern verurteilt, da der Server glauben wird, dass wir ein tatsächlich unter dieser URL existierendes Element zu erreichen versuchen, zum Beispiel das Verzeichnis controllername/actionname/. Um das zu vermeiden, müssen wir die URL an index.php weitergeben und dem Webserver zu verstehen geben, dass wir tatsächlich alle Anfragen über index.php laufen lassen wollen.

Zum Glück bieten Webserver eine Funktionalität namens URL-Rewriting an. Sie ermöglicht es uns, alle URLs (die bestimmte Kriterien erfüllen) in eine neue URL zu transformieren, die auf index.php abgebildet wird und so eine endgültige URL entsprechend dem Muster http://domain.tld/index.php/controllername/actionname erzeugt. Klarerweise muss dieses Kriterium alle URLs zu Ressourcen wie unseren Stylesheets, Javascripts und Bildern aussparen, da wir diese nicht als Parameter an die Anwendung übergeben wollen. Diese Dateien müssen immer direkt ausgeliefert werden.

Wenn Sie Apache als Webserver verwenden, müssen Sie eventuell URL-Rewriting einrichten, indem Sie das Rewrite-Modul aktivieren. Dieses Modul ist bei vielen neu installierten Apache-Instanzen standardmäßig deaktiviert. Um das Modul zu aktivieren, müssen Sie die Konfigurationsdatei von Apache editieren oder auf Ubuntu einfach den (ziemlich praktischen) a2enmod-Befehl verwenden.

Wenn Sie Ubuntu einsetzen, dann versuchen Sie Folgendes:

sudo a2enmod rewrite

Der Befehl nutzt einen Symlink, um die Rewrite-Konfigurationsdatei hinzuzufügen, damit sie als Teil der Gesamtkonfiguration von Apache automatisch geladen wird. Sie müssen Apache neu laden, damit Änderungen an Modulen übernommen werden. Das wird unter Ubuntu mit dem folgenden Befehl erreicht:

sudo /etc/init.d/apache2 reload

Falls Sie Ihre Konfigurationsdatei manuell bearbeiten müssen, müssen Sie normalerweise nur etwas wie die folgende Zeile hinzufügen (Apache danach neu laden):

LoadModule rewrite_module modules/mod_rewrite.so

Falls Sie nicht Apache verwenden, konsultieren Sie bitte den Handbuchabschnitt zu Zend_Controller , um Anweisungen speziell für Ihre Installation ausfindig zu machen.

Um von URL-Rewriting Gebrauch zu machen, fügen Sie die folgende Datei namens .htaccess in /public hinzu:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d

RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]

Falls Sie planen, Ihre Anwendung in einem Unterverzeichnis zu hosten, sollten Sie auch eine RewriteBase-Zeile hinzufügen um sicherzugehen, dass die Regeln diesen Teil der URL ausnehmen und nur den Pfadteil nach diesem Punkt heranziehen, wenn die URL für index.php umgeschrieben wird.

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d

RewriteBase /subdirectory/
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]

Die Datei .htaccess stellt einige Rewrite-Regeln auf um sicherzugehen, dass alle entsprechenden Anfragen auf die Index-Datei unserer Anwendung geleitet werden. Dabei sind die Regeln so formuliert, dass alle URLs außer jenen berücksichtigt werden, auf welche die vorangegangenen Rewrite-Konditionen zutreffen. Die Konditionen nehmen URLs aus, die auf eine Datei (mit einer Dateigröße größer als 0), ein existierendes Verzeichnis oder einen symbolischen Link verweisen. Dadurch ist gesichert, dass Ihre JavaScript-, CSS- und andere Nicht-PHP-Dateien direkt ausgeliefert werden können, selbst wenn sie woanders vorgehalten werden und nur durch symbolische Links referenziert werden.

[Anmerkung] Anmerkung

Wenn Sie einen kleinen Geschwindigkeitsgewinn erzielen wollen, ist es oft eine gute Idee, den Inhalt der .htaccess-Datei direkt in Ihre Apache-Konfiguration für dieses Verzeichnis einzutragen (wir haben dieses Verzeichnis vorhin konfiguriert, als wir einen neuen virtuellen Host hinzufügt haben). Dann können Sie die Datei .htaccess löschen und Apache muss sie nicht bei jeder Anfrage parsen, da sie beim Start von Apache einmalig und permanent geladen wird. Allerdings müssen Sie Apache jedes Mal neu starten, wenn Sie Änderungen an den Rewrite-Regeln vornehmen.

5.6. Schritt 5: Standard-Controller und -View hinzufügen

Als wir Model-View-Controller (MVC) diskutiert haben, haben wir angemerkt, dass der Controller dafür verantwortlich ist, die Verbindung zwischen Benutzereingaben und dem Model bzw. den Models und der View herzustellen. Der Controller ist daher eine der ersten Komponenten, mit denen Sie sich auseinandersetzen müssen, wenn Sie ein neues Feature zu einer Anwendung hinzufügen.

In Zend Framework sind alle Controller letztlich Subklassen von Zend_Controller_Action. Diese Basisklasse stellt einige Grundregeln auf, die Sie in Erinnerung behalten sollten. Zum Beispiel wurde festgelegt, dass standardmäßig alle Controller automatisch Views rendern. Das bedeutet, dass Sie sich nicht manuell darum kümmern müssen, dass View-Templates gerendet werden - stattdessen wird ein Action-Helfer mit dem Namen View-Renderer (Zend_Controller_Action_Helper_ViewRenderer) aufgerufen. In unserer Bootstrap-Klasse passten wir das Standardverhalten an, indem wir sicherstellten, dass der View-Renderer eine Zend_View-Instanz mit dem Standardzeichensatz UTF-8 (statt ISO-8859-1) verwendet. Im Referenzhandbuch ist dokumentiert, wie das automatisierte Rendern von Views deaktiviert werden kann. Dies ist häufig nützlich, wenn Sie Zend_View umgehen müssen (zum Beispiel, um JSON oder XML-Dokumente auszuliefern, die nicht templatebasiert sind und keine weitere Verarbeitung benötigen).

Der Router (Zend_Controller_Router_Route und zugehörige Klassen) ist dafür verantwortlich festzustellen, welcher Controller benutzt werden soll. Er trifft die Entscheidung anhand des URL-Strings, welcher entweder den Klassennamen des Controllers sowie den Namen der Methode enthält oder einer konfigurierten Route entspricht, die standardmäßige Controller- und Action-Namen liefert. Fehlt diese Information, geht der Router jeweils vom Standardwert "index" aus. Da wir nur vorhaben, die Root-URL http://helloworld.tld anzufragen, werden wir einen Index-Controller mit einer Index-Action benötigen, also einen Controller, der die Standardannahmen des Routers erfüllt, wonach die URL gleichbedeutend mit http://helloworld.tld/index/index ist. Hier ist der Quelltext für /application/controllers/IndexController.php:

Die Methode init() können Sie ignorieren, da sie nur für Funktionen benötigt wird, die beim Setup des Controllers ausgeführt werden müssen - eine solche Funktion brauchen wir hier nicht. Wichtiger ist die Methode indexAction(). Sie ist leer, was kein Problem ist, da wir in diese Methode nur etwas hineinschreiben müssen, wenn wir mit einem Model oder anderen Klassen interagieren müssen. Momentan ist das nicht der Fall. Die Methode dient nur als eine Stub-Methode, die dem ViewRenderer-Action-Helfer mitteilt, dass er eine View mit einem ähnlichen Namen rendern soll.

Um das Mapping zu erklären: ein Controller "Index" mit einer Methode indexAction() wird auf ein View-Template umgelegt, das unter /application/views/scripts/index/index.phtml zu finden ist. ErrorController::indexAction() würde demnach zu /application/views/scripts/error/index.phtml führen und so weiter. Es handelt sich um eine simple Konvention. Lassen Sie uns ein Template für IndexController::indexAction() in /application/views/scripts/index/index.phtml erstellen:

In Zend Framework befinden sich Templates innerhalb des Geltungsbereichs des Zend_View-Objekts. Somit sind alle Eigenschaften und Methoden, die für Zend_View zugänglich sind, auch für Templates erreichbar, indem $this verwendet wird (um auf das aktuelle Zend_View-Objekt zu referenzieren, dessen Variablenbereich gerade gültig ist).

Bei diesem Code handelt es sich um ein hundertprozentig valides Template, das auch funktioniert, aber später werden wir das Konzept der View-Helfer genauer kennenlernen. Kurz gesagt kapselt ein View-Helfer häufig benötigte, präsentationsbezogene Funktionen in Helfer-Klassen. Wollen wir zum Beispiel den Doctype-String zu dutzenden Templates hinzufügen? Wenn wir das machen und sich der Doctype ändert, müssen wir dutzende Templates editieren. Nein, wir wollen es nicht. Zend_View besitzt einen Helfer, den wir im Bootstrap verwendet haben, um einen Standard-Doctype festzusetzen. Genauso, wie wir im Bootstrap einen weiteren Helfer verwendet haben, um einen http-equiv-Header mit einem Standard-Content-Type zu den Meta-Informationen des Headers hinzuzufügen. Mittels dieser zwei Helfer, deren Inhalt direkt über echo ausgegeben werden kann, weil sie indirekt die magische PHP-Methode __string() implementieren, können wir das Template auf den folgenden Code reduzieren:

Nun haben wir "en" noch an drei verschiedenen Stellen eingetragen. Wir könnten das ebenfalls mit einem View-Helfer automatisieren, der sicherstellt, dass der Wert entsprechend der Sprache der Inhalte angepasst wird. Das demonstriert, warum View-Helfer nützlich sind - wir können Funktionen für Änderungen an der View in sie auslagern, damit sie vielfach über viele verschiedene Views hinweg wiederverwendbar sind. Es ist nicht wichtig, dass Sie View-Helfer schon jetzt komplett verstehen. Sie müssen nur wissen, dass sie existieren!

Editieren Sie nun IndexController.php, um der View den Titel der Seite zu übergeben (im View-Skript als $this->title referenziert).

Alle Controller müssen Zend_Controller_Action erweitern, da die Klasse alle später referenzierten internen Methoden und Eigenschaften enthält, die allen Controllern gemein sind. Falls Sie den Basiscontroller optimieren müssen, um neue Methoden oder Eigenschaften einzuführen, können Sie das machen, indem Sie eine Subklasse von Zend_Controller_Action erstellen und Sie alle Anwendungscontroller stattdessen von dieser Subklasse ableiten. Seien Sie aber sehr vorsichtig, wenn Sie auf diese Weise vorgehen - es ist praktisch, der Klasse so neue Eigenschaften hinzuzufügen, aber oft ist es besser, zusätzliche Methoden als eigenständige Action-Helfer hinzuzufügen, um der Entwicklung einer übergeordneten Controller-Klasse vorzubeugen, die kaum mehr ist als ein schwer wartbares Knäuel von kaum zueinander in Verbindung stehenden Spaghetti-Nudeln.

Unsere neue Action-Methode ignoriert das Rendering; das passiert wie oben erwähnt automatisch über den standardmäßig aktivierten View-Renderer. Alles was wir zun müssen ist, die benötigten View-Daten zu definieren. Auf diese Weise können Sie fast alles zur View hinzufügen, da es schlicht eine Eigenschaft in einem View-Template wird. Tun Sie sich keinen Zwang an, Objekte und Arrays hinzuzufügen. Falls Sie Smarty oder PHPTAL verwenden, ist das vielleicht anders. Dies ist - wie ebenfalls weiter oben besprochen - auf das Konzept zurückzuführen, laut dem Views Models verwenden. Ein Model ist üblicherweise ein Objekt, also gibt es keinen Grund, Views auf einfache Arrays zu beschränken, wenn es wesentlich angenehmer ist, einfach ein Objekt zu übergeben.

Oben haben wir der View mitgeteilt, dass Templates eventuell eine lokale, öffentliche Klasseneigenschaft "title" verwenden werden und haben dieser den Wert "Hello, World!" zugewiesen. Wenn die Action-Methode abgewickelt ist, kommt der View-Renderer ins Spiel und versucht das Template in der Datei /application/views/scripts/index/index.phtml zu rendern.

Innerhalb des View-Scripts maskieren (escapen) wir den Titel, da wir nicht davon ausgehen können, dass er harmlos ist. Es ist eigentlich obligatorisch, alles so zu maskieren, wenn es als HTML ausgegeben wird. Intern verwendet Zend_View standardmäßig htmlspecialchars()und gibt der Funktion die Character-Encoding-Einstellung der aktuellen Instanz mit. Auch das ist eine dieser kleinen Ärgernisse - in Zend Framework 2.0 wird die Maskierung automatisch vorgenommen, ohne dass ständig die Methode escape() aufgerufen werden muss.

5.7. Fazit

In diesem Kapitel haben wir ein ziemlich einfaches (aha!) Beispiel behandelt, wie Zend Framework zur Erstellung einer Anwendung verwendet wird. Es betont auch, wie wichtig Bootstraping ist, da hier fast das komplette Setup der Anwendung erfolgt, inklusive des Setzens von Standardwerten und Konfigurationseinstellungen für Zend-Framework-Komponenten. Über das gesamte Buch hinweg erfolgt die Verwaltung eigener Plugins, Action-Helfer und anderer nicht standardmäßig zum Zend Framework gehörenden Klassen über den Bootstrap, da es sich um den logischsten Ort handelt, um ihre Konfiguration und Einbindung in eine Anwendung vorzunehmen.

Im nächsten Kapitel beschäftigen wir uns mit etwas, was ich - wie jedem, der über die neueren Versionen von Zend Framework informiert ist, klar aufgefallen sein wird - ausgespart habe: wie man die Komplexität des Bootstrapping mittels Zend_Application bändigt. Danach erkläre ich, wie man mit Anwendungsfehlern umgeht. Bald danach tauchen wir in eine tatsächliche Anwendung ein, da ich unbedingt einen Ersatz für mein Blog benötige, und so wird das die einfache Anwendung sein, andhand der wir andere Zend-Framework-Komponenten genauer erforschen werden.