Zend Framework Tutorial Teil 8:
Formularverarbeitung mit Zend_Form

Im siebten Teil vom Zend Framework Tutorial haben wir die Zend_View Komponente kennen gelernt und schon für die Anzeige der Artikelliste und eines einzelnen Artikels verwendet. Wir haben ein Haupttemplate mit dem Seitenaufbau sowie mehrere Subtemplates erstellt. Zudem haben wir ein wenig CSS unser TravelloBlog ein wenig aufgehübscht. Wenn du die ersten sieben Teile noch nicht gelesen hast, hole dies bitte schnell nach.

In diesem achten Teil des Tutorials werden wir uns um die Formularverarbeitung kümmern. Hierbei übernehmen die Aktionsmethoden des Controllers die Interaktion zwischen Model, View und Controller. Ich zeige einen Weg auf, wie du mit Hilfe des Zend Frameworks die einzelnen Schritte und Aspekte einer Formularverarbeitung (Erstellung des Formulars, Validierung der Daten, Behandlung der Fehlermeldung und Speichern der Daten) lösen kannst.

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.

Inhaltsverzeichnis

Vorüberlegungen

Die Verarbeitung von Formularen in einem Webprojekt erfordert mehrere Teilschritte. Für unsere Artikel wären dies im einzelnen (die Liste lässt sich sicher erweitern, dies sollte aber für uns erst einmal ausreichend sein):

  1. Erstellen des Formulars für neue Artikel mit Vorbelegung initialer Werte
  2. Erstellen des Formulars für bestehende Artikel mit Vorbelegung der vorhandenen Werte
  3. Validierung der eingegebenen Daten nach dem Absenden des Formulars
  4. Behandlung von Fehlermeldungen bei fehlerhafter Validierung sowie erneute Ausgabe des Formulars
  5. Speichern der Daten bei erfolgreicher Validierung für einen neuen Artikel
  6. Aktualisieren der Daten bei erfolgreicher Validierung für einen bestehenden Artikel
  7. Ausgabe einer Ergebnisseite nach dem Speichern der Daten

Jetzt wäre es denkbar, alle diese Teilschritte von einer einzigen Aktionsmethode von unserem ArticleController verarbeiten zu lassen. Dies würde diese Aktionsmethode jedoch sehr umfangreich und schlecht wartbar werden lassen. Deshalb ist es sinnvoll, diese Teilschritte in verschiedenen Aktionsmethoden verarbeiten zu lassen. So könnte eine Methode für die Erstellung des Formulars zuständig sein, während eine andere die Daten validiert und die nächste die Daten speichert.

Um mehrfach vorhandenen Code zu vermeiden, ist es ebenfalls sinnvoll, nicht für jeden der genannten Teilschritte eine eigene Aktionsmethode zu erstellen. In der folgenden Tabelle habe ich diese Überlegungen einmal zusammengefasst. In den Klammern habe ich die Bezeichner der einzelnen Teilschritte von oben eingefügt.

Aktion Aufgabe
createAction bereitet die Initialwerte für das Anlegen eines neuen Artikels auf und übergibt die Kontrolle zusammen mit den Werten an formAction (a.)
updateAction lädt die Werte des zu ändernden Artikels aus der Datenbank und übergibt die Kontrolle zusammen mit den Werten an formAction (b.)
formAction erstellt das Formular mit den vorgegeben Werten; (a. und b.)
gibt ggf. auch die Fehlermeldungen nach einer fehlerhaften Validierung aus (d.)
validateAction validiert die Eingaben (c.)

  • wenn die Validierung fehlerhaft ist, wird die Kontrolle zusammen mit den Fehlermeldungen wieder an formAction übergeben
  • wenn die Validierung erfolgreich war, wird die Kontrolle zusammen mit den Daten an saveAction übergeben
saveAction speichert die Daten ab

  • für neue Artikel wird ein neuer Datensatz angelegt (e.)
  • für bestehende Artikel wird der Datensatz aktualisiert (f.)

danach wird nach showAction umgeleitet

showAction zeigt den Artikel an (g.)

Auf den ersten Blick mag es recht umständlich aussehen, für die Verarbeitung eines einfachen Formulars sechs Aktionsmethoden zu verwenden. Dies verbessert jedoch die Übersicht in den einzelnen Aktionsmethoden und erleichtert damit auch die spätere Wartung.

Für das Übergeben der Kontrolle an eine andere Aktionsmethode sowie für das Umleiten stellt die Zend_Controller Komponente zwei praktische Methoden bereit. Mit Hilfe von _forward() kann in einem Controller die Kontrolle an einer andere Aktionsmethode übergeben werden, wobei alle gewünschten Parameter übergeben werden können. Mit Hilfe von _redirect() kann, wie der Name schon sagt, eine Umleitung auf eine andere Adresse initiiert werden. Dabei können außer über die URL keine Parameter übergeben werden.

Da die Methoden formAction und saveAction jedoch nicht direkt vom Benutzer über die Eingabe einer entsprechenden URL aufgerufen werden sollen, müssen wir uns etwas überlegen. Es bietet sich auf den ersten Blick an, diese Methoden nicht als öffentlich zugängliche Aktionsmethoden, sondern als private Methoden zu deklarieren. Dabei müssen wir sie in buildForm und saveData umbenennen, weil der Zend_Controller verlangt, dass alle Methoden, die auf "Action" enden, als öffentlich deklariert sind. Doch dazu gleich mehr.

Artikelformular erstellen

Um neue Artikel erstellen und bestehende ändern zu können, benötigen wir ein entsprechendes Template mit einem Formular. Wie oben erwähnt verwenden wir sowohl für das Erstellen als auch für das Ändern eines Artikels das gleiche Formular.

Lege also in dem Verzeichnis "/travelloblog/application/views/article" die neue Datei mit Namen form.phtml und folgendem Inhalt an:

PHP:
  1. <form action="<?php echo $this->form_action; ?>" method="post">
  2. <?php if (isset($this->article['art_id'])) : ?>
  3. <input type="hidden" id="art_id" name="art_id" value="<?php echo $this->article['art_id']; ?>" />
  4. <?php endif; ?>
  5. <fieldset>
  6. <legend>Artikeldaten</legend>
  7. <table>
  8. <tr>
  9. <td><label for="art_title">Titel</label></td>
  10. <td>
  11. <?php if (isset($this->errors['art_title'])) : ?><div class="error"><?php endif; ?>
  12. <input type="text" id="art_title" name="art_title" maxlength="64" value="<?php echo $this->article['art_title']; ?>" />
  13. <?php if (isset($this->errors['art_title'])) : ?><br/><?php echo $this->escape($this->errors['art_title']); ?></div><?php endif; ?>
  14. </td>
  15. </tr>
  16. <tr>
  17. <td><label for="art_teaser">Teaser</label></td>
  18. <td>
  19. <?php if (isset($this->errors['art_teaser'])) : ?><div class="error"><?php endif; ?>
  20. <input type="text" id="art_teaser" name="art_teaser" maxlength="255" value="<?php echo $this->article['art_teaser']; ?>" />
  21. <?php if (isset($this->errors['art_teaser'])) : ?><br/><?php echo $this->escape($this->errors['art_teaser']); ?></div><?php endif; ?>
  22. </td>
  23. </tr>
  24. <tr>
  25. <td><label for="art_text">Text</label></td>
  26. <td>
  27. <?php if (isset($this->errors['art_text'])) : ?><div class="error"><?php endif; ?>
  28. <textarea id="art_text" name="art_text" rows="10"><?php echo $this->article['art_text']; ?></textarea>
  29. <?php if (isset($this->errors['art_text'])) : ?><br/><?php echo $this->escape($this->errors['art_text']); ?></div><?php endif; ?>
  30. </td>
  31. </tr>
  32. <tr>
  33. <td> </td>
  34. <td><input type="submit" name="button_save" value="Artikel speichern" class="button" /></td>
  35. </tr>
  36. </table>
  37. </fieldset>
  38. </form>
  39. <hr />
  40. <a href="<?php echo $this->url(array('controller'=>'article', 'action'=>'index'), null, true); ?>">zur&uuml;ck zur Artikelliste</a>

Das Formular Template setzt voraus, dass in der Templatevariable $this->article die Werte für die einzelnen Felder und in $this->errors mögliche Fehlermeldungen vorhanden sind. Ist für eine Spalte ein Fehler gefunden worden, wird das entsprechende Eingabefeld farblich hervorgehoben und die Fehlermeldung ausgegeben.

Zudem wird bei zu ändernden Artikeln die Id des Artikels ausgegeben. Außerdem erwartet das Template die Templatevariable form_action mit der Aktion für das Formular.

Bevor wir uns dem Controller widmen, fügen wir noch in unserem Haupttemplate main.phtml im Verzeichnis "/application/layouts/" einige Links für die Anzeige der Artikelliste, Tagliste und Kategorieliste sowie zum Formular für das Erstellen neuer Artikel ein.

PHP:
  1. [...]
  2.  
  3. <div id="navi">
  4. <ul>
  5. <li><a href="<?php echo $this->url(array('controller'=>'article', 'action'=>'index'), null, true); ?>">Artikel auflisten</a></li>
  6. <li><a href="<?php echo $this->url(array('controller'=>'article', 'action'=>'create'), null, true); ?>">Artikel anlegen</a></li>
  7. <li><a href="#">a</a></li>
  8. <li><a href="#">b</a></li>
  9. <li><a href="#">c</a></li>
  10. <li><a href="#">d</a></li>
  11. </ul>
  12. </div>
  13.  
  14. [...]

Anpassen der createAction Methode

Als erstes ändern wir die bereits vorhandene createAction Methode in unserem ArticleController wie folgt ab:

PHP:
  1. class ArticleController extends Zend_Controller_Action
  2. {
  3.     [...]
  4.    
  5.     public function createAction()
  6.     {
  7.         $params = array();
  8.         $params['title'] = 'TravelloBlog - Neuen Artikel erstellen';
  9.         $params['article']['art_title' ] = '';
  10.         $params['article']['art_teaser'] = '';
  11.         $params['article']['art_text'  ] = '';
  12.         $params['errors'] = array();
  13.        
  14.         $this->buildForm($params);
  15.     }
  16.    
  17.     [...]
  18. }

Zu jeder Aktion gehört auch ein view-Skript. unsere create view-Skript macht nichts anderes als das Artikel-Formular aufzurufen.
Lege dazu bitte die Datei create.phtml im Verzeichnis "/views/scripts/article/" an und schreibe dort rein:

PHP:
  1. <?php
  2.  
  3. require 'form.phtml';
  4.  
  5. ?>

Im Prinzip wird in createAction nur ein Parameter Array für die Verarbeitung durch die private Methode buildForm zum Erstellen unseres Formulars befüllt. Zuerst werden die initialen Werte für die Felder des Formulars belegt. Da das Formular noch nicht validiert worden ist, gibt es auch noch keine Fehlermeldungen. Zuguterletzt wird noch der Titel für die Seite festgelegt.

Zum Schluss werden die Parameter an die Methode buildForm übergeben, welche das Formular erstellt und ausgibt.

Als nächstes müssen wir die neue private Methode buildForm in unserem ArticleController anlegen:

PHP:
  1. class ArticleController extends Zend_Controller_Action
  2. {
  3.     [...]
  4.    
  5.     private function buildForm($params)
  6.     {
  7.         foreach($params as $key => $value)
  8.         {
  9.             $this->view->assign($key, $value);
  10.         }
  11.        
  12.         $this->view->assign('form_action', 'validate');
  13.     }
  14.  
  15.     [...]
  16. }

Die übergebenen Parameterwerte werden einfach an unser Zend_View Objekt übergeben.

Rufe nun bitte wieder die Adresse "http://localhost/travelloblog/public/article/" in deinem Browser auf und klicke dort auf den "Artikel anlegen". Das Formular sollte jetzt in etwa so aussehen:

Artikel anlegen

Wenn du nun auf den "Artikel speichern" Button klickst, wird nur "ArticleController::__call()" ausgegeben. Daran erkennen wir, dass die aufgerufene Aktionsmethode für die Validierung noch nicht existiert.

Validierung des Formulars

In unserem ArticleController legen wir die neue Aktionsmethode validateAction an:

PHP:
  1. class ArticleController extends Zend_Controller_Action
  2. {
  3.     [...]
  4.    
  5.     public function validateAction()
  6.     {
  7.         $data = array();
  8.        
  9.         if (isset($_POST['art_id']))
  10.         {
  11.             $data['art_id'] = $_POST['art_id'];
  12.         }
  13.        
  14.         $data['art_title' ] = $_POST['art_title' ];
  15.         $data['art_teaser'] = $_POST['art_teaser'];
  16.         $data['art_text'  ] = $_POST['art_text'  ];
  17.         $errors = array();
  18.        
  19.         if (strlen($data['art_title']) == 0)
  20.         {
  21.             $errors['art_title'] = 'Bitte Titel eingeben!';
  22.         }
  23.        
  24.         if (strlen($data['art_text']) == 0)
  25.         {
  26.             $errors['art_text'] = 'Bitte Text eingeben!';
  27.         }
  28.        
  29.         if (count($errors)> 0)
  30.         {
  31.             $params = array();
  32.             $params['article'] = $data;
  33.             $params['errors' ] = $errors;
  34.             $params['title'  ] = 'TravelloBlog - Artikelvalidierung';
  35.             $this->buildForm($params);
  36.            
  37.             return;
  38.         }
  39.        
  40.         $this->saveData($data);
  41.     }
  42.    
  43.     [...]
  44. }

Und wie es sich gehört, legen wir für diese Aktion auch wieder ein entsprechendes view-Skript (validate.phtml) an. Wie auch schon bei create.phtml brauchen wir hier lediglich das Artikel-Formular einzulesen:

PHP:
  1. <?php
  2.  
  3. require 'form.phtml';
  4.  
  5. ?>

Zuerst holen wir uns alle benötigten Formularwerte aus dem globalen $_POST Array. Danach überprüfen wir, ob für den Artikel ein Titel und ein Text angegeben worden ist. Falls ja, wird eine entsprechende Fehlermeldung festgelegt.

Hinweis
Du solltest nie die Daten aus dem globalen $_POST Array direkt übernehmen, um dir keine Sicherheitslücken einzuhandeln. Das Zend Framework bietet mit Zend_Filter_Input eine gute Lösung, um Benutzerdaten zu prüfen und zu verarbeiten. In einem späteren Teil des Tutorials lernst du mehr über Zend_Filter_Input. Momentan übernehmen wir die Daten des Benutzers ohne viele Prüfung bzw. Filterung.

Wenn mindestens ein Fehler gefunden worden ist, wird wieder die Methode buildForm aufgerufen, wobei die Artikeldaten und Fehlermeldungen übergeben werden. Das return wird benötigt, weil ansonsten der nachfolgende Code ebenfalls ausgeführt werden würde. Falls die Validierung erfolgreich war, werden die Daten an die Methode saveData übergeben.

Sende nun bitte einmal das Formular ab, ohne dass du in eines der Feldern irgendwelche Daten eingibst. Das Formular sollte nun die Fehlermeldungen ausgeben:

Fehlermeldung

Speichern der Daten

Nachdem die Validierung nun geklappt hat, widmen wir uns dem Speichern der Daten. Lege nun bitte in unserem ArticleController die neue private Methode saveData an:

PHP:
  1. class ArticleController extends Zend_Controller_Action
  2. {
  3.     [...]
  4.    
  5.     private function saveData($data)
  6.     {
  7.         $newDate = date('Y-m-d H:i:s');
  8.        
  9.         $data['art_user_id'] = '1';
  10.         $data['art_cdate'  ] = $newDate;
  11.         $data['art_udate'  ] = $newDate;
  12.        
  13.         $article = new ArticleModel();
  14.         $art_id = $article->insert($data);
  15.         $url = '/article/show/id/' . $art_id;
  16.         $this->_redirect($url);
  17.     }
  18.    
  19.     [...]
  20. }

Zuerst werden für weitere Felder unseres Artikeldatensatzes neue Werte festgelegt. Danach initialisieren wir wieder unsere Model Klasse für den Artikel und speichern den neuen Artikeln ab.

Die insert() Methode gibt die Id des neuen Artikels zurück. Die _redirect() Methode führt die Weiterleitung durch um den neuen Artikel gleich anzuzeigen. Durch die sofortige Weiterleitung verhindern wir übrigens auch, dass jemand das Formular aus Versehen doppelt absendet.

Wenn du nun die Daten für einen neuen Artikel eingibst, sollte das Ganze in etwa wie folgt aussehen:

Neuer Artikel angelegt

Das schaut ja alles schon sehr gut aus, nur bietet und das Zend Framework die Möglichkeit, die Formularestellung und die Validierung zu vereinfachen, und zwar mit Zend_Filter bzw. Zend_Filter_Input und Zend_Validate. Lies dir das alles mal in einer ruhigen Stunde durch.

Wir gehen aber gleich einen Schritt weiter und verwenden Zend_Form. Damit werden Forumularerstellung und Validierung
noch einfacher und vor allem wartungsfreundlicher.

Zend_Form in Action

Zunächst einmal müssen wir das Formular neu anlegen. Dazu erstelle bitte eine Datei mit dem Namen ArticleForm.php im Verzeichnis "/application/models/". Dort trage dann folgendes ein:

PHP:
  1. class ArticleForm extends Zend_Form
  2. {
  3.     public function __construct($options = null)
  4.     {
  5.         parent::__construct($options);
  6.        
  7.         $art_id = new Zend_Form_Element_Hidden('art_id');
  8.        
  9.         $title = new Zend_Form_Element_Text('art_title');
  10.         $title->setLabel('Titel')
  11.               ->setRequired(true)
  12.               ->addFilter('StripTags')
  13.               ->addFilter('StringTrim')
  14.               ->addValidator('NotEmpty')
  15.               ->addErrorMessage('Bitte einen Titel eintragen');
  16.        
  17.         $teaser = new Zend_Form_Element_Text('art_teaser');
  18.         $teaser->setLabel('Teaser')
  19.                ->addFilter('StripTags')
  20.                ->addFilter('StringTrim');
  21.        
  22.         $text = new Zend_Form_Element_Textarea('art_text');
  23.         $text->setLabel('Text')
  24.              ->setAttribs(array('rows' => 10, 'cols' => 70))
  25.              ->setRequired(true)
  26.              ->addFilter('StripTags')
  27.              ->addFilter('StringTrim')
  28.              ->addValidator('NotEmpty')
  29.              ->addErrorMessage('Etwas Text muss schon sein');
  30.        
  31.         $submit = new Zend_Form_Element_Submit('submit');
  32.         $submit->setLabel('Artikel speichern');
  33.        
  34.         $this->addElements(array($art_id, $title, $teaser, $text, $submit));
  35.     }
  36. }

Was haben wir hier gemacht? Zend_Form hat vordefinierte Elemente, die wir entweder in der Standardeinstellung verwenden oder bei Bedarf an unsere Bedürfnisse anpassen können:

Jedes Element, das wir hinzufügen, bekommt als Attribut den Feldnamen unter dem es in unserer Datenbank angelegt ist.
Mit setLabel() können wir den Text festlegen, der im Formular angezeigt wird und dem User sagt, welche Eingabe erwartet wird.
Sollte ein Feld ausgefüllt werden müssen, kann das durch setRequired(true) festgelegt werden.
addFilter bietet die Möglichkeit mit Filtern die Usereingabe zu entschärfen. In unserem Fall löschen wir mit StringTrim() die Leerzeichen vor und hinter der Eingabe und mit StripTags() werden alle HTML und PHP Tags aus dem Text gelöscht. Weitere Filter findest du unter Standard Filter Klassen.
Wir wollen die Usereingabe jedoch nicht nur entschärfen, wir müssen die Eingabe auch prüfen (validieren). Dazu gibt es addValidator() mit dem wir Regeln aufstellen können, nach der die Eingabe geprüft wird.
Sollte es zu einer Fehleingabe kommen, wird per default die Standardmeldung ausgegeben, und das in englisch. Wir wollen aber unsere eigene Fehlermeldung anzeigen und zudem in deutsch. Um die Fehlermeldung zu individualisieren, verwenden wir addErrorMessage().

So, das Formular haben wir. Jetzt müssen wir noch unsere createAction() Methode anpassen. Öffne dazu bitte den ArticleController und ändere createAction() wie folgt:

PHP:
  1. class ArticleController extends Zend_Controller_Action
  2. {
  3.     [...]
  4.    
  5.     public function createAction()
  6.     {
  7.         $this->view->title = "TravelloBlog - Neuen Artikel hinzuf&uuml;gen";
  8.        
  9.         $newDate = date('Y-m-d H:i:s');
  10.        
  11.         $form = new ArticleForm();
  12.         $this->view->form = $form;
  13.        
  14.         if ($this->_request->isPost())
  15.         {
  16.             $formData = $this->_request->getPost();
  17.            
  18.             if ($form->isValid($formData))
  19.             {
  20.                 $article = new ArticleModel();
  21.                
  22.                 $row = $article->createRow();
  23.                 $row->art_title = $form->getValue('art_title');
  24.                 $row->art_teaser = $form->getValue('art_teaser');
  25.                 $row->art_text = $form->getValue('art_text');
  26.                 $row->art_user_id = '1';
  27.                 $row->art_cdate = $newDate;
  28.                 $row->art_udate = $newDate;
  29.                
  30.                 $art_id = $row->save();
  31.                 $url = '/article/show/id/' . $art_id;
  32.                 $this->_redirect($url);
  33.             }
  34.             else
  35.             {
  36.                 $form->populate($formData);
  37.             }
  38.         }
  39.    
  40.     [...]
  41. }

Wir erstellen zunächst ein neues Objekt mit dem Namen ArticleForm. Aufgrund der Namenskonvention weiß Zend Framework, dass es die dazu gehörende Datei ArticleForm.php im Verzeichnis "/application/models/" zu suchen hat.
Sollte das Formular via POST übermittelt werden, werden die Daten gesammelt und validiert. Sind keine Fehler aufgetreten werden die Daten in die entsprechenden Felder unserer Datenbanktabelle geschrieben und gespeichert. Wenn es jedoch einen oder mehrere Fehleingaben geben, wird das Formular erneut angezeigt.
Kurz und knackig. Wenn du dir mal anshaust, was wir für die gleichen AKtionen vorher alles machen mussten:
buildForm(), validateAction() und saveData() - die kannst du jetzt alle löschen.

Als letztes müssen wir noch dafür sorgen, dass unser Formular auch angezeigt wird. Öffne dazu bitte die Datei create.phtml im Verzeichnis "/application/views/scripts/article/" und ändere den Eintrag wie folgt:

PHP:
  1. <fieldset>
  2. <legend>Artikeldaten</legend>
  3.  
  4. <?php
  5.  
  6. echo $this->form;
  7.  
  8. ?>
  9.  
  10. </fieldset>
  11.  
  12. <hr />
  13. <a href="<?php echo $this->url(array('controller'=>'article', 'action'=>'index'), null, true); ?>">zur&uuml;ck zur Artikelliste</a>

Das war's auch schon. Wenn du jetzt "http://localhost/travelloblog/public/article/" in deinem Browser aufrufst siehst du, dass alles genauso ist wie vorher.

Artikel ändern

Um einen Artikel ändern zu können, bearbeiten wir als erstes die Datei show.phtml ind unserem Scripts-Verzeichnis und ergänzen es um einen Link zum Ändern des Artikels:

PHP:
  1. [...]
  2.  
  3. echo '<hr />';
  4. echo '<h2><a href="'. $this->url(array('controller'=>'article',
  5.                                        'action'=>'index'), null, true) .'">'
  6.                     .'zur&uuml;ck zur Artikelliste</a> | ';
  7.  
  8. echo '<a href="'. $this->url(array('controller'=>'article',
  9.                                        'action'=>'change')) .'">'
  10.                     .'Artikel &auml;ndern</a></h2>';

Danach ändern wir unsere Aktionsmethode changeAction() im ArticleController:

PHP:
  1. class ArticleController extends Zend_Controller_Action
  2. {
  3.     [...]
  4.    
  5.     public function changeAction()
  6.     {
  7.         $this->view->title = "Travelloblog - Artikel &auml;ndern";
  8.        
  9.         $form = new ArticleForm();
  10.         $this->view->form = $form;
  11.        
  12.         if ($this->_request->isPost())
  13.         {
  14.             $formData = $this->_request->getPost();
  15.            
  16.             if ($form->isValid($formData))
  17.             {
  18.                 $article = new ArticleModel();
  19.                
  20.                 $id = (int)$form->getValue('art_id');
  21.                
  22.                 $row = $article->fetchRow('art_id='. $id);
  23.                 $row->art_title = $form->getValue('art_title');
  24.                 $row->art_teaser = $form->getValue('art_teaser');
  25.                 $row->art_text = $form->getValue('art_text');
  26.                 $row->art_udate = date('Y-m-d H:i:');
  27.                
  28.                 $art_id = $row->save();
  29.                 $url = '/article/show/id/' . $art_id;
  30.                 $this->_redirect($url);
  31.             }
  32.             else
  33.             {
  34.                 $form->populate($formData);
  35.             }
  36.         }
  37.         else
  38.         {
  39.             //-- Daten ins Formular einlesen
  40.             $id = (int)$this->_request->getParam('id', 0);
  41.            
  42.             if ($id> 0)
  43.             {
  44.                 $article = new ArticleModel();
  45.                 $article = $article->fetchRow('art_id='. $id);
  46.                 $form->populate($article->toArray());
  47.             }
  48.         }
  49.     }
  50.    
  51.     [...]
  52. }

Letztendlich ist hier alles weitestgehend identisch zur createAction(), es ist lediglich noch ein Teil hinzugekommen, mit dem wir die Daten erstmalig ins Formular einlesen: Die Id des Artikels wird aus den Parametern übernommen und der Datensatz gelesen und mit populate an das Formular übergeben.

Jetzt müssen wir uns nur noch um die Anzeige des Formulars kümmern und das ist ebenfalls identisch zum create.phtml. Also öffne bitte die Datei change.phtml und ändere diese folgendermaßen:

PHP:
  1. <fieldset>
  2. <legend>Artikeldaten</legend>
  3.  
  4. <?php
  5.  
  6. echo $this->form;
  7.  
  8. ?>
  9.  
  10. </fieldset>
  11.  
  12. <hr />
  13. <a href="<?php echo $this->url(array('controller'=>'article', 'action'=>'index'), null, true); ?>">zur&uuml;ck zur Artikelliste</a>

Wenn du dir einen Artikel anzeigen lässt und auf den "Artikel ändern" Link klickst, sollte das in etwa so aussehen:
Artikel ändern

Artikel löschen

Jetzt fehlt nur noch die Möglichkeit bestehende Artikel nach einer Sicherheitsabfrage zu löschen. Dafür ergänzen wir das als erstes das Template show.phtml mit einem Link zum Löschen des Artikels:

PHP:
  1. [...]
  2.  
  3. echo '<hr />';
  4. echo '<h2><a href="'. $this->url(array('controller'=>'article',
  5.                                        'action'=>'index'), null, true) .'">'
  6.                     .'zur&uuml;ck zur Artikelliste</a> | ';
  7.  
  8. echo '<a href="'. $this->url(array('controller'=>'article',
  9.                                        'action'=>'change')) .'">'
  10.                     .'Artikel &auml;ndern</a> | ';
  11.  
  12. echo '<a href="'. $this->url(array('controller'=>'article',
  13.                                        'action'=>'delete')) .'">'
  14.                     .'Artikel l&ouml;schen</a></h2>';

Als nächstes benötigen wir noch ein Template, welches den Artikel zur Kontrolle noch einmal anzeigt und einen entsprechenden Löschbutton enthält. Ändere dafür im Verzeichnis "/travelloblog/application/views/article" das Template delete.phtml:

PHP:
  1. <fieldset>
  2. <legend>Artikel l&ouml;schen</legend>
  3.  
  4. <?php
  5.  
  6. echo '<h2>'. $this->escape($this->article->art_title) .'</h2>';
  7. echo '<p><em>'. $this->escape($this->article->art_cdate) .'</em></p>';
  8. echo '<p>'. $this->escape($this->article->art_text) .'</p>';
  9.  
  10. ?>
  11.  
  12. <form action="<?php echo $this->url(array('action'=>'delete')); ?>" method="post">
  13.     <input type="hidden" name="art_id" value="<?php echo $this->article->art_id; ?>" />
  14.     <input type="submit" name="del" value="Artikel wirklich l&ouml;schen" />
  15. </form>
  16.  
  17. </fieldset>
  18.  
  19. <hr />
  20. <a href="<?php echo $this->url(array('controller'=>'article', 'action'=>'index'), null, true); ?>">zur&uuml;ck zur Artikelliste</a>

Als nächstes müssen wir nun unsere Aktionsmethode deleteAction im ArticleController überarbeiten:

PHP:
  1. class ArticleController extends Zend_Controller_Action
  2. {
  3.     [...]
  4.    
  5.     public function deleteAction()
  6.     {
  7.         $this->view->title = "travelloblog - Artikel l&ouml;schen";
  8.        
  9.         if ($this->_request->isPost())
  10.         {
  11.             $id = (int)$this->_request->getPost('art_id');
  12.            
  13.             $del = $this->_request->getPost('del');
  14.            
  15.             if ($del && $id> 0)
  16.             {
  17.                 $article = new ArticleModel();
  18.                 $where = 'art_id = ' . $id;
  19.                 $article->delete($where);
  20.             }
  21.             $this->_redirect('article/');
  22.         }
  23.         else
  24.         {
  25.             $id = (int)$this->_request->getParam('id');
  26.            
  27.             if ($id> 0)
  28.             {
  29.                 $article = new ArticleModel();
  30.                 $this->view->article = $article->fetchRow('art_id='. $id);
  31.             }
  32.         }
  33.     }
  34.    
  35.     [...]
  36. }

Wir übergeben an das Template delete.phtml neben den Artikeldaten auch eine entsprechende Aktion für das Formular. Wenn du dir nun einen Artikel anzeigen lässt und auf den Link "Artikel löschen" klickst, sollte das in etwa so aussehen:

Artikel löschen

Übung: die weiteren Formulare

Als kleine Übung bis zum nächsten Teil dieses Tutorials möchte ich dich bitten für die Kategorien und die Tags auch die entsprechenden Formulare zu erstellen und die Controller Klassen CategoryController und TagController für die Verwendung dieser Formulare anzupassen. Es sollen neue Kategorien und Tags angelegt sowie bestehende verändert und gelöscht werden können.

Achte bitte darauf, dass die Felder tag_path bzw. cat_path keine direkten Eingabefelder sein sollen, sondern die Eingaben aus tag_name bzw. cat_name in eine URL freundliche Variante umwandeln sollen. Du kannst dafür z.B. diese Zeilen verwenden:

PHP:
  1. $value = preg_replace("=[^a-z0-9]=i", "_", strtolower($value));
  2. $value = preg_replace("=_+=i", "_", $value);

Dabei wird zuerst eine Zeichenkette in Kleinbuchstaben umgewandelt. Dann werden alle Zeichen, die keinen Buchstaben oder Ziffern sind, in einen Unterstrich umgewandelt. Zum Schluss werden mehrfach vorkommende Unterstriche zusammengefasst.

Zudem ändern wir die Übergabe per id von tag_path bzw. cat_path in tag_id bzw. cat_id, also so, wie beim Artikel auch. Dazu musst du die jeweiligen index.phtml Dateien und die showAction Methoden anpassen.

Zur Kontrolle lade dir den aktuellen Stand des Tutorials runter. Dann kannst du deine Ergebnisse damit vergleichen.

Download

Der aktuelle Stand des Tutorials nach diesem achten Teil kann herunter geladen werden. Hier sind auch alle Templates enthalten:

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 siebten Teil des Zend Framework Tutorials haben wir die Formularverarbeitung mit Hilfe von Zend_Form realisiert. Wir haben ein mehrfache verwendbares Formular für das Anlegen und Bearbeiten eines Artikels erstellt und unseren ArticleController um einige private Methoden ergänzt bzw. bestehende Aktionsmethoden überarbeitet. Das Anlegen neuer Artikel klappt nun genauso gut wie das Bearbeiten und Löschen bestehender Artikel.

Im nächsten Teil werden wir ein wenig aufräumen und die fehlenden Controller, Model und View Elemente unseres TravelloBlogs erstellen. Außerdem werden wir uns um die Startseite unseres TravelloBlogs kümmern. Danach wird das TravelloBlog zumindest schon einmal rudimentär laufen.

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

Navigation

Autor: Uwe E. Schirm
Datum: Sonntag, 8. März 2009 19:56
Trackback: Trackback-URL Themengebiet: Zend Framework Tutorial für Anfänger

Feed zum Beitrag: RSS 2.0 Diesen Artikel kommentieren

39 Kommentare

  1. 1

    Nur eine kleine Sache:

    Sollte “Lege also in dem Verzeichnis “/travelloblog/application/views/article” die neue Datei mit Namen “form.php” und folgendem Inhalt an:” nicht so sein:
    “/travelloblog/application/views/scripts/article” die neue Datei mit Namen “form.phtml” und folgendem Inhalt an:”
    ?

  2. 2

    genauso ist es. Ich hab’s geändert. Danke für den Hinweis

  3. 3

    – Zitat Anfang –
    Als nächstes benötigen wir noch ein Template, welches den Artikel zur Kontrolle noch einmal anzeigt und einen entsprechenden Löschbutton enthält. Ändere dafür im Verzeichnis “/travelloblog/application/views/article” das Template delete.php:
    – Zitat Ende –
    Meinst doch sicher delete.phtml, oder?

  4. 4

    klar… :(
    ist geändert, danke für den Hinweis

  5. 5

    Super Tutorial! Weiter so.
    Freue mich schon auf die nächsten Teile.

    Vielen Dank dafür!

  6. 6

    Vielen Dank für dieses Tutorial bzw. dessen Aktualisierung. Ich bin schonn sehr gespannt auf die nächsten Teile!

  7. 7

    Kann mich da nur anschliessen. Ein sehr gutes Tutorial.

  8. 8

    Schließe mich 5), 6) und 7) an: danke für das Tutorial, das erste Schritte im Framework deutlich erleichtert. Bin auf die nächsten Teile gespannt!

  9. 9

    Vielen Dank für das geniale Tutorial! Weiter so! =)

    Grüße
    Ronald

  10. 10

    Echt klasse Tutorial! Warte schon shensüchtig auf die nächste Episode!

  11. 11

    Kevin, das wird evtl. noch ein wenig dauern.
    Als nächstes kommt erstmal die Anpassung an die Veränderungen des ZF 1.8

    Zudem portiere ich gerade mein Shopsystem auf ZF – ist mehr Arbeit, als ich befürchtet habe.

    Aber die Fortsetzung kommt!

  12. 12

    Hab mir jetzt das Buch vom Ralf gekauft. Interessant wären vielleicht anstatt ein komplettes How2 einzelne Kapitel. Kannst dann ja auch Teile erzählen, die Du jetzt bei deinem Shop umgesetzt hast, also wie setze ich ein Login um, Sessionmanagement oder sowas. (:

  13. 13

    Ich halte einzelne Kapitel zunächst mal ür wenig hilfreich.
    Als Beginner weiss man noch nicht viel über den Aufbau, die Strukturierung und das Ineinandergreifen der einzelnen Komponenten des Frameworks.
    Und dadurch kommt es zu Problemen. Geh doch einfach mal die Beispiele der durchaus sehr guten Dokumentation von ZF durch. Blickst du da als Anfänger immer durch? Ich jedenfalls nicht.

    Aus diesem Grund glaube ich, dass ein chronologischer Aufbau zunächst mal viel hilfreicher ist.

  14. 14

    Hier musste ich für 1.8.2 nur sehr wenig ändern. So heißt meine Klasse für ArticleForm den Namen Model_ArticleForm. Ansonsten geht das fast 1:1.

  15. 15

    So, harter Arbeitstag hinter mir.

    Dieses Tutorial ist genau das, was ich lange gesucht habe!!! Sehr gut!!

    Warum gibt es eigentlich auf der Zend-Seite so schlechte Starthilfen? Ich hab mir auch das Buch von Ralf geholt (von dem ja die Urversion dieses Tuts stammt), aber die Beispiele aus dem Buch gefielen mir gar nicht. Da ist ja dieser Blog hinten auch nochmal drin, aber er entwickelt das Projekt gar nicht sondern fängt gleich mit einer Bootstrap-Datei an, die schon alles enthält was man je brauchen wird.

    Deshalb: Danke für die Aktualisierung dieses Blogs! Mir hat das sehr geholfen. Dazu das PDF, das ich in einem früheren Post erwähnt habe (Kapitel 1 oder 2). Beide zusammen sind die idealen Starthilfen und sollten direkt auf der Zend-Seite angeboten werden.

    Mich würden aber speziell noch Bereiche wie Zwischenspeichern von Session-Daten (etwa Warenkorb), Login, Ajax usw interessieren. Das ist hier ja noch nicht enthalten. Hoffe dass du bald auch Zeit dafür findest.

  16. 16

    hi marcus .. hast du dir das version 1.7 buch geholt oder ein älteres ??

    hier das meine ich :)
    http://www.amazon.de/exec/obidos/ASIN/3827327857/ecnethambu

  17. 17

    ja, genau das. kann ich für anfänger nicht empfehlen. wer noch nie mit zend gearbeitet hat wird mit dem buch von ralf eggert nicht so richtig glücklich werden. kann sein dass das buch besser ist, wenn man sich mit zend schon auskennt. – ich will aber erstmal einsteigen.

  18. 18

    Danke erstmal für das Top Tutorial!

    Weiß jemand, wie man SQL-Fehler, die von $row->save() ausgelöst werden, abfangen kann? Konkret geht es bei mir um Spalten, die unique sind und daher einen Fehler verursachen, wenn man eine Zeile mit gleichem Inhalt in den entsprechenden Spalten einfügen will.

  19. 19

    [...] Aber es wird eine Zeit kommen, da reicht einem das Standard-Layout des Zend Framework nicht mehr aus. Wenn die Ansprüche steigen, wird es Zeit, sich mit den Dekoratoren von Zend_Form zu befassen. Das Thema wird von vielen Entwicklern eher gemieden, dabei geht es eigentlich ganz einfach. Auf die Möglichkeiten zur Erstellung eines Formulars mit Zend Framework möchte ich an dieser Stelle nicht eingehen. Ein recht aktuelles Tutorial zum Thema finden Sie im Zend Framework Tutorial von Uwe E. Schirm. [...]

  20. 20

    [...] Weiter zu Teil 8: Formularverarbeitung mit Zend_Form Tags » Zend Framework, Zend Framework Tutorial « Autor: Uwe E. Schirm Datum: Donnerstag, 5. Februar 2009 1:09 Trackback: Trackback-URL Themengebiet: Zend Framework Tutorial für Anfänger Feed zum Beitrag: RSS 2.0 Diesen Artikel kommentieren [...]

  21. 21

    Vielen Dank für dass super Tutorial.
    Hoffe es kommen bald weitere Teile…

  22. 22

    Vielen dank für das tolle Tutorial.
    Endlich blicke ich durch das ganze besser durch. Freue mich schon auf den nächsten Teil.

  23. 23

    Hallo,

    ja geniales Tutorial, das ist genau das was mir bei der ZF Doku aufstösst, es gibt keine praktische Anleitung … sondern mehr ein sammelsurium aus Funktionsblöcken ;-)
    benutz ZF schön länger, also einzelteile GData, Rss, SOAP etc… :-)

    thx!

  24. 24

    Zunächst auch von mir vielen Dank!

    Ich arbeite mit der Version 1.9 und erhalte beim Laden des Formulars folgende Fehlermeldung:

    Fatal error: Class ‘ArticleForm’ not found

    Die Datei liegt wie beschrieben in application/models und ist ArticleForm.php benannt.

    In den Kommentaren wurde bereits erwähnt die Klasse in Model_ArticleForm umzubenennen. Das änderte bis auf den Klassennamen nichts an der Fehlermeldung.

    Hat noch jemand einen Tipp für mich?

  25. 25

    hi @ all,

    erstmal ein herzliches Danke für das aufbauende Tutorial. Ich finde deine/eure Art wie das hier erklärt und darauf eingegangen wird echt Klasse.

    So genug …, ich habe eine Frage bezüglich dem 9. Teil, weißt Du schon wann der ca. online kommen wird? Naja und wenn das noch dauert, was hier ja bestimmt jeder verstehen kann, wo finde ich das Urtutorial von diesem Ralf (wahrscheinlich etwas veraltet u in englisch)? Hab ich das richtig verstanden, dass du dich daran orientierst?

    ….schon mal Danke im voraus für jegliche Hilfe und mach weiter so!!!

    Greetz

    derbjoern

  26. 26

    Hallo
    Ich stecke voll im Tutorial. Super da auch bei der Fehlersuche, die Details durchgeleuchtet werden.
    Ich erhalte nach der Speicherung eines neuen Artikels die Fehlermeldung:
    Cannot send headers; headers already sent in C:\xampp\htdocs\travelloblog\library\Zend\Loader.php, line 207
    Meine Version:
    ZF 1.9
    Hat jemand eine Idee?

  27. 27

    Sollte dieser Text “Zuerst holen wir uns alle benötigten Formularwerte aus dem globalen $_POST Array. Danach überprüfen wir, ob für den Artikel ein Titel und ein Text angegeben worden ist. Falls ja, wird eine entsprechende Fehlermeldung festgelegt.”
    -> JA sollte NEIN heissen oder?

  28. 28

    Einfach suuuuuuuuuuuuuuuuper Tutorial!!!
    Nur ich lese hier, dass es seit März anscheinend kein weiterer Teil hinzugekommen ist? oO

    Bitte!!! Meinetwegen flaster die Seite mit Werbung und “Spende Button” zu – vielleicht ist das ein Anreiz weiterzumachen, denn dann würdest du auch noch gut dabei verdienen – aber bitte führe das Tutorial fort!!!

    Vielen Dank
    Gruß Schorschi

  29. 29

    Das tutorial ist SUPER. Wäre sehr schade, wenn es nicht weiter geht.

    Kennt jmd ein gutes Tutorial für zend_auth und zend_acl?

  30. 30

    Hallo!
    Das Tutorial ist einfach genial.
    Herzlichen Dank!

    Wird das Tutorial weitergeführt?

    Grüße
    Mustafa

  31. 31

    Suuuperr
    Bitte weitermachen!

  32. 32

    Ich finds auch Klasse!

  33. 33

    Hallo, ist geplant das Tutorial auf das neue Framework umzuschreiben?? Also 1.8., beim überfliegen des Tutorials ist mir nämlich aufgefallen das vieles in der neuen Version nicht mehr funktionieren sollte. Aber ansonsten ein echt super Tutorial!!

    Viele Grüße

  34. 34

    Ich finde es Klasse, wie du dieses Tutorial gemacht hast.
    Ich hoffe es kommt noch mehr :)

  35. 35

    Hallo, klasse tutorial! Dennoch ein Problem, ich habe Zend Framework + Zend Server Community Edition(CE) (PHP 5.3) installiert und habe das dortige Framework einfach mit dem Framework 1.8.2 ersetzt. Danach “travelloblog_08″ heruntergeladen und in htdocs extrahiert. Der gibt mir auf jeden Link den ich klicke folgende Fehlermeldung aus:

    Not Found

    The requested URL /travelloblog_08/public/category was not found on this server.

    Woran könnte das liegen?

  36. 36

    Hallo,

    was mach ich den wenn diese fehlermeldung kommt?:

    Fatal error: Class ‘ArticleForm’ not found in /xyz/travelloblog/application/controllers/ArticleController.php on line 33

  37. 37

    Hallo Uwe,

    vielen Dank für das Super Tutorial…
    Mach bitte weiter so.
    Danke.
    Andreas

  38. 38

    Das Tutorial war für mich ein Traum zum Einstieg ins ZF. Selbst mehrere Bücher und ZF-Doku haben mich bei Weitem nicht so zielgerichtet vorwärts gebracht wie diese Anleitung.

    Ich selbst habe tausende Stunden in kostenfreie Internetprojekte gesteckt und weiß daher, wie sich das Thema Motivation bzgl. solcher auf Dauer gestaltet. Sollte ich hier irgendwann eine Möglichkeit finden, in Form einer wie auch immer gearteten Spende Danke zu sagen, werde ich es tun.

    Vielen Dank nochmal

  39. 39

    Gestern und heute habe ich nur mit diesem Tut gearbeitet und es ist wirklich genial!

    Mach bitte weiter – Vielen Dank!
    =)

Kommentar abgeben