Quicknavi |
|
PHP-Frameworks im Test (5)
3.3. Zend Framework
3.3.1. Allgemeines
Roadmap des Projekts
Das Zend Framework stellt unter http://framework.zend.com/whyzf/future/ seine
Roadmap für die zukünftigen Releases vor. Ein konkreter Release-Plan fehlt jedoch genauso
wie ein Zeitplan für das erscheinen der aufgezeigten Features.
Aktualität der Version
Die Seite http://framework.zend.com/download gibt eine Übersicht über
die letzten 6 Releases, die jeweils im Abstand zwischen 10 und 30 Tagen erfolgten. Das aktuelle
Release, mit dem auch beim Verfassen dieses Artikels zurückgegriffen wurde ist 1.0.1 vom
30.07.2007.
Release-Packages in verschiedenen Formaten
Das Release-Package ist in den Varianten ZIP und TGZ verfügbar. Die Dokumentation wurde seit dem
Release 1.0.0 RC2 aus dem Release-Package ausgegliedert. Die aktuelle Version der Dokumentation kann
unter http://framework.zend.com/manual eingesehen werden.
CVS/SVN-Repositories
Unter http://framework.zend.com/download/subversion/ ist beschrieben, wie der
Entwickler eine Kopie des SVN-Repositories, bzw. "nighly builds" beziehen kann. Damit ist
gewährleistet, dass Bugfixes schnell verfügbar sind.
Bug-Tracking / Ticketing
Der Bug-Tracker http://framework.zend.com/issu...board.jspa war
während der Zeit der Evaluierung nicht durchgängig verfügbar und der Aufruf wurde oft
mit einem Fehler 502 quittiert. Der Autor geht davon aus, dass das Zend Framework über einen
funktionierenden Bug-Tracker verfügt, da Jira über ähnliche Features wie das Software-
Paket Trac verfügt.
Version für PHP 4
Eine Version für PHP 4 ist nicht erhältlich.
Version für PHP 5
Die installierte Version ist zu PHP 5 (im Test: Version 5.2.1) kompatibel. Um das Zend Framework betreiben
zu können wird eine PHP Version > 5.1.2 vorausgesetzt.
3.3.2. Installation
Extract & Go
Die Installation des Frameworks gestaltet sich erwartungsgemäß einfach. Nach dem Extrahieren
des Paketes kann der Anwender mit der Implementierung seiner ersten Anwendung beginnen. Auch bei
diesem Framework wurde ein lokaler VHOST angelegt um z.B. URL-Rewriting sauber testen zu können.
Es fällt jedoch sofort auf, dass das Zend Framework keine Beispiel-Applikation oder eine Startseite
mit wichtigen Hinweisen im Release mitbringt.
Konfiguration
Der Einsteiger stößt nach einer Weile des Suchens auf ein Einsteiger-Tutorial, das zeigt,
wie eine Anwendungsstruktur und eine "Hallo-Welt"-Applikation erstellt werden kann. Hinsichtlich
Konfiguration beschreibt http://framework.zend.com/manu...troduction
dass die Zend Framework Bibliotheken via PHP include_path erreichbar sein müssen.
Dieser muss entweder global oder in der Bootstrap-Datei der Applikation gesetzt sein. Für den
Test entschied sich der Autor für die zweite Alternative.
Weiterhin muss die Bootstrap-Datei (/myapp/html/index.php) die benötigten Bibliotheken
laden, im Fall der beschriebenen Beispiel-Applikation ist das der Zend Framework FrontController.
Dieser kann nach dem Setzen des include_path's per
require_once 'Zend/Controller/Front.php';
eingebunden werden.
3.3.3. Erste Schritte
Demo-Software
Weder das Release-Package noch das Wiki beinhalten eine einfache Demo-Software, mit dem der Anwender
einen ersten Einblick in die Funktionsweise und die Anwendung des Frameworks bekommen kann.
Einführung / Quickstart
Da kein ausgewiesenes Einsteiger-Tutorial auf der Seite framework.zend.com verfügbar ist, versuchte
der Autor über das Wiki ein für Einsteiger relevantes Tutorial zu finden. Nach einer Recherche
konnte http://akrabat.com/zend-framework-tutorial/ ausgemacht werden. Das dort
verfügbare Einsteiger-Tutorial, das auch in Deutsch erhältlich ist, beschreibt das Erstellen
einer einfachen CD-Verwaltung in für Einsteiger nachvollziehbaren Schritten.
3.3.4. Erstellung einer Webseite
Template-Bau / Layoutgestaltung
Das unter 3.3.3 genannte Tutorial gibt erste Einblicke in die Art und Weise des Template-Baus, die
nun zur Erstellung der Demo-Seite verwendet werden können. Dazu wird unter einem neuen Ordner
(/myapp) eine Strukur für die Applikation gemäß
http://framework.zend.com/manu...troduction
angelegt. Auch das Zend Framework verfolgt die Philosophie, dass die URL gemäß dem Pattern
http://www.example.com[/{Module}]/{Controller}/{Action}[/{Param1}/../{ParamN}]
aufgebaut ist. Der Einfachheit wegen wird die Demo-Seite ohne die Verwendung der Modul-Logik aufgebaut.
Zunächst muss unter /myapp/html eine index.php mit folgendem Inhalt
angelegt werden:
// Set include_path set_include_path(get_include_path().';'.'***/zendtest.de/library');
// Run FrontController require_once 'Zend/Controller/Front.php'; $fC = Zend_Controller_Front::getInstance(); $fC->throwExceptions(true); $fC->setControllerDirectory('../application/controllers'); $fC->dispatch();
Die Aktivierung des Parameters throwExceptions des Frontcontrollers ist dabei von
großer Bedeutung für Anfänger, da der FrontController sonst nur Meldungen der Form
Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with message
'Invalid controller specified ...
wirft und keinen Hinweis auf den eigentlichen Fehler ausgibt.
Auf Grund des gewünschten URL-Designs wird nun unter /myapp/application/controllers die
Datei SeiteController.php mit der Klasse SeiteController angelegt. Der darin
enthaltene Action-Controller erbt von der Klasse Zend_Controller_Action. Das Grundgerüst
sieht wie folgt aus:
class SeiteController extends Zend_Controller_Action {
// Abfangen von falschen / nicht vorhandenen Actions function __call($method, $args){
// indexAction if($method == 'indexAction'){ return $this->render('startseite'); // end if }
// return error page return $this->render('error');
// end function }
// end class }
Die Methode __call() wird verwendet um Standard- und Fehler-Fälle abzufangen. Im hier
aufgezeigten Fall wird die Fehlerseite angezeigt, falls es keine anzeigbare Seite gibt. Die View-
Templates wurden im Ordner /myapp/application/views/scripts/seite angelegt und mit der Endung
.phtml versehen. Um nicht bei jeder Seite den Quellcode des Headers, des Menüs,
des News-Bereichs, des Top-Menüs und des Footers kopieren zu müssen wurden diese Teile in
den Ordner /myapp/application/views/scripts/seite/design ausgelagert. Dort existieren nun
fünf Dateien:
-
header.phtml: Beinhaltet den Teil vor dem Content-Bereich. Inkludiert
News, Top-Menü und Menü.
- news.phtml: Newsbereich der Seite
- topmenu.phtml: Horizontales Menü im oberen rechten Bereich
- menu.html: Haupt-Menü in linken mittleren Bereich
- footer.phtml: HTML-Fragmente der Fußzeile der Seite
Wird nun die URL
http://zendtest.de/Seite/Benchmark
aufgerufen, so lädt der FrontController die ActionKlasse SeiteController und führt
die Methode benchmarkAction() aus. Diese ist im Moment noch nicht implementiert und die Fehler-
Seite wird angezeigt. Legt der Benutzer nun die Datei benchmark.phtml im Ordner
/myapp/application/views/scripts/seite an und erweitert den Controller um die Methode
function benchmarkAction(){ }
so wird die Benchmark-Seite angezeigt. Die Template-Datei für die Benchmark-Seite ist dabei wie
folgt aufgebaut:
<?php
$view = new Zend_View();
$view->setScriptPath('../application/views/scripts/seite/design');
// Header ausgeben
echo $view->render('header.phtml');
?>
<font style="font-size: 26px; font weight: bold;">Benchmark</font>
<br />
<br />
[..]
<?php
// Footer ausgeben
echo $view->render('footer.phtml');
?>
Handling von Controllern
Unter Template-Bau / Layoutgestaltung wurde bereits angerissen, wie Controller
im Zend Framework aufgebaut sind und wie sich diese verhalten. Auch wurde bereits vorweg genommen,
wie die Namensgebung der Controller festgelegt ist. Um das im Test gewünschte URL-Format
abbilden zu kännen und um zu erreichen, dass beim Aufruf der URL
http://zendtest.de/
keine Fehlermeldung, sondern die gewünschte Seite angezeigt wird, muss das Standard-Routing
angepasst werden. Hilfestellung dazu bietet das Manual auf der Seite
http://framework.zend.com/manu...ult-routes.
Etwas unter geht hier jedoch die Tatsache, dass die Variable $router eine Referenz
auf die Instanz des Rewrite-Routers sein muss. Die index.php muss dann um die Zeilen
$router = $fC->getRouter();
$default_route = new Zend_Controller_Router_Route( '', array( 'controller' => 'Seite', 'action' => 'index' ) );
$seite_route_default = new Zend_Controller_Router_Route( 'Seite', array( 'controller' => 'Seite', 'action' => 'index' ) );
$seite_route_dynamic = new Zend_Controller_Router_Route( 'Seite/:Action/*', array( 'controller' => 'Seite' ) );
$router->removeDefaultRoutes(); $router->addRoute('default',$default_route); $router->addRoute('SeiteDefault',$seite_route_default); $router->addRoute('SeiteDynamic',$seite_route_dynamic);
zwischen
require_once 'Zend/Controller/Front.php'; $fC = Zend_Controller_Front::getInstance(); $fC->throwExceptions(true);
und
$fC->setControllerDirectory('../application/controllers'); $fC->dispatch();
erweitert werden. Weitere Routing-Einträge können analog dazu eingetragen werden. Hier sind
die Hinweise auf der zuvor referenzierten Manual-Seite zu beachten. Das gewählte Routing
impliziert jedoch weitere Änderungen im Controller. Es war dem Autor nicht möglich sowohl
das Default-Routing als auch das dynamische Routing so zu konfigurieren, dass der Controller in der
oben aufgezeigten Form sowohl für
http://zendtest.de/
als auch für
http://zendtest.de/Seite
oder
http://zendtest.de/Seite/Literatur
die richtigen Views rendert und ausliefert. Der Router unterstützt zwar ein Remapping von URLs,
jedoch kein Remapping von Wildcard-Parametern in die URL-Parameter selbst, so dass der Dispatcher
weiterhin erkennt, dass der zweite Parameter die Action ist. Das Manual (englisch) spricht zwar von
Route definition can contain one more special character a wildcard represented by '*' symbol. It is
used to gather parameters similarly to the default Module route (var => value pairs defined in the
URI). The following route moreorless mimics the Module route behavior:
$route = new Zend_Controller_Router_Route(
':module/:controller/:action/*',
array('module' => 'default')
);
$router->addRoute('default', $route);
, das bewirkt jedoch nur ein Mappen der URL-Pfad-Abschnitte in Request-Variablen, die im
Request-Objekt ausgelesen werden können. Der zweite - bzw. im Beispiel des Manuals
dritte - URL-Parameter wird jedoch nicht automatisch dem Dispatcher als Action-Kenner übergeben.
Daher wurde die __call()-Methode wie folgt umgestellt, so dass diese zunächst
versucht eine Methode für das Rendering aufzurufen, sollte diese nicht vorhanden sein, versucht
den View zu rendern und ansonsten eine Fehler-Seite anzeigt. In PHP-Code gestaltet sich das wie folgt:
public function __call($method,$args){
// Request-Objekt holen $Request = $this->getRequest();
// Action-Parameter holen (muss in Route definiert sein $ActionParam = strtolower($Request->getParam('Action'));
// Request-Methode zusammenbauen $RequestedMethod = $ActionParam.'Action';
// Prüfen, ob Methode existiert und diese dann ausführen if(method_exists($this,$RequestedMethod)){ return $this->$RequestedMethod(); // end if } else{ // Falls lediglich der View existiert, diesen ohne Hilfe einer Action-Methode rendern if(file_exists('../application/views/scripts/seite/'.$ActionParam.'.phtml')){ return $this->render($ActionParam); // end if } // end else }
// Für alle übrigen Fälle Fehler-Seite zeigen return $this->render('error');
// end function }
Etwas ungenerisch ist hierbei die Prüfung gewählt, ob das View-Script existiert. Es wurde
jedoch nicht weiter nach einer Lösung gesucht, da sich die Änderungen auf Grund des
URL-Routings bereits als zeitintensiv erwiesen haben.
Erweiterbarkeit der GUI-Komponenten
Wie auch in den bisherigen Tests befinden sich im Quellcode der Datei benchmark.phtml
neben "normalen" HTML-Tags auch XML-Tags, zwischen den PHP-Codes eingeschlossen sind, die formatiert
auf der Seite dargestellt werden sollen. Dies sind
<php:highlight>
</php:highlight>
für das Highlighting und
<doku:navigation />
für die Darstellung des dynamischen Menüs. Dies beiden Aufgaben können durch Action-Helper
realisiert werden, die dem FrontController bzw. Dispatcher in der index.php bekannt gemacht
werden. Auf der Seite http://framework.zend.com/manu...per.broker
wird diese Möglichkeit entsprechend beschrieben wird. Der Action-Helper muss dabei immer von
Zend_Controller_Action_Helper_Abstract erben und kann die unter
http://framework.zend.com/manu...ingyourown
beschriebenen Methoden implementieren. Im Fall des Formatierens von XML-Tags kommt hier die Funktion
postDispatch() in Frage, da zu diesem Zeitpunkt alle Views gerendert sind und der
HTML-Quelltext im Response-Objekt vollständig vorliegt. Nachteil der Lösung ist jedoch, dass
nicht nur der betroffene ein Teil des Quelltextes (Content-View) durchsucht werden muss, sondern der
komplette Quelltext, was u.U. zu unerwünschten Ergebnissen oder zu schlechter Performance führen
kann. Eine andere Lösung konnte jedoch auch unter
http://www.zfforum.de/showthread.php?t=685 nicht erarbeitet werden.
Die beiden Helper wurden unter /myapp/applications/views/helpers angelegt und mit
Highlight.php und DokuNavi.php benannt. Die Quelltexte der zwei
Helper gestaltet sich wie folgt:
Highlight.php:
require_once 'Zend/Controller/Action/Helper/Abstract.php';
class Helper_Highligh extends Zend_Controller_Action_Helper_Abstract {
function postDispatch(){
// Response-Objekt holen $Response = $this->getResponse();
// Inhalt vom Response-Objekt holen $Body = $Response->getBody();
// PHP-Highlight erzeugen $Body = $this->highlight($Body);
// Body in das Response-Objekt zurückschreiben $Response->setBody($Body);
// end function }
function highlight($content){
// Quelltext parsen return preg_replace_callback( '=\<php\:highlight\>(.*?)\<\/php\:highlight\>=si', array('Helper_Highligh','highlight_it'), $content );
// end function }
function highlight_it($content){
$HighlightedContent = highlight_string(trim('<?php'.ltrim(rtrim($content[1]),"\x0A..\x0D").' ?>'),true);
// PHP-Anfangstag ersetzen $HighlightedContent = str_replace('<font color="#007700"><?</font>', '', $HighlightedContent); $HighlightedContent = str_replace('<font color="#0000BB"><?php ', '<font color="#0000BB">', $HighlightedContent); $HighlightedContent = str_replace('<font color="#0000BB">php', '<font color="#0000BB">', $HighlightedContent); $HighlightedContent = str_replace('<font color="#0000BB"> </font>', '', $HighlightedContent);
// PHP-Endtag ersetzen $HighlightedContent = str_replace('<font color="#0000BB">?></font>','',$HighlightedContent);
// Code im DIV zurückgeben return '<div class="phpcode">'.$HighlightedContent.'</div>';
// end function }
// end class }
DokuNavi.php: (gekürzt)
require_once 'Zend/Controller/Action/Helper/Abstract.php';
class Helper_DokuNavi extends Zend_Controller_Action_Helper_Abstract {
private $__DokuSites = array();
function postDispatch(){
// // Navigation erzeugen //
// Array füllen $this->__fillSitesArray();
// Aktuelle Seite deklarieren $Request = $this->getRequest();
// Action-Parameter holen (muss in Route definiert sein $ActionParam = $Request->getParam('Action'); if($ActionParam == null){ $Page = 'Startseite'; // end if } else{ $Page = $ActionParam; // end else }
// Vorherige Seite deklarieren $PreviousPage = $this->__getNeighborPageName($Page);
// Nächste Seite deklarieren $NextPage = $this->__getNeighborPageName($Page,'next');
// Rückgabe-Puffer deklarieren $Buffer = (string)'';
[..]
// // Ergebnis in Response implantieren //
// Response-Objekt holen $Response = $this->getResponse();
// Inhalt vom Response-Objekt holen $Body = $Response->getBody();
// Ausgabe in Response-HTML-Quelltext einsetzen $Body = str_replace('<doku:navigation />',$Buffer,$Body);
// Body in das Response-Objekt zurückschreiben $Response->setBody($Body);
// end function }
function __fillSitesArray(){ [..] }
function __getNeighborPageName($CurrentPage,$Type = 'previous'){ [..] }
// end class }
Um den Navi-Helper dem Dispatcher bzw. FrontController bekannt zu machen, muss die index.php
wie folgt geändert werden:
require_once '../application/views/helpers/Highlight.php'; require_once '../application/views/helpers/DokuNavi.php'; Zend_Controller_Action_HelperBroker::addPath('../application/views/helpers','Helper'); $Helper_Highlight = new Helper_Highligh(); $Helper_DokuNavi = new Helper_DokuNavi(); Zend_Controller_Action_HelperBroker::addHelper($Helper_Highlight); Zend_Controller_Action_HelperBroker::addHelper($Helper_DokuNavi);
Komplexe Layouts
Die Erstellung einfacher Layouts für eine Webseite konnte sehr einfach beschritten werden. Das
Gestalten von komplexen Layouts scheitert auch hier an der "Ein Controller - eine Action"-Logik im
Bereich der Umsetzung des MVC-Pattern und am URL-Design. So ist es weder möglich einem
eingebundenen View einen Controller zuzuweisen, der dem View dynamisch Inhalte liefert, noch ist
vorgesehen, dass mehrere Front- bzw. ActionController-Actions in der URL deklariert werden können.
Hierzu wurde eine ausführliche Diskussion unter http://www.zfforum.de/showthread.php?t=359
mit dem Ergebnis geführt, dass das Framework bisher keine Möglichkeit vorsieht, ein Layout
mit mehreren und vor Allem unabhängigen Actions für unterschiedliche GUI-Teile zu erstellen.
FormularDesign
Wie auf der Seite http://framework.zend.com/manu...rs.initial
beschrieben ist, kann der Entwickler zur Erstellung von Formularen auf eine Vielzahl von Helper-
Methoden zurückgreifen. Um das hier zu erstellende Formular mit dem Zend Framework nachempfinden
zu können, wird zunächst eine View-Script-Datei mit dem Namen kontakt.phtml
angelegt und eine weitere (danke.phtml) für die Anzeige der Erfolgsmeldung. Die Datei
kontakt.phtml beinhaltet neben den üblichen Bereichen für das Anzeigen von
Header- und Footer-Komponenten den folgenden Quelltext:
<font style="font-size: 26px; font weight: bold;">Kontakt-Formular</font>
<br />
<br />
Wenn Sie mit mir in Kontakt treten möchten, dann benutzen Sie einfach dieses Formular. Geben Sie Ihre
Nachricht ein und schon kann es los gehen. Ich werden mich dann umgehend mit Ihnen in Verbindung
setzten. <strong>Bitte füllen Sie das Formular vollständig aus!</strong>.
<br />
<br />
<form action="<?php echo $this->url(); ?>" method="post">
<span style="width: 47px; border: 0px solid black; margin-right: 69px;">Person:</span>
<?php echo $this->formSelect('Person',
$this->Person,
array(
'class' => 'eingabe_feld',
'style' => $this->PersonStyle
),
array(
'' => '',
'1' => 'Max Mustermann',
'2' => 'Bianka Mustermann'
)
);
?>
<?php echo $this->PersonError; ?>
<br />
<br />
<span style="width: 56x; border: 0px solid black; margin-right: 64px;">Ihr Name:</span>
<?php echo $this->formText('Name',
$this->Name,
array(
'class' => 'eingabe_feld',
'style' => 'width: 280px;'.$this->NameStyle
)
);
?>
<?php echo $this->NameError; ?>
<br />
<br />
<span style="width: 108px; border: 0px solid black; margin-right: 10px;">Ihre eMail-Adresse:</span>
<?php echo $this->formText('EMail',
$this->EMail,
array(
'class' => 'eingabe_feld',
'style' => 'width: 280px;'.$this->EMailStyle
)
);
?>
<?php echo $this->EMailError; ?>
<br />
<br />
<span style="width: 57px; border: 0px solid black; margin-right: 61px;">Ihr Betreff:</span>
<?php echo $this->formText('Subject',
$this->Subject,
array(
'class' => 'eingabe_feld',
'style' => 'width: 280px;'.$this->SubjectStyle
)
);
?>
<?php echo $this->SubjectError; ?>
<br />
<br />
Ihre Nachricht:
<br />
<?php echo $this->formTextarea('Comment',
$this->Comment,
array(
'class' => 'eingabe_feld',
'style' => 'height: 200px;
width: 400px;
overflow: auto;
'.$this->CommentStyle
)
);
?>
<?php echo $this->CommentError; ?>
<br />
<br />
<?php echo $this->formSubmit('Absenden','Absenden',array('class' => 'eingabe_feld')); ?>
</form>
Im Controller wird für das Formular-Handling eine neue Methode mit dem Namen
kontaktAction angelegt, die das Überprüfen der Formular-Eingaben und
das reagieren auf Fehleingaben erledigt. Dabei wird von der Möglichkeit Gebrauch gemacht, dass
dem View beliebige Variablen zur Verwendung durch Setzen der Attribute des aktuellen View-Objekts
zugewiesen werden können. Der Quelltext der Methode ist folgender:
function kontaktAction(){
// View-Variablen setzen $this->view->Person = (string)''; $this->view->Name = (string)''; $this->view->EMail = (string)''; $this->view->Subject = (string)''; $this->view->Comment = (string)'';
// Variablen zur Ausgabe-Steuerung setzen $this->view->PersonStyle = (string)''; $this->view->NameStyle = (string)''; $this->view->EMailStyle = (string)''; $this->view->SubjectStyle = (string)''; $this->view->CommentStyle = (string)'';
// Variablen für Fehlermeldungen setzen $this->view->PersonError = (string)''; $this->view->NameError = (string)''; $this->view->EMailError = (string)''; $this->view->SubjectError = (string)''; $this->view->CommentError = (string)'';
// Prüfen, ob Formular abgeschickt wurde if(isset($_POST['Absenden']) && $_POST['Absenden'] == 'Absenden'){
// Validatoren erstellen $Val_StrLen = new Zend_Validate_StringLength(3); $Val_EMail = new Zend_Validate_EmailAddress();
// Werte des Formulars presetten $this->view->Person = $_POST['Person']; $this->view->Name = $_POST['Name']; $this->view->EMail = $_POST['EMail']; $this->view->Subject = $_POST['Subject']; $this->view->Comment = $_POST['Comment'];
// Post-Daten prüfen $FormValid = true;
if(empty($_POST['Person'])){ $this->view->PersonStyle = ' background-color: red; border: 2px solid red;'; $this->view->PersonError = 'Bitte wählen Sie eine Kontakt-Person aus!'; $FormValid = false; // end if } if(!$Val_StrLen->isValid($_POST['Name'])){ $this->view->NameStyle = ' border: 2px solid red;'; $this->view->NameError = 'Bitte geben Sie einen Namen ein!'; $FormValid = false; // end if } if(!$Val_EMail->isValid($_POST['EMail'])){ $this->view->EMailStyle = ' border: 2px solid red;'; $this->view->EMailError = 'Bitte geben Sie eine korrekte E-Mail-Adresse ein!'; $FormValid = false; // end if } if(!$Val_StrLen->isValid($_POST['Subject'])){ $this->view->SubjectStyle = ' border: 2px solid red;'; $this->view->SubjectError = 'Bitte geben Sie ein Betreff ein!'; $FormValid = false; // end if } if(!$Val_StrLen->isValid($_POST['Comment'])){ $this->view->CommentStyle = ' border: 2px solid red;'; $this->view->CommentError = 'Bitte geben Sie einen Kommentar ein!'; $FormValid = false; // end if }
// Formular absenden, fals Valide ausgefüllt if($FormValid == true){ header('Location: /Seite/Danke'); // end if }
// end if }
// Formular anzeigen $this->render('kontakt');
// end function }
Das Zend Framework bringt - wie unschwer zu erkennen ist - einen Satz von Validatoren mit, die einfach
zur Validierung der Benutzereingaben verwendet werden können. Das Presetting von Benutzer-Eingaben
in Formular-Komponenten muss der Entwickler, genauso wie Markierung von nicht korrekt ausgefüllten
Feldern oder Fehlermeldungs-Ausgaben - trotz Form-Helper - zu Fuß implementieren. Verglichen mit
z.B. CakePHP wird das Formular-Handling nur rudimentär unterstützt und der Template-Bauer
spart sich durch den Einsatz der View-Helper nur wenig Arbeit. Das Presetting von Select-Feldern wird
jedoch im Gegensatz zu den View-Helpern von CodeIgniter durch Übergabe des POST-Wertes
unterstützt.
3.3.5. URL-Handling
Unterstützung von URL-Rewriting
Das Ausliefern der Applikation über Rewriting-URLs wird vom Zend-Framework standardmäßig
unterstützt. Damit alle Anfragen auf die Bootstrapping-Datei weitergeleitet werden muss die
RewriteRule
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
für den VHOST aktiviert werden. Über die Unterstützung von URLs ohne Rewriting wurde
im Manual kein Eintrag gefunden.
Generik des URL-Layouts
Wie bei den bisherigen Test-Kandidaten wird das URL-Layout der Form
http://www.example.com[/{Module}]/{Controller}/{Action}[/{Param1}/.../{ParamN}]
fest vorgeschrieben und kann lediglich durch Routing-Einträge manipuliert, jedoch nicht in seiner
Bedeutung geändert werden.
URL-Manipulations-Tools / Linkgenerierung
Zur Unterstützung der URL-Generierung liefert das Zend Framework die Komponente Zend_Uri
mit. Diese unterstützt aktuell HTTP- und HTTPS-Schemata und kann beispielsweise mit
require_once 'Zend/Uri.php'; $uri = Zend_Uri::factory( 'http://www.zend.com:8180/Module/Controller/Action/Value1/Value2/Value3?param4=val4¶m5=val5' ); $uri->setPath('/Seite/Danke'); $uri->setPort(''); $uri->setHost('www.test.de'); $uri->setQuery('param4=show¶m5=false'); echo $uri->getUri();
die URL
http://www.zend.com:8180/Module/Controller/Action/Value1/Value2/Value3?param4=val4¶m5=val5
zu
http://www.test.de/Seite/Danke?param4=show¶m5=false
verändern. Auffällig ist jedoch, dass Ampersands in URLs nicht codiert werden, was auf
Ausgabe-Seite zum Effekt führen kann dass statt der oben aufgeführten URL
http://www.test.de/Seite/Danke?param4=show¶m5=false
oder jede mögliche andere Kombination von HTML-Entitys ausgegeben werden.
3.3.6. Design des Frameworks
Umfang der mitgelieferten Komponenten
Das Zend Framework besticht in der aktuellen Version durch eine Fülle von Komponenten für
die verschiedensten Anwendungsfälle. Es werden im Paket Klassen für Benutzer-Authentifizierung,
Rechte-Verwaltung (Zend_ACL), Webservices, Google-Data Client, Mail-Versand, PDF-Generierung,
Mehrsprachigkeit, XMLRPC und viele mehr mitgeliefert. Einen Überblick und Detail-Informationen
können unter http://framework.zend.com/manual/de/ eingesehen werden. Die
Evaluation jeder dieser Komponenten wurde nicht in der Evaluierung einbezogen. Der Umfang wird jedoch
als sehr positiv in die Bewertung eingebracht. Besonders aufgefallen ist, dass sich die Entwickler
des Zend Frameworks der Einheiten-Thematik eine eigene Komponente gewidmet haben und die Lucene-Suche
bereits out-of-the-box unterstützt wird. Ebenso positiv ist das konsequente Exception-Handling
für die jeweiligen Module.
Negativ zu bewerten ist, dass das Zend Framework keine eigene Benchmark-Möglichkeit mitbringt um
den Quellcode profilen zu können.
Einsatz von Design-Pattern
Design-Pattern spielen beim Zend Framework eine herausragende Rolle. Im Mittelpunkt stehen wie bei den
übrigen bisherigen Probanden auch das MVC- und FrontController-Paradigma als zentrale
Präsentations- und Business-Schicht-Pattern. Um die Struktur und den Aufbau genauer analysieren
zu können wurde auch hier eine Komplett-API-Dokumentation in Doxygen und Dot erzeugt. Trotz des
hinsichtlich PHP 5 möglichen sauberen Interface-Designs und der Verwendung von abstrakten
Basis-Klassen ist auch beim Zend Framework im Gegensatz zu CakePHP und dem Adventure-PHP-Framework
kein einheitliches Klassen-Design auszumachen, sondern jedes Package besitzt eine oder mehrere eigene
Definitionen einer abstrakten Basis-Klasse oder eines Interfaces.
Auffällig ist, dass sehr viele Klassen entweder statisch verwendet werden (Zend_Controller_Action_HelperBroker)
oder das Singleton-Pattern in jeder Klasse neu implementieren (Zend_Controller_Front). Ein
abstrakter Ansatz (evtl. "abstract singleton" oder "generic fabric pattern") wird nicht verfolgt, was
den Anwender darauf beschränkt, nur diejenigen Klassen singleton instanziieren oder verwenden zu
können, die das Feature auch unterstützen.
Struktur des Quellcodes / Design der Klassen
Der Aufbau des Packages wurde nach dem Zend Namensgebungsprinzip stringent aufgebaut und der Anwender
findet sich in den Komponenten sehr schnell zurecht. Die Klassen und deren Methoden sind auf einem
sehr hohen Abstraktionslevel abgefasst, was designtechnisch als sehr positiv zu bewerten ist, Einsteigern
das Analysieren des Quellcodes jedoch etwas erschwert. Nichtsdestoweniger wird durchgängig
Gebrauch von der Parameter-Typ-Deklaration in den Funktionsdefinitionen gemacht, was das Debugging
erleichtert, da nur erlaubte Daten- und Objekt-Typen akzeptiert werden.
Einsetzbarkeit für mehrere Applikationen
Um Anwendungen und Module in unterschiedlichen Umgebungen verwenden zu können bietet das Zend
Framework die Komponenten
- Zend_Registry
- Zend_Config
- Zend_Locale.
Mit diesen kann der Entwickler sehr einfach Sprach- und Umgebungs-abhängige Konfigurationen erzeugen
und in den Anwendungen verwenden. Im Klassen-Design fehlt die Sprach- und Umgebungs-Abhängigkeit
jedoch noch, so dass es nicht möglich ist in einem Controller an Hand der Sprache des Controllers
selbst eine Konfiguration zu laden, sondern man muss auf Mittel wie Registry zurückgreifen, was
zunächst nicht negativ auffällt, aber etwas aufwändiger ist.
Erweiterbarkeit
Engagierte Entwickler können das Zend Framework einfach erweitern. Möglichkeiten werden
bereits im Manual aufgezeigt und es wird auf Situationen verwiesen, zu denen dieses auch notwendig ist.
Dies sollte dem Anwender auch nicht schwer fallen, denn zu den jeweiligen Klassen existiert
üblicherweise eine Interface-Definition der zu erweiternden Klasse. Durch die Masse der im Zend
Framework integrierten Klassen und Module besteht jedoch auch hier die Gefahr, dass dieses zu einer
monolithischen Klassensammlung wie PEAR mutieren könnte und das Kern-Design verloren geht. Wie
bei den bisherigen Testkandidaten auch, muss der Entwickler bei der Erstellung komplexer GUI-Strukturen
auf Drittprodukte ausweichen, was vom Autor als problematisch hinsichtlich des ursprünglichen
Designs des Frameworks betrachtet wird.
Scaffolding
Ein Rapid Development Feature im Sinne von CakePHP und CodeIgniter ist im Zend Framework nicht
vorgesehen. Es sind zwar ähnliche Strukturen vorhanden (Zend_Db_Adapter, Row- / Table-Data-Gateway),
jedoch gibt es keinen Scaffolding-Mode, bei dem mit wenigen Handgriffen eine komplette GUI-Anwendung
erzeugt werden kann. Aus Sicht des Autors ist dieses jedoch auch nicht Teil der Strategie bzw. des
Designs des Frameworks, muss aber in der Bewertung als fehlend kenntlich gemacht werden.
3.3.7. Dokumentation
Dokumentation des Quellcodes
Der Quellcode des Frameworks ist sehr gut dokumentiert wodurch der Blick in den Quellcode eine einfache
Analyse - natürlich im Rahmen der Fähigkeiten des Programmierers betrachtet - zulässt.
API-Dokumentation
Unter http://framework.zend.com/apidoc/core/ findet der interessierte
Entwickler eine API-Dokumentation, die mit PHPDocumentor aus dem Quelltext generiert wurde.
Einführungen, Tutorials und Anwendungs-Beispiele
Die Seite http://framework.zend.com/ dient dem Entwickler als zentrale Ressource
für Dokumentationen. Das Manual selbst ist im deutschen an vielen Stellen schlecht übersetzt,
oder es fehlen Übersetzungen. Die Beispiele sind oft unvollständig und "verschweigen" die
Bedeutung einiger Variablen (wie oben aufgezeigt $router). Viele der Code-Snippets zeigen
zudem nur die Verwendung einer Komponente als Prototyp, unterstützen jedoch nicht den konkreten
Anwendungsfall.
Ein weiteres Manko ist die Verfügbarkeit des Wikis (http://framework.zend.com/wiki/display/ZFDEV/Home).
Dieses ist aus München nur in ca. 50% der Fälle verfügbar und wird üblicherweise
mit einem "Bad Proxy Request" quittiert. Im Wiki sind nach Meinung der Redaktion keine für
Anfänger geeigneten Tutorials enthalten - die Beiträge helfen lediglich bereits mit dem
Thema vertrauten Personen.
ChangeLogs / Migrations-Hinweise für API-Änderungen
Die detaillierten ChangeLogs und Änderungshinweise zu den Versionen sind im Manual eingearbeitet
und werden auch auf http://framework.zend.com/changelog nochmal gesondert für
die bereits veröffentlichten dargestellt.
3.3.8. Support
Für den Support des Frameworks werden dem Besucher unter http://framework.zend.com/support
mehrere kostenlose und kostenpflichtige Services offeriert. Unter die kostenlosen Services fallen
das Wiki, verschiedene Mailing-Listen, Chats, Blogs und der Bugtracker. Im deutschsprachigen Raum wird
das "ZF Forum" (http://www.zfforums.de/), das oben bereits zitiert
wurde, angeboten. Darüber hinaus bietet Zend das englischsprachige Pendant unter
http://www.zfforums.com/, bzw. die Developer Zone
(http://devzone.zend.com/public/view). Alles in Allem ist der Umfang
der von Zend angebotenen Support-Möglichkeiten sehr groß und sehr vielseitig.
3.3.9. Benchmark
Das Benchmark-Ergebnis wurde mit der im Adventure-PHP-Framework integrierten Benchmark-Komponente
benchmarkTimer gemessen. Hierzu wurde ein
$T = &Singleton::getInstance('BenchmarkTimer'); $T->start('ZFPage');
am Anfang der index.php und ein
$T->stop('ZFPage'); echo $T->createReport();
am Ende eingefügt. Es wurde eine Durchschnitts-Wert von 0.2498 s gemessen. In
der Rendering-Zeit ist die komplette Ausführungszeit für das Generieren der Views und der
Formatierung der Quelltexte eingeschlossen.
» Weiter auf Seite 6 (Bewertung Adventure-PHP-Framework).
Kommentare
Möchten Sie den Artikel eine Anmerkung hinzufügen, oder haben Sie ergänzende Hinweise? Dann können Sie diese hier einfügen. Die bereits verfassten Anmerkungen und Kommentare finden Sie in der untenstehenden Liste.
«
1
»
Einträge/Seite: |
5 |
10 |
15 |
20 |
|
1
|
Christian
28.10.2007, 12:18:20
|
Da im Test bewusst auf den Einsatz von ByteCodeCaching-Mechanismen verzichtet wurde hier eine manuelle Test-Reihe zum Zend Framework und dem Adventure PHP Framework:
http://www.adventure-php-framework.org/frontend/media/PerformanceTest_mit_eAccelerator.txt
|