Zend Framework Tutorial Teil 3: MVC Design Pattern und Zend_Controller

Nach der Einführung in das TravelloBlog Projekt im ersten Teil dieses Tutorials haben wir im zweiten Teil unser grundlegendes System aufgebaut, die Verzeichnisstruktur eingerichtet und eine erste rudimentäre Bootstrap Datei erstellt. Wer mochte, hat sich auch einen VirtualHost auf seinem Entwicklungsrechner eingerichtet. Wenn du die ersten beiden Teile noch nicht gelesen hast, hole dies bitte schnell nach.

In diesem dritten Teil gebe ich eine kurze Einführung in das Model-View-Controller Entwurfsmuster (neudeutsch auch Design Pattern). Mit diesem Wissen ausgerüstet werden wir unsere Anforderungen aus dem ersten Teil des Zend Framework Tutorials untersuchen und alle benötigten Controller und deren Aktionen (Actions) ermitteln. Danach erstellen wir gemeinsam unseren ersten Controller und die notwendigen Aktionen. Hierfür greifen wir auf die Zend Framework Komponente Zend_Controller zurück.

Wenn du über neue Tutorial Teile informiert werden möchtest, abonniere am besten den Feed dieses Blogs. Dann verpasst du garantiert keinen Teil des Tutorials. Es gibt auch Übersicht mit den bisher erschienen Teilen des Tutorials.

Wichtig: Dieses Tutorial setzt die Zend Framework Preview Version 0.6.0 voraus und kann bei der Verwendung einer aktuelleren Version aus dem SVN unter Umständen nicht zu 100% funktionieren.

Inhaltsverzeichnis

Model-View-Controller

Das Zend Framework bietet bereits alle Voraussetzungen, um ein Webprojekt nach dem Model-View-Controller Entwurfsmuster aufbauen zu können. Bei einer MVC Architektur wird die Anwendung in die drei wesentlichen Teilkomponenten Daten (Model), Präsentation (View) und Programmsteuerung (Controller) aufgeteilt.

Die Model Komponente ist hierbei für die Interaktion mit den Daten zuständig. Die Daten können aus verschiedenen Datenquellen stammen, z.B. aus einer MySQL oder SQLite Datenbank, aus XML Dateien oder einem beliebigen anderen Dateiformat oder über einen Webservice per XML-RPC oder SOAP von einem entfernten Webserver. Das Model liest die Daten aus der Datenquelle und gibt die gelesenen Daten an den Controller zurück. Das Model erhält aber auch Daten vom Controller und "speichert" sie in der Datenquelle ab.

Die View Komponente ist für die Präsentation der Daten zuständig. Bei einer Webanwendung ist dies in der Regel ein HTML Template, es kann aber auch eine XML Datei, ein RSS Feed oder eine WML Seite ausgegeben werden. Die View Komponente erhält die zu präsentierenden Daten vom Controller und sollte niemals direkt mit der Model Komponente interagieren. In einem View sollte nur Präsentationslogik (z.B. Schleifdurchläufe für die Darstellung von Listen oder einfache Fallentscheidungen für eine Farbwahl) enthalten sein und keine Geschäftslogik (z.B. Umrechnung von Währungskursen oder Verarbeitung von Eingabedaten). Die Verarbeitung der Geschäftslogik bleibt ausschließlich der Controller Komponente vorenthalten.

Die Controller Komponente ist dafür zuständig, zwischen den anderen beiden Komponenten zu vermitteln. In der Regel wird bei einer Anfrage an einen Webserver ermittelt, welcher Controller für die Verarbeitung der Anfrage zuständig ist. Wenn nötig, ruft der Controller bei der zuständigen Model Komponente die erforderlichen Daten ab, bereitet sie auf und übergibt sie an die zuständige View Komponente, welche die Daten darstellt. Der Controller kann bei einer Anfrage aber auch nur mit der View Komponente interagieren, wenn keine Daten gelesen oder geschrieben werden müssen. Genauso gut kann der Controller bei einer Anfrage aber auch nur mit der entsprechenden Model Komponente interagieren, wenn nach der Verarbeitung der Daten keine Ausgabe erforderlich ist.

Wenn du über das Model-View-Controller Entwurfsmuster erfahren möchtest, schaue dir bei Gelegenheit einmal die folgenden Links an:

Ein Controller ist in der Regel eine Klasse, die eine beliebige Anzahl an öffentlichen Methoden enthält, die so genannten Aktionen. Wenn wir uns z.B. einen Controller für einen Benutzer vorstellen, wären dies mögliche Aktionen:

  • anlegen
  • ändern
  • löschen
  • anzeigen
  • einloggen
  • authentifizieren
  • ausloggen

Hierbei sollte man darauf achten, dass eine Aktionsmethode möglichst auch nur eine Aktion verarbeitet, um nicht in die Verlegenheit zu kommen, komplizierte switch- oder if-elseif-else-Anweisungen verwenden zu müssen. Dadurch vermeiden wir eine unnötige Komplexität.

Buchtipp Design Patterns

Wenn du dir generell einmal einen fundierten Überblick über Design Patterns und deren Umsetzung in PHP verschaffen möchtest, sei dir das englischsprachige Buch "PHP Architect's Guide to PHP Design Patterns" von Jason E. Sweat ans Herz gelegt. Obwohl es in englisch ist, kann man die Beispiele recht gut nachvollziehen. Zudem wird man durch das Buch mit dem Test-Driven-Design Virus infiziert, aber das ist ein anderes Thema.

Benötigte Controller und Aktionen ermitteln

Jetzt stellt sich natürlich die Frage, welche Controller und welche dazugehörigen Aktionen wir denn für unser TravelloBlog überhaupt benötigen. Um nicht blind in der Gegend herum zu raten, ziehen wir an dieser Stelle die Liste mit den Anforderungen aus dem ersten Teil des Tutorials zu Rate.

Im ersten Schritt gehen wir jede der Anforderungen durch und notieren uns die benötigten Entitäten. Dabei kommt diese Liste heraus (in Klammern die Nummer der Anforderung, welche sich auf die Entität bezieht):

  • Beitrag (1, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14)
  • Benutzer (1, 2, 11)
  • Kommentar (3, 11)
  • Kategorie (4, 7)
  • Tag (4, 7)
  • Suchindex (13)

Wir sehen also, dass die Entität "Beitrag" der Kern unserer Bloganwendung werden wird, was dich nicht überraschen sollte. Am zweitwichtigsten scheint danach die Entität "Benutzer" zu sein. Wir benötigen somit fürs Erste insgesamt sechs Controller.

Im zweiten Schritt analysieren wir nun, welche Aktionen für die einzelnen Controller benötigt werden. Dies gestaltet sich ein wenig schwieriger, da nicht jede Aktion sofort ersichtlich ist.

In der folgenden Tabelle habe ich in der ersten Spalte die Controller und in der zweiten Spalte die entsprechenden Aktionen notiert (in Klammern steht wieder bei jeder Aktion die Nummer der Anforderung)

Controller Aktionen
Beitrag anlegen (1), ändern (1), löschen (1), anzeigen (3), listen auf Startseite (6), listen nach Kategorie (7), listen nach Tag (7), listen nach Monat (7), Trackback verarbeiten (8), Pingback versenden (8), listen für Newsfeed (9), anzeigen als PDF (12), listen für Suche (13), zeige Bücher von Amazon (14), zeige Fotos von Flickr (14)
Benutzer registrieren (1), ändern (1), einloggen (1*), ausloggen (1*), authentifizieren (1*), anzeigen (2)
Kommentar schreiben (3), benachrichtigen (11)
Kategorie anlegen (4*), ändern (4*), löschen (4*)
Tag anlegen (4*), ändern (4*), löschen (4*)
Suchindex anlegen (13*), ändern (13*), löschen (13*), durchsuchen (13*)

Die mit (1*) markierten Aktionen werden zwar nicht explizit in den Anforderungen genannt. Ich denke aber, dass man davon ausgehen kann, dass diese Aktionen für das Handling eines Benutzer wichtig sein werden.

Zu (4*) ist zu sagen, dass diese Aktionen auch nur indirekt zu erkennen sind. Wenn ein Beitrag einer Kategorie und/oder einem Tag zugeordnet werden können soll, müssen Kategorien und Tags natürlich auch angelegt, geändert und gelöscht werden können.

Bei (13*) gilt ähnliches. Auch diese Aktionen resultieren indirekt aus der entsprechenden Anforderung. Ohne eine vorhandenen Index kann selbiger auch nicht durchsucht werden.

Nach dieser ersten Analyse haben wir nun einen ersten Überblick, welche Controller und welche Aktionen wir benötigen werden.

Zend_Controller

Nach der theoretischen Einführung in das MVC-Konzept und der Ermittlung aller benötigten Controller und Aktionen gibt es nun endlich Butter bei die Fische. Mit Hilfe der Zend_Controller Komponente schreiben wir unsere erste Controller Klasse. Für einen Überblick empfehle ich die Lektüre des Zend Framework Manuals zur Zend_Controller Komponente.

Im Zend Framework wird ein Controller durch eine Klasse repräsentiert, die von der abstrakten Klasse Zend_Controller_Action abgeleitet werden muss. Zend_Controller_Action stellt einige Methoden für Redirects auf andere Seiten, das Weiterleiten zu anderen Controllern und Aktionen sowie das Bereitstellen von Parametern aus der angeforderten URL bereit.

Unsere Controller Klasse muss mit dem Namen des Controllers starten und auf "Controller" enden, wobei der Name mit einem Großbuchstaben beginnen muss. Für unser TravelloBlog würde dies folgende Controller Namen ergeben:

  • ArticleController
  • UserController
  • CommentController
  • CategoryController
  • TagController
  • SearchController

Die Controller Klassen müssen genauso benannt werden und werden nur um die Dateiendung ".php" ergänzt. Alle Controller Klassen werden dann in einem Verzeichnis abgelegt. Wie du sicher schon vermutest, ist dies in unserem Fall das Verzeichnis "/travelloblog/application/controllers".

Die Aktionen eines Controllers müssen als öffentliche Methoden (public) deklariert werden. Sie müssen mit einem Kleinbuchstaben beginnen und auf "Action" enden. Durch das Routing weiß Zend_Controller dann, welche Controller Klasse und welche Action Methode aufgerufen werden muss. Dazu gleich mehr.

Die abstrakte Klasse Zend_Controller_Action, von der wir unsere Controller Klassen ableiten, setzt zwingend das Vorhandensein einer Methode mit Namen "indexAction" voraus. Diese Methode wird immer dann aufgerufen, wenn keine auszuführende Aktion für einen Controller ermittelt werden konnte.

Routing

Der erste Teil einer URL wird auf einen Controller und der zweite Teil auf die Aktion des Controllers abgebildet. Ist weder Controller noch Aktion angegeben, wird per Default die Methode IndexController::indexAction() aufgerufen. Ist zwar ein Controller aber keine Aktion angegeben, wird die Methode indexAction() in diesem Controller aufgerufen.

Das Routing funktioniert per Default beispielsweise wie folgt:

Adresse Routing auf
http://travelloblog/ IndexController::indexAction()
http://travelloblog/index/foo IndexController::fooAction()
http://travelloblog/foo FooController::indexAction()
http://travelloblog/foo/bar FooController::barAction()
http://travelloblog/bar/foo BarController::fooAction()

IndexController

Zusätzlich zu den im vorletzten Abschnitt identifizierten Controllern benötigen wir somit auf jeden Fall einen Controller, welche die Homepage unseres TravelloBlogs und einige andere Zugriffe steuert, die nicht direkt einer unserer Entitäten zugeordnet werden kann. Dies könnte zum Beispiel das Handling von Zugriffen sein, für die keine Route ermittelt werden konnte, also die klassische 404 Fehlerseite.

Wir erstellen im Verzeichnis "/travelloblog/application/controllers" eine Datei mit Namen "IndexController.php" und folgendem rudimentären Code:

PHP:
  1. <?php
  2. class IndexController extends Zend_Controller_Action
  3. {
  4.     public function indexAction()
  5.     {
  6.         echo "IndexController::indexAction()<br />";
  7.     }
  8. }
  9. ?>

Damit dieser Controller aufgerufen werden kann, öffnen wir nun wieder unsere Bootstrap Datei "index.php" im Verzeichnis "/travelloblog/public/" und erweitern den Code wie folgt.

PHP:
  1. <?php
  2.  
  3. require_once('set_include_path.php');
  4.  
  5. if (!class_exists('Zend')) require_once 'Zend.php';
  6.  
  7. Zend::loadClass('Zend_Controller_Front');
  8.  
  9. $dir = '../application/controllers';
  10.  
  11. $controller = Zend_Controller_Front::getInstance();
  12. $controller->setControllerDirectory($dir);
  13. $controller->throwExceptions(true);
  14. $controller->dispatch();
  15. ?>

Zuerst setzen wir das Error Reporting von PHP auf "E_ALL", damit uns kein Fehler entgeht. Das Laden der Datei "set_include_path.php" und der Zend Basisklasse ist uns schon aus dem letzten Teil dieses Tutorials bekannt. Die restlichen Zeilen sind aber neu.

Wir verwenden die Zend::loadClass Methode, um die "Zend_Controller_Front" Klasse zu laden. Danach legen wir das Verzeichnis fest, in dem sich unsere Controller Klassen befinden. Um nun den Routingprozess zu starten, erstellen wir zuerst eine Instanz von "Zend_Controller_Front", setzen dann das Controller Verzeichnis und starten zum Schluss den Dispatching Prozess. Der Aufruf der throwExceptions() Methode dient dazu, dass uns während der Entwicklung auch alle nicht abgefangenen Exceptions ausgeworfen werden. Ansonsten wissen wir nicht, wenn es irgendwo zu einem Problem gekommen ist.

Für detaillierte Informationen zum Dispatching und Routing der Zend_Controller Komponente verweise ich noch einmal auf das Zend Framework Manual, in dem dies sehr gut beschrieben wird.

Rufen wir nun die Adresse unseres TravelloBlogs im Browser auf und sehen, was passiert. Wenn wir die verkürzte Adresse "http://travelloblog/" aufrufen, wird wie erwartet der Text "IndexController::indexAction()" ausgegeben. Bei einem Aufruf der Adresse "http://localhost/travelloblog/public/" erhalten wir jedoch eine Fehlermeldung über eine nicht abgefangene Ausnahme. Was ist passiert?

In den ersten Versionen von Zend_Controller funktionierte das Routing, also das Abbilden von URLs auf Controller und Aktionen, nur, wenn die Bootstrap Datei im DocumentRoot der Webserveradresse lag. In der Adresse "http://localhost/travelloblog/public/" liegt unsere Bootstrap Datei jedoch in einem Unterverzeichnis und das Routing schlägt fehl.

Um das Problem zu lösen, greifen wir auf die in Version 0.1.5 eingeführte Komponente Zend_Controller_RewriteRouter zurück.

Zend_Controller_RewriteRouter

Mit Hilfe von Zend_Controller_RewriteRouter können wir das Routing von URLs auf Controller und Aktionen besser beeinflussen. Ich empfehle dir hier wieder die Lektüre des Manuals, um dir einen ersten Überblick über die Komponente zu verschaffen.

Die genaue Funktionsweise des Routingprozesses von Zend_Controller_RewriteRouter und, wie man das oben erläuterte Verhalten beeinflussen kann, werden wir in einem späteren Kapitel genauer unter die Lupe nehmen.

Um unser obiges Problem zu lösen, benötigen wir in unserer Bootstrap Datei nur einige neue Zeilen (ich ersetze der Einfachheit halber einige unveränderte Zeilen durch [...]).

PHP:
  1. <?php
  2. [...]
  3.  
  4. Zend::loadClass('Zend_Controller_Front');
  5. Zend::loadClass('Zend_Controller_RewriteRouter');
  6.  
  7. $dir = '../application/controllers';
  8.  
  9. $router = new Zend_Controller_RewriteRouter();
  10.  
  11. $controller = Zend_Controller_Front::getInstance();
  12. $controller->setRouter($router);
  13. $controller->setControllerDirectory($dir);
  14. $controller->throwExceptions(true);
  15. $controller->dispatch();
  16. ?>

Jetzt funktioniert der Aufruf von "http://travelloblog/" weiterhin reibungslos. Und auch wenn du das TravelloBlog in einem Unterverzeichnis betreibst, z.B. unter der Adresse "http://localhost/travelloblog/public/", sollte der Aufruf klappen.

Hinweis

Der Einfachheit halber werde ich in Zukunft nur noch die kürzere Adresse verwenden und nicht mehr beide Varianten angeben. Wenn du also keinen VirtualHost angegeben hast, musst du die Aufrufe entsprechend anpassen.

Falsche Routen abfangen

Was passiert eigentlich, wenn wir nun testweise einmal "http://travelloblog/foo" als Adresse eingeben? Wir erhalten wieder eine Fehlermeldung, in der unter anderem folgendes steht (diese Meldung wird nur ausgegeben, wenn wir die throwExceptions() Methode mit true aufgerufen haben):

Zend_Controller_Dispatcher_Exception: "foo" controller does not exist

Wenn das Routing fehlschlägt und kein Controller gefunden werden konnte, bricht der Dispatching Prozess also mit einer Exception ab. Wir müssen nun also sicherstellen, dass dieser Fall nicht auftritt bzw. eine entsprechende Fehlerseite aufgerufen wird. Bis zum Release 0.6.0 wurde für diesen Fall eine Methode "norouteAction" im IndexController vorausgesetzt, mit dem Release 0.6.0 wurde dies jedoch geändert. Aus diesem Grund benennen wir die Methode für die Anzeige von fehlerhaftem Routing auch weiterhin genauso.

Um die fehlerhaften Routen abzufangen, erweitern wir unsere IndexController Klasse um die beiden Methoden "norouteAction" und "__call". Die Methode "__call" muss unbedingt zwei Argumente entgegen nehmen, ansonsten erhalten wir eine Fehlermeldung:

PHP:
  1. <?php
  2. class IndexController extends Zend_Controller_Action
  3. {
  4.     [...]
  5.  
  6.     public function norouteAction()
  7.     {
  8.         echo "IndexController::norouteAction()<br />";
  9.     }
  10.    
  11.     public function __call($methodName, $args)
  12.     {
  13.         echo "IndexController::__call()<br />";
  14.     }
  15. }
  16. ?>

Wenn wir unsere Adresse "http://travelloblog/foo" wieder aufrufen, wird aber weiterhin die Exception ausgeworfen. Um "__call" aufzurufen, geben wir die Adresse "http://travelloblog/index/foo" ein und sehen den Text "IndexController::__call()".

Jetzt fragst du dich wahrscheinlich immer noch, wo denn nun genau der Unterschied zwischen "norouteAction" und "__call" ist.

  • "norouteAction" wird immer dann im IndexController aufgerufen, wenn kein Controller für die Anfrage ermittelt werden konnte.
  • "__call" wird immer dann aufgerufen, wenn ein Controller zwar vorhanden ist, aber die Aktionsmethode nicht existiert.
  • Daraus folgt, dass die Deklaration von "norouteAction" nur im IndexController Sinn macht, während jede Controller Klasse eigentlich immer eine "__call" Methode enthalten sollte.

Jetzt müssen wir aber immer noch sicherstellen, dass die "norouteAction" Methode auch aufgerufen wird, wenn kein Controller gefunden werden konnte. Dazu müssen wir die Exception abfangen und die Methode manuell aufrufen:

PHP:
  1. <?php
  2. [...]
  3. $controller = Zend_Controller_Front::getInstance();
  4. $controller->setRouter($router);
  5. $controller->setControllerDirectory($dir);
  6. $controller->throwExceptions(true);
  7.  
  8. try
  9. {
  10.     $controller->dispatch();
  11. }
  12. catch (Exception $e)
  13. {
  14.     require_once($dir . '/IndexController.php');
  15.     IndexController::norouteAction();
  16. }
  17. ?>

Dies ist nur ein schneller Hack, um das Problem erst einmal zu lösen. Im weiteren Verlauf des Tutorials werde ich noch einen eleganteren Weg zeigen, wie man fehlerhafte Routen abfangen kann. Später werden wir außerdem noch sehen, was in den Parametern "$methodName" und "$args" enthalten ist, wenn die "__call()" Methode aufgerufen wird (wobei die Namen eigentlich schon selbsterklärend sind).

Der IndexController enthält nun erst einmal alle notwendigen Methoden, die wir brauchen. Im nächsten Schritt definieren wir nun unseren ArticleController mit allen notwendigen Methoden.

ArticleController

Wir erstellen im Verzeichnis "/travelloblog/application/controllers" eine Datei mit Namen "ArticleController.php" und folgendem Code:

PHP:
  1. <?php
  2. class ArticleController extends Zend_Controller_Action
  3. {
  4.     public function indexAction()
  5.     {
  6.         echo "ArticleController::indexAction()<br />";
  7.     }
  8.    
  9.     public function __call($methodName, $args)
  10.     {
  11.         echo "ArticleController::__call()<br />";
  12.     }
  13. }
  14. ?>

Probiere einmal folgende Adressen aus und sehe, was passiert:

  • http://travelloblog/article/
  • http://travelloblog/article/show
  • http://travelloblog/article/create

Jetzt ziehen wir unsere Übersicht mit allen benötigten Aktionen für unseren ArticleController zu Rate und erstellen für jede Aktion aus der Liste eine eigene Methode. Dies sieht dann in etwa wie folgt aus:

PHP:
  1. <?php
  2. class ArticleController extends Zend_Controller_Action
  3. {
  4.     [...]
  5.  
  6.     public function createAction()
  7.     {
  8.         echo "ArticleController::createAction()<br />";
  9.     }
  10.    
  11.     public function changeAction()
  12.     {
  13.         echo "ArticleController::changeAction()<br />";
  14.     }
  15.    
  16.     public function deleteAction()
  17.     {
  18.         echo "ArticleController::deleteAction()<br />";
  19.     }
  20.    
  21.     public function showAction()
  22.     {
  23.         echo "ArticleController::showAction()<br />";
  24.     }
  25.    
  26.     public function listStartpageAction()
  27.     {
  28.         echo "ArticleController::listStartpageAction()<br />";
  29.     }
  30.    
  31.     public function listCategoryAction()
  32.     {
  33.         echo "ArticleController::listCategoryAction()<br />";
  34.     }
  35.    
  36.     public function listTagAction()
  37.     {
  38.         echo "ArticleController::listTagAction()<br />";
  39.     }
  40.    
  41.     public function listMonthAction()
  42.     {
  43.         echo "ArticleController::listMonthAction()<br />";
  44.     }
  45.    
  46.     public function trackbackAction()
  47.     {
  48.         echo "ArticleController::trackbackAction()<br />";
  49.     }
  50.    
  51.     public function pingbackAction()
  52.     {
  53.         echo "ArticleController::pingbackAction()<br />";
  54.     }
  55.    
  56.     public function listNewsfeedAction()
  57.     {
  58.         echo "ArticleController::listNewsfeedAction()<br />";
  59.     }
  60.    
  61.     public function showPdfAction()
  62.     {
  63.         echo "ArticleController::showPdfAction()<br />";
  64.     }
  65.    
  66.     public function listSearchAction()
  67.     {
  68.         echo "ArticleController::listSearchAction()<br />";
  69.     }
  70.    
  71.     public function showAmazonAction()
  72.     {
  73.         echo "ArticleController::showAmazonAction()<br />";
  74.     }
  75.    
  76.     public function showFlickrAction()
  77.     {
  78.         echo "ArticleController::showFlickrAction()<br />";
  79.     }
  80. }
  81. ?>

Probiere nun wieder folgende Adressen aus und sehe, was passiert:

  • http://travelloblog/article/
  • http://travelloblog/article/show
  • http://travelloblog/article/create
  • http://travelloblog/article/showAmazon
  • http://travelloblog/article/listTag
  • http://travelloblog/article/trackback
  • http://travelloblog/article/foo

Unser ArticleController ist somit erst einmal fertiggestellt und das rudimentäre Routing von URLs auf die Aktionsmethoden klappt.

Übung: die weiteren Controller

Als kleine Übung bis zum nächsten Teil dieses Tutorials erstelle bitte die restlichen Controller und deren Aktionsmethoden, die wir oben ermittelt haben. Zur Kontrolle lade dir den aktuellen Stand des Tutorials runter. Dann kannst du deine Ergebnisse gut vergleichen.

Download

Der aktuelle Stand des Tutorials nach diesem dritten Teil kann wieder herunter geladen werden. Hier sind auch alle Controller Klassen enthalten. Die Textdateien "empty.txt" in einigen Verzeichnissen habe ich nur angelegt, weil mein Winzip keine leeren Verzeichnisse im Zip Archiv anlegt:

Die Zip Datei enthält nicht die aktuelle Version des Zend Frameworks. Dies musst du bitte selber in das entsprechende Verzeichnis kopieren.

Zusammenfassung

In diesem dritten Teil meines Zend Framework Tutorials habe ich das Model-View-Controller Konzept erläutert und dir einige weiterführende Links an die Hand gegeben. Wir haben die benötigten Controller und Aktionen anhand unserer Anforderungsliste ermittelt. Nach einer Einführung in die Zend_Controller Komponente haben wir den IndexController erstellt und erfahren, wie das Routing von URLs auf die Controller und Aktionsmethoden funktioniert. Zum Abschluss haben wir unsere sechs weiteren Controller erstellt.

Im nächsten Teil dieses Tutorials kümmern wir uns um den Model Part unserer Anwendung. Dabei lernen wir die Zend_Db Komponente mit ihren diversen Teilkomponenten kennen und werden diese in unserem TravelloBlog auch einbinden.

Fragen, Probleme und Anregungen bitte nicht per E-Mail senden, sondern hier in die Kommentare stellen. Dann haben alle etwas davon.

Change Log

An dieser Stelle werden Änderungen an diesem Tutorial Teil zusammengefasst, die nach dem Ersterscheinen (04.09.2006) notwendig waren, z.B. durch neuere Versionen des Zend Frameworks oder Änderungen am Konzept des Tutorials oder den Anforderungen an unser TravelloBlog.

  • 05.11.2006: Tutorial an Release 0.2.0 angepasst
  • 28.12.2006: für Release 0.6.0 aktualisiert

Navigation

57 Antworten für “Zend Framework Tutorial Teil 3: MVC Design Pattern und Zend_Controller”

  1. Ralf’s PHP Blog » Zend Framework Tutorial Teil 1: Einführung und Anforderungen sagt:

    [...] MVC Design Pattern und Zend_Controller [...]

  2. Andre sagt:

    Hallo,
    freue mich schon auf den weiteren verlauf. Endlich mal etwas in Step by Step und das noch beim genz frischen Zend Framework. Klasse ;)

  3. Ralf Eggert sagt:

    Hallo Andre,

    freut mich, dass dir das Tutorial weiter hilft. Das Tutorial wird durch die Schritt-für-Schritt Anleitung zwar etwas umfangreicher, aber ich hoffe, dass dadurch mehr Leute den Weg zum Zend Framework finden. Also bitte weiter sagen... ;-)

    Gruß,

    Ralf

  4. Patrick Rudolph sagt:

    Hallo Ralf,

    erstmal klasse, dass du dieses Tutorial schreibst.
    Bei mir scheint aber etwas nicht so zu funktionieren wie es soll:
    Wenn ich z.B. eine URL wie http://localhost/travelloblog/article aufrufe erhalte ich nur eine Fehlermeldung vom Webserver, dass das Objekt nicht gefunden wurde. Habe XAMPP installiert, rewrite_module ist geladen und auch sonst hab ich alle Schritte nach deiner XAMPP-Anleitung befolgt. Wo liegt der Fehler?

    Vielen Dank
    Patrick

  5. Ralf Eggert sagt:

    Hallo Patrick,

    kannst du bitte mal die genaue Fehlermeldung hier rein kopieren? Vielleicht kann ich daran schon etwas erkennen.

    Danke und Gruß,

    Ralf

  6. Patrick Rudolph sagt:

    Objekt nicht gefunden!

    Der angeforderte URL konnte auf dem Server nicht gefunden werden. Sofern Sie den URL manuell eingegeben haben, überprüfen Sie bitte die Schreibweise und versuchen Sie es erneut.

    Sofern Sie dies für eine Fehlfunktion des Servers halten, informieren Sie bitte den Webmaster hierüber.
    Error 404
    localhost
    09/07/06 14:04:37
    Apache/2.2.0 (Win32) DAV/2 mod_ssl/2.2.0 OpenSSL/0.9.8a mod_autoindex_color PHP/5.1.1

  7. Andre sagt:

    Hallo Patrick,

    befolge mal Ralf schritte mit dem verkürzen der URL.
    Bei mir ging es danach ;)Xampp ist da irgendwie eigen.

  8. Daniel Henninger sagt:

    Hallo Patrick,

    lad mal die gezippte Datei runter, und entpacke Sie. Anschließend Deine alten Verzeichnisse und Inhalte ersetzen und die entsprechenden Pfade anpassen.

    Ich habe meiner Meinung nach auch alles nach Anleitung durchgeführt und den gleicehn Fehler wie Du gehabt. Bei mir hat es dann geholfen.

    Vermutlich im Tut irgendwo ein Fehler...

    Gruß,
    Daniel

  9. Daniel Henninger sagt:

    Freue mich schon aufs nächste Tutorial. Danke.

  10. Ralf Eggert sagt:

    Hallo Patrick,

    das Problem ist etwas sonderbar. Mir ist aber aufgefallen, dass du PHP 5.1.1 verwendest. Das Zend Framework setzt in Version 0.1.5 jedoch PHP 5.1.4. Kann das Problem lösen, muss es aber nicht.

    Dann war in meiner Xampp Anleitung noch ein kleiner Fehler, den ich eben danke Daniels Hinweis korrigiert habe. In der "/xampp/apache/bin/php.ini" muss nämlich folgendes stehen (da fehlt vorher das "=" Zeichen):

    include_path = ".;C:\xampp\php\pear\;..\application\config\"

    Außerdem kann es sein, dass du evtl. noch ein zweite Zeile in der "/xampp/apache/conf/httpd.conf" auskommentieren musst. Ich habe den Abschnitt über Xampp noch ein wenig aktualisiert. Schau dort am besten noch mal rein.

    Wenn das auch alles nichts hilft, hast du mal den Tipp von Daniel probiert und dir das aktuelle Zip File downgeloadet und geprüft, ob es dann läuft?

    Gruß,

    Ralf

  11. Patrick Rudolph sagt:

    Tja, also das aktuelle ZIP hab ich installiert, die 0.1.5-Version des Frameworks reinkopiert, die Pfade angepasst, aber keine Besserung. Wenn ich einen Virtual Host einrichte, bekomme ich einen 403-Fehler. Auch sehr seltsam.
    Hab mir deine Anmerkungen zu XAMPP nochmal angesehen. In meiner httpd.conf gibt's keine Zeile AddModule mod_rewrite.c. Wenn ich sie einfüge, startet der Apache nicht mehr.

    Gruß,
    Patrick

  12. Ralf Eggert sagt:

    Hallo Patrick,

    welche Xampp Version verwendest du denn? Ich habe das Ganze auf der 1.5.3a Version getestet, in der u.a. PHP 5.1.4 enthalten ist. Anhand der Fehlermeldung war nur zu erkennen, dass du PHP 5.1.1 verwendest?

    Mit der Xampp Version 1.5.3a lief das Ganze bei mir unter Windows XP Home auf jeden Fall problemlos.

    Gruß,

    Ralf

  13. Patrick Rudolph sagt:

    Hallo Ralf,

    ich benutze XAMPP 1.5.1. Werde mir heute mal ein Update ziehen und probieren ob es dann klappt.

    Gruß
    Patrick

  14. Patrick Rudolph sagt:

    Hallo Ralf,

    Installation von xampp 1.5.3a hat das Problem behoben. Vielen Dank für die Unterstützung.

    Gruß
    Patrick

  15. Ralf Eggert sagt:

    Hallo Patrick,

    danke für die Infos. Gut zu wissen, dass es daran gelegen hat. Ich aktualisiere gleich mal die Hinweise für Xampp User in dem anderen Kapitel.

    Gruß,

    Ralf

    P.S. Morgen gibt es endlich wieder einen neuen Teil des Tutorials :-)

  16. Ralfs PHP Blog » Zend Framework Tutorial Teil 2: Systemaufbau mit Bootstrap Datei und der Zend Basisklasse sagt:

    [...] Basisklasse, Zend Framework, Zend Framework Tutorial, ZF Tutorial Bookmark: del.icio.us yigg.de mister-wong.de  [...]

  17. Ralfs PHP Blog » Zend Framework Tutorial Teil 4: MVC Design Pattern und Zend_Db sagt:

    [...] Im dritten Teil des Zend Framework Tutorials haben wir das Model-View-Controller Entwurfsmuster kennen gelernt. Basierend auf der Komponente Zend_Controller haben wir dann unsere Controller Klassen für unser TravelloBlog erstellt. Wenn du die ersten drei Teile noch nicht gelesen hast, hole dies bitte schnell nach. [...]

  18. Wolfgang sagt:

    Hallo Ralf,

    will mal kurz Feedback geben. Bis jetzt ist alles sehr gut zu verstehen. Echt toll dass du dir die Mühe machst, zu diesem brandneuen Framework ein Tutorial zu schreiben.

    Warte schon sehnsüchtig auf die neuen Teile. Mach weiter so.

    Gruß
    Wolfgang

  19. Ralf Eggert sagt:

    Danke Wolfgang,

    falls noch nicht entdeckt, der aktuellste Teil ist heute morgen erst erschienen:

    http://www.ralfeggert.de/2006/09/18/zend-framework-tutorial-mvc-design-pattern-zend_view/

    Viele Grüsse,

    Ralf

  20. Torsten sagt:

    Hallo Ralf,

    vorweg, ein klasse Tutorial!

    Ich hab da ne Frage zum Programmierstil.
    Wiso wird eigentlich die Zeile 7 in der index.php
    $dir = '../application/controllers';
    nicht in config ausgelagert?

    Torsten

  21. Ralf Eggert sagt:

    Hallo Torsten,

    die Konfigurationsdaten sind in der Tat derzeit noch wild verstreut. Das wird aber noch verbessert. In Teil 10 werde ich Zend_Config vorstellen und dann wird das alles aufgeräumt. Schau mal in die Übersicht hier, dann siehst du es.

    http://www.ralfeggert.de/2006/09/04/zend-framework-tutorial-teil-3-mvc-design-pattern-und-zend_controller/#comments

    Natürlich könnte ich jetzt schon Zend_Config vorstellen, aber ich wollte erst einmal die Basis des MVC Konzeptes realisieren. Vielleicht ziehe ich den Zend_Config Teil aber auch noch vor.

    Gruß,

    Ralf

  22. Torsten sagt:

    Hi Ralf,

    Ahja, ok, dann war ich wohl etwas zu voreilig :)
    Wollte nur sicher gehn ob ich mit meinen Überlegungen richtig liege.

    Torsten

  23. Torsten sagt:

    Hi,

    Was mir ein wenig fehlt in diesem Teil des Tutoriums, wäre zusätzlich zu "Benötigte Controller und Aktionen ermitteln" ein Klassen Diagramm mit allen Assoziationen. Im 4. Teil gibts ja ein Datenbank Diagramm, welches mir eine gute Übersicht gegeben hat. Wäre schön wenn es sowas auch für die Klassen gebe. Aber das soll nur ein Vorschlag am Rande sein, ansonsten ist dieses Tutorial super! Man kann es nicht oft genug sagen :)

    Torsten

  24. Ralf Eggert sagt:

    Hi Torsten,

    in einem Klassendiagramm für Controller würde nicht so viel zu erkennen sein, weil die Controller voneinander in der Regel unabhängig sind. Man kann zwar aus einer Aktionsmethode des einen Controllers auf eine andere Aktionsmethode eines anderen Controllers umleiten, aber das lässt sich schwer darstellen. Es sei denn, du hast eine Idee, wie man das machen könnte.

    Gruß,

    Ralf

  25. Ralfs PHP Blog » Zend Framework Tutorial Teil 5: MVC Design Pattern und Zend_View sagt:

    [...] Vielleicht erinnerst du dich noch an die Komponente Zend_Controller_RewriteRouter, die wir im dritten Teil des Tutorials schon kurz betrachtet haben. Der RewriteRouter stellt genau die Methode getRewriteBase() bereit, die wir nun brauchen. Jetzt stehen wir vor dem nächsten Problem, denn wir können wir im Controller auf eine Instanz des Routers zugreifen? [...]

  26. Matthias Hof sagt:

    Hallo zusammen,

    bei mir funktioniert der IndexController wunderbar, nur die anderen nicht.
    Hab kein Xampp, sonderen nen normalen Apache 2.0 und PHP version 5.1.6.
    mod_rewrite ist ebenfalls an.
    Bekomme beim Aufruf auf den Article Controller nen 404 Meldung.

  27. Ralfs PHP Blog » Zend Framework Tutorial Teil 7: MVC Design Pattern für weitere Controller sagt:

    [...] Bereits im dritten Teil dieses Tutorials haben wir bereits die Zend_Controller_RewriteRouter Komponente kennen gelernt. Wir schauen uns dafür einmal einen Ausschnitt aus der aktuellen Bootstrap Datei an, die sich im Verzeichnis "/travelloblog/public/" befindet: Quellcode (klicken) PHP: [...]

  28. Axel sagt:

    Dasselbe geschieht bei mir. Ich habe das ganzeTutoruíal heruntergeladen und versuche es mit ZF 0.6.0/XAMPP zum Laufen zu bekommen.

    Meine URL ist http://localhost/WebDev/_demo

    Der IndexController wird aufgerufen. Aber das Redirect von IndexController auf ArticleController führt auf ein 404 (das vom Apache, nicht vom Tutorial).

    In ZF 0.6.0 gibt es keine Funktion Zend_RewriteRouter::setRewriteBase() mehr.

    Ich habe daher in der Bootstrap-Datei das BaseDirectory über den FrontController gesetzt: $controller->setBaseUrl('/WebDev/_demo');

    In der settings.php habe ich in der Funktion getRewriteBase erst mal die BaseURL fest gesetzt: $url = '/WebDev/_demo';

  29. Ralf Eggert sagt:

    Hallo Axel,

    das Tutorial setzt noch die alte Version 0.2.0 voraus. Bisher bin ich noch nicht dazu gekommen, die umfangreichen Änderungen ins Tutorial einzuarbeiten. Bitte habe noch ein wenig Geduld.

    Gruß,

    Ralf

  30. Dino Knoll sagt:

    @Axel:

    Ich glaub nicht, dass /WebDev/_demo dein absoluter Pfad ist ;)
    Schau dir das nochmal an.

    Gruß

  31. Axel sagt:

    Ooops, ja, Danke Dino. Es ist nur /_demo. So einfach kann das Leben manchmal sein ;=)

  32. Martin Lemke sagt:

    Nachdem mit mod_rewrite nun die Umleitung aller URLs auf /public/index.php funktioniert:

    .htaccess:
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule .* index.php

    stutze ich, dass es nun in Teil 3 erforderlich sein soll, dass es nicht funktionieren, wenn ich http://zf.maaaddin.de/foo eingebe.

    Bei mir wird nun alles auf /public/index.php umgeleitet. Auch die nicht existierende Adresse. Also erscheint bei mir bei Aufruf der URL http://zf.maaaddin.de/foo/bar die Ausgabe:

    IndexController::indexAction()

    Wo muss ich nun der Fehler suchen? In meiner zf-Installation oder ist meine .htaccess ungeeignet?

    Nach Installation von Zend_Controller_RewriteRouter in /public/index.php erfolgt beim Aufruf von http://zf.maaaddin.de/foo nicht wie im Tutorial angegeben die Fehlermeldung

    Zend_Controller_Dispatcher_Exception: "foo" controller does not exist

    sondern nach wie vor: IndexController::indexAction()

    Daran ändert auch die Erweiterung des IndexController nichts.

    Ich kann mir vorstellen, dass das gesamte Controller-System nicht funktionieren kann, wenn -- wie bei mir -- alle Anfragen bei IndexController::indexAction() landen.

    Wo könnte es haken?

    (php 5.1.4, ZF 0.6.0, Apache 1.3)

    Martin

  33. Martin Lemke sagt:

    Kurioser Nachtrag:

    Aufruf http://zf.maaaddin.de/foo

    -> IndexController::indexAction()

    Aufruf http://zf.maaaddin.de/poo

    ->
    Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with message '"poo" controller does not exist' in /kunden/85977_23552/libraries/Zend.php:229 Stack trace: #0 /kunden/85977_23552/libraries/Zend/Controller/Dispatcher.php(386): Zend::exception('Zend_Controller...', '"poo" controlle...') #1 /kunden/85977_23552/libraries/Zend/Controller/Front.php(725): Zend_Controller_Dispatcher->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http)) #2 /kunden/85977_23552/webseiten/subdomains/maaaddin/zftutorial/public/index.php(17): Zend_Controller_Front->dispatch() #3 {main} thrown in /kunden/85977_23552/libraries/Zend.php on line 229

    Ich verstehe das nicht.

    Martin

  34. Martin Lemke sagt:

    Einen Tag habe ich darüber gebrütet und wie immer: Kaum poste man darüber, fällt der Groschen oder man findet den Fehler.

    Es funktioniert jetzt wie erforderlich.

  35. Hans Körting sagt:

    Hallo Martin,

    und wieso funktioniert es jetzt?

  36. Bernd sagt:

    Erst mal: Super Tutorial, gefällt mir sehr gut.

    Ein Tipp für die, die bereits Version 0.8 des Frameworks benutzten: In dieser Version wurde "Zend_Controller_RewriteRouter" zu "Zend_Controller_Router_Rewrite" umbenannt. Also einfach den Namen austauschen, dann geht's auch mit der Version.

  37. Antje sagt:

    Wie versprochen hier noch einige Anmerkungen zum Update auf Version 0.9 für das Kapitel 3:

    Soweit ich gelesen habe, gibt es die Klasse "Zend" in der Version 0.9 nicht mehr und somit kann man den folgenden Code in der index.php weglassen:

    require_once('set_include_path.php');

    Um Klassen zu laden gibt es nun die Klasse "Zend_Loader" und deren statische Methode "loadClass()"

    Zend_Loader::loadClass('Zend_Controller_Front');

    Zum Abschnitt *Zend_Controller_Rewrite_Router* und *Falsche Routen abfangen*:

    Auch hier hat sich etwas in der Version 0.9 geändert. Anstatt der obigen Klasse gibt es nun die Klasse "Zend_Controller_Router_Rewrite". Für die Aufgabe der Umleitung aller Anfragen auf den IndexController kann man aber diese Klasse weglassen. Mit einem einfachen:

    $controller->setParam('useDefaultControllerAlways', true);

    werden alle Anfragen automatisch auf den IndexController umgeleitet. Somit sieht meine Version der php-datei dann so aus:

    setRouter($router);
    $controller->setControllerDirectory($dir);
    $controller->throwExceptions(true);
    $controller->setParam('useDefaultControllerAlways', true);

    $controller->dispatch();
    ?>

    Wenn man "$controller->setParam('useDefaultControllerAlways', true)" wegläßt und im Browser z.B. travelloblog/grosser/unsinn eingibt, bricht das Programm ab (so soll es ja auch sein, weil wir keinen Controller mit dem Namen "Unsinn" programmiert haben. Eigentlich sollte nun eine Exception ausgegeben werden, da ja $controller->throwExceptions(true) gesetzt wurde. Doch leider hat das bei mir nicht funktioniert. Mein Browser streikt, rödelt eine Weile herum und gibt nur einen weissen Bildschirm aus (obwohl eigentlich ein Text mit der geworfenen Exception - so was wie "Exception->__construct('Invalid controller specified (unsinn)')" ausgegeben werden sollte - das weiß ich, weil mir xdebug diesen Fehler ins tracefile schreibt). Habe in der php.ini display_errors eingeschaltet und error_reporting = E_ALL gesetzt. Vielleicht kann ja einer von Euch dazu etwas schreiben.

  38. Antje sagt:

    Bitte meine Anmerkungen zum Abschnitt *Zend_Controller_Rewrite_Router* und *Falsche Routen abfangen* vergessen. Bin nun mit der Zeit auch schlauer geworden (zumindestens was diese Thema betrifft). Auf folgender Seite gibt eine interessante Diskussion über Ersatzmöglichkeiten der nonRouteAction():
    http://www.zfforum.de/showthread.php?p=3785#post3785

    Überhaupt ist die obige Seite SEHR zu empfehlen. Viele Fragen zu neuen Versionen des zf und werden dort beantwortet.

    Wen es interessiert, warum meine Exception nicht angezeigt wurden: in meiner php.ini stand:

    log_errors = On -> alle Fehler werden in eine Logdatei geschrieben und nicht am Bildschirm ausgeben

    Mußte ich selbst erst lernen: log_errors und display_errors beeinflussen sich gegenseitig. D.h. steht in der php.ini zuerst display_errors = On (also alle Fehler / Exceptions werden am Bildschirm angezeigt) und weiter unten dann log_errors = Off, überschreibt log_errors = Off die Einstellung von display_errors = On. Es werden also alle Fehler / Exceptions / Notices in die Log-Datei geschrieben und nicht angezeigt, was dann die Ursache der ungeliebten weißen Seiten ist.

  39. Maik sagt:

    Hallo,

    super Sache dieses Tutorial, auch wenn es schon etwas betagt und teilweise Änderungen im Code erfordert. Das ändert aber nichts daran, das hier die Grundlagen für das Framework anschaulich erklärt werden, daher sind diese Seiten für einen PHP-Entwickler Gold wert. Danke Ralf.

    Allerdings hab ich hier nun ein kleines Problem, das ich alleine bisher nicht lösen konnte. Ich verwende die Produktiv-Version des Frameworks, also 1.0.0. Anscheinend hat das Framework im Laufe der Entwicklung sehr viele Änderungen an der Basis durch gemacht, daher auch die verschiedensten Feedbacks. Meines betrifft das Feature des automatischen Renderns durch das Zend_View. Ich bekomme immer, wenn für den Controller kein .phtml im views/scripts-Ordner liegt eine Exception. Meine Frage an der Stelle: Ist das normal? Bislang behelfe ich mir immer, in dem ich einfach für jeden Controller ein leeres File anlege. Ist dieses Vorgehen korrekt? Es resultiert zu mindest in einem funktionerenden Ablauf.

  40. Maik sagt:

    Sorry, ich hab das Problem mittlerweile selbst lösen können, es gibt einen Parameter, mit dem man das View-Rendering abschalten kann:

    $controller->setParam('noViewRenderer', true);

    Allerdings fang ich grad erst an, mich mit dem Zend-Framework auseinander zu setzen, und noch keine Ahnung, welche Auswirkungen das haben wird.

  41. Robert sagt:

    @Ralf: Super Tutorial!!!

    Ich habe ein ähnliches Problem wie Maik & Martin Lemke ....

    Meine Index & Error Controller laufen. Aber mein Article Controller will einfach nicht.

    Es kommt die Fehlerseite. Ein paar neue Methoden im Index Controller haben das gleiche Problem verursacht... Ich habe einfach mal IndexController->showAction eingebaut ... dann sollte ein Aufruf /index/show ja eigentlich showAction aufrufen, aber auch da immer nur die Fehlerseite ....

    so long
    - Robert

  42. Maik sagt:

    @Robert: Zeig doch mal deine Bootstrap insb. den Teil mit dem Router-Part. Welche Version des FW verwendest du denn?

  43. Thomas sagt:

    @Robert: Möglicherweise musst du erst im Verzeichnis application/views/scripts einen Ordner article/ anlegen und für jede Funktion eine .phtml Datei anlegen, z.B. in deinem Fall show.phtml. Bei mir hat das jedenfalls geklappt.

  44. Maik sagt:

    Oder man schaltet das automatische Rendering ab:

    $controller->setParam('noViewRenderer', true);

  45. Maik sagt:

    @Dan, wie sieht denn deine Verzeichnisstrukur aus? Wie lautet der Include-Pfad?

    Du kannst den Include-Pfad vor dem Einbinden der Loader.php prüfen, in dem du

    echo get_include_path();

    aufrufst und das Ergebnis kontrollierst. Der Include-Pfad sollte ebenfalls einen Eintrag auf den Ordner haben, in dem du das Framework entpackt hast.

  46. Maik sagt:

    Ich brauch den Zend_Loader eigentlich nur in meiner __autoload-Funktion, ich hab da so gelöst:

    site
    |-> application
    | |
    | | -> config
    | | |-----> autoload.php
    | | |-----> setpath.php
    | |
    | | -> controllers
    | | -> models
    | | -> views
    | | -> plugins
    |
    |-> library
    | |
    | |-> Zend
    | |-> Custom
    | |-> Smarty
    |
    |-> templates
    |
    |-> cache
    |
    |-> index.php

    In der autoload ist folgender Code drin:

    Die setpath.php sieht so aus:

    Meine Bootstrap (index.php) ist so aufgebaut:

    Das ist die einfachste Variante. Vielleicht bringt dich das auf ne Idee.

    Zu deinen Fragen:

    1. Ja. Der 2. Parameter kann ein Array aus Pfadangaben sein.
    2. Jain, er nimmt den include_path trotzdem, auch wenn da Pfade angegeben sind.
    3. Der Router ist dafür gedacht, die Angaben aus der URL zu extrahieren, den entsprechenden Controller zu holen und darin die geforderte Methode aufzurufen:

    http://www.schnick.de/schnack/schnuck

    Würde an den SchnackController leiten und dort die Methode (Action) schnuckAction() aufrufen. Du müsstest also unter application/controllers eine Datei "SchnackController.php" haben, die ungefähr so aussieht:

    Hoffe geholfen zu haben.

  47. Florian sagt:

    statt:
    $this->getResponse()->setBody($this->view->render('main.phtml'));
    lässt sich in ZF ab 1.0.0. zum rendern der main.phtml folgendes machen:
    $this->_helper->viewRenderer('main');
    Hat den Vorteil, den automatischen viewRenderer nicht mehr abschalten zu müssen. Zu beachten ist dann aber, dass die main.phtml dann nicht mehr im Verzeichnis /scripts sondern in /scripts/article liegen muss

  48. Robert sagt:

    @Maik: ich verwende noch keinen Router. Ich verwende ZF 1.0.

    @Thomas: Danke für den Tipp. Damit funktioniert es.

  49. slava sagt:

    Zend_Controller_RewriteRouter
    heist jetzt
    Zend_Controller_Router_Rewrite

  50. mentor sagt:

    hm..
    bekomme diesen Fehler hier

    Warning: Zend_Loader::require_once(Zend/Exception.php) [function.Zend-Loader-require-once]: failed to open stream: No such file or directory in D:\xampp\htdocs\cms\library\Zend\Loader.php on line 158

    weiss jemand Rat?

  51. mentor sagt:

    require_once('set_include_path.php');
    if (!class_exists('Zend')) require_once 'Zend.php';
    Zend::loadClass('Zend_Controller_Front');

    $dir = '../application/controllers';

    $controller = Zend_Controller_Front::getInstance();
    $controller->setControllerDirectory($dir);
    $controller->throwExceptions(true);
    $controller->dispatch();

    In der ZF 1.0.2
    ============================

    require_once('set_include_path.php');
    if (!class_exists('Zend-Loader')) require_once 'Zend/Loader.php';

    $dir = '../application/controllers';

    Zend_Loader::loadClass('Zend_Controller_Front');
    Zend_Controller_Front::run($dir);

  52. Maik sagt:

    @mentor: Ich möchte nicht auf die neue Version updaten. Aber funktioniert es noch genauso mit der alten Art und Weise mittels dispatch()? Wenn nicht hat Zend hier einen großen Fehler gemacht. Danke für die Info.

  53. Jessica sagt:

    Hallo, ich bis jetzt das Turtorial gut gemeistert, leider habe ich jetzt ein problem, nämlich wenn ich http://travelloblog/article eingebe, bekomme ich die Meldung, dass die Webseite nicht gefunden wurde...

  54. Carsten sagt:

    >Thomas:
    >@Robert: Möglicherweise musst du erst im Verzeichnis application/views/scripts einen >Ordner article/ anlegen und für jede Funktion eine .phtml Datei anlegen, z.B. in deinem >Fall show.phtml. Bei mir hat das jedenfalls geklappt.

    Ich bin jetzt neu mit Zend Framework 1.5 eingestiegen und habe ebenfalls wie Thomas feststellen müssen, das im Verzeichnis "application/views/scripts" ein Ordner "article" angelegt werden muß sowie für jede Funktion jeweils eine "*.phtml"-Datei (z.B. show.phtml).

    Allerdings erhalte ich bei den Funktionen, wo im Funktionsname ein großer Buchstabe vorkommt (z.B. "showAmazon"), so erhalte ich die folgende Fehlermeldung:

    Fatal error:
    Uncaught exception 'Zend_Controller_Action_Exception' with message 'Action "showamazon" does not exist and was not trapped in __call()' in C:\Programme\xampp\htdocs\travelloblog\library\Zend\Controller\Action.php:477
    Stack trace: #0 C:\Programme\xampp\htdocs\travelloblog\library\Zend\Controller\Action.php(504): Zend_Controller_Action->__call('showamazonActio...', Array)
    #1 C:\Programme\xampp\htdocs\travelloblog\library\Zend\Controller\Dispatcher\Standard.php(293): Zend_Controller_Action->dispatch('showamazonActio...')
    #2 C:\Programme\xampp\htdocs\travelloblog\library\Zend\Controller\Front.php(914): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
    #3 C:\Programme\xampp\htdocs\travelloblog\public\index.php(21): Zend_Controller_Front->dispatch()
    #4 {main} thrown in C:\Programme\xampp\htdocs\travelloblog\library\Zend\Controller\Action.php on line 477

    By the way: Da ich gerade in der Einarbeitung von Zend Framework bin, wollte ich mal fragen, ob Interesse besteht, an einem Tutorial für die Version 1.5 ?
    Vielleicht kann man ja mit Unterstützung von Ralf Eggert und anderen Usern das ganze Projekt auf 1.5 portieren !?

  55. Carsten sagt:

    > Maik meint: Hinzugefügt am 8. Juli, 2007 um 21:10 Uhr
    > Sorry, ich hab das Problem mittlerweile selbst lösen können, es gibt einen Parameter, mit > dem man das View-Rendering abschalten kann:
    > $controller->setParam('noViewRenderer', true);
    > Allerdings fang ich grad erst an, mich mit dem Zend-Framework auseinander zu setzen, und > noch keine Ahnung, welche Auswirkungen das haben wird.

    Ein Nachteil beim Ausschalten des Renderings ist der, das die Titelleiste im Browser (hier: "Travello-Blog") immer verschwindet. Denn das ist ja unter Umständen auch nicht gewünscht.

  56. Lukas sagt:

    Hallo Ralf,

    sehr gutes Tutorial, wirklich! Auch wenn ich das Zend Framework selbst nicht benutze, so bekommt man doch ein gutes Gefühl, wie eine komplexe PHP-Anwendung unter der Decke aussehen kann.

  57. Marco sagt:

    ....
    Die Verarbeitung der Geschäftslogik bleibt ausschließlich der Controller Komponente vorenthalten.
    .....
    Müsste es nicht "vorbehalten" heißen?

Hinterlasse eine Antwort