Zend Framework Tutorial Teil 6: MVC Design Pattern und Formularverarbeitung

Im fünften 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 fünf Teile noch nicht gelesen hast, hole dies bitte schnell nach.

In diesem sechsten 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.

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

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.php" 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>Article data</legend>
  7. <table>
  8. <tr>
  9. <td><label for="art_title">Title</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>&nbsp;</td>
  34. <td><input type="submit" name="button_save" value="save article" class="button" /></td>
  35. </tr>
  36. </table>
  37. </fieldset>
  38. </form>
  39. <hr>
  40. <a href="article/">back to list</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.php" einige Links für die Anzeige der Artikelliste, Tagliste und Kategorieliste sowie zum Formular für das Erstellen neuer Artikel ein.

PHP:
  1. [...]
  2. <div id="navi">
  3. <ul>
  4. <li><a href="article/create/">create new article</a></li>
  5. <li><a href="#">b</a></li>
  6. <li><a href="#">c</a></li>
  7. <li><a href="#">d</a></li>
  8. </ul>
  9. </div>
  10. [...]

Anpassen der createAction Methode

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

PHP:
  1. public function createAction()
  2.     {
  3.         $params = array();
  4.         $params['article']['art_title' ] = '';
  5.         $params['article']['art_teaser'] = '';
  6.         $params['article']['art_text'  ] = '';
  7.        
  8.         $params['errors'] = array();   
  9.        
  10.         $params['title'] = 'TravelloBlog - Create new article';
  11.        
  12.         $this->buildForm($params);
  13.     }

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. private function buildForm($params)
  2.     {
  3.         $view = Zend::registry('view');
  4.        
  5.         foreach($params as $key => $value)
  6.         {
  7.             $view->assign($key, $value);
  8.         }
  9.        
  10.         $view->assign('form_action', 'article/validate/');
  11.         $view->assign('subtemplate', 'article/form.php');
  12.        
  13.         echo $view->render('main.php');
  14.     }

Die übergebenen Parameterwerte werden einfach an unser Zend_View Objekt übergeben. Zusätzlich wird noch die ausführende Aktion des Formulars und unser einzubindendes Subtemplate festgelegt. Danach wird unser Template ausgegeben.

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

Screen 1: Neuer Artikel

Wenn du nun auf den "save article" 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. public function validateAction()
  2.     {
  3.         $data = array();
  4.  
  5.         if (isset($_POST['art_id']))
  6.         {
  7.             $data['art_id'] = $_POST['art_id'];
  8.         }
  9.        
  10.         $data['art_title' ] = $_POST['art_title' ];
  11.         $data['art_teaser'] = $_POST['art_teaser'];
  12.         $data['art_text'  ] = $_POST['art_text'  ];
  13.        
  14.         $errors = array();
  15.        
  16.         if (strlen($data['art_title']) == 0)
  17.         {
  18.             $errors['art_title'] = 'Please enter a title!';
  19.         }
  20.        
  21.         if (strlen($data['art_text']) == 0)
  22.         {
  23.             $errors['art_text'] = 'Please enter a text!';
  24.         }
  25.        
  26.         if (count($errors)> 0)
  27.         {
  28.             $params = array();
  29.             $params['article'] = $data;
  30.             $params['errors' ] = $errors;
  31.             $params['title'  ] = 'TravelloBlog - Verify article';
  32.        
  33.             $this->buildForm($params);
  34.            
  35.             return;
  36.         }
  37.        
  38.         $this->saveData($data);
  39.     }

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:

Screen 2: Daten verifizieren

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. private function saveData($data)
  2.     {
  3.         $newDate = date('Y-m-d H:i:s');
  4.        
  5.         $data['art_user_id'] = '1';
  6.         $data['art_cdate'  ] = $newDate;
  7.         $data['art_udate'  ] = $newDate;
  8.        
  9.         $article = new ArticleModel();
  10.        
  11.         $art_id = $article->insert($data);
  12.        
  13.         $url = Zend::registry('router')->getRewriteBase();
  14.         $url.= '/article/show/' . $art_id;
  15.        
  16.         $this->_redirect($url);
  17.     }

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. Mit Hilfe der Rewrite Basis erstellen wir eine URL für die Weiterleitung, um den neuen Artikel gleich anzuzeigen. Die _redirect() Methode führt die Weiterleitung durch. 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:

Screen 3: Artikel anzeigen

Aufräumarbeiten

Bevor wir uns um das Ändern bestehender Artikel kümmern, müssen wir wieder einmal ein wenig aufräumen. Es gibt nun das Problem, dass die Methode validateAction nicht direkt über den Browser aufgerufen werden sollte.

Deshalb fügen wir in der Aktionsmethode validateAction folgende Abfrage ein:

PHP:
  1. public function validateAction()
  2.     {
  3.         if (!isset($_POST['button_save']))
  4.         {
  5.             $url = Zend::registry('router')->getRewriteBase();
  6.             $url.= '/article/';
  7.            
  8.             $this->_redirect($url);
  9.         }
  10.        
  11.         [...]
  12.     }

Dadurch leiten wir bei einem direkten Aufruf der validateAction auf die Artikelliste zurück. Natürlich kannst du auch auf das Formular zum Anlegen eines neuen Artikels umleiten.

Da wir die Ermittlung der Rewrite Basis jedoch schon an einer anderen Stellen benötigt haben, führen wir nun noch eine kleine Hilfsmethode getRewriteBase() ein, die wir als privat deklarieren.

PHP:
  1. private function getRewriteBase()
  2.     {
  3.         $url = Zend::registry('router')->getRewriteBase();
  4.        
  5.         return $url;
  6.     }

Nun lässt sich unsere Abfrage in validateAction deutlich vereinfachen:

PHP:
  1. public function validateAction()
  2.     {
  3.         if (!isset($_POST['button_save']))
  4.         {
  5.             $url = $this->getRewriteBase() . '/article/';
  6.            
  7.             $this->_redirect($url);
  8.         }
  9.        
  10.         [...]
  11.     }

Zuguterletzt können wir in saveData die Umleitung am Ende der Methode optimieren:

PHP:
  1. private function saveData()
  2.     {
  3.         [...]
  4.        
  5.         $url = $this->getRewriteBase() . '/article/show/' . $art_id;
  6.        
  7.         $this->_redirect($url);
  8.     }

Artikel ändern

Um einen Artikel ändern zu können, bearbeiten wir als erstes das Template "show.php" und ergänzen es um einen Link zum Ändern des Artikels.

PHP:
  1. <h2><?php echo $this->escape($this->article['art_title']); ?></h2>
  2. <p><em><?php echo $this->escape($this->article['art_cdate']); ?></em></p>
  3. <p><?php echo $this->escape($this->article['art_text']); ?></p>
  4. <hr>
  5. <a href="article/">back to list</a> |
  6. <a href="article/change/<?php echo $this->escape($this->article['art_id']); ?>">change article</a>

Danach ändern wir unsere Aktionsmethode changeAction im ArticleController:

PHP:
  1. public function changeAction()
  2.     {
  3.         $art_id = $this->_getParam('id');
  4.        
  5.         $article = new ArticleModel();
  6.        
  7.         $row = $article->find($art_id);
  8.        
  9.         $params = array();
  10.         $params['article'] = $row->toArray();
  11.        
  12.         $params['errors'] = array();   
  13.        
  14.         $params['title'] = 'TravelloBlog - Update article';
  15.        
  16.         $this->buildForm($params);
  17.     }

Zuerst wird die Id des Artikels aus den Parametern übernommen und der Datensatz gelesen. Die Werte des Artikels werden dann an die formAction übergeben, um das Formular anzuzeigen. Wenn du dir einen Artikel anzeigen lässt und auf den "change article" Link klickst, sollte das in etwa so aussehen:

Screen 4: Artikel aktualisieren

Bevor du die Daten jedoch änderst und abspeicherst, müssen wir unsere Methode saveData noch ein wenig anpassen. Bisher war die Methode nur für das Anlegen neuer Artikel ausgerichtet. Die vollständige saveData Methode sieht dann so aus:

PHP:
  1. private function saveData($data)
  2.     {
  3.         $newDate = date('Y-m-d H:i:s');
  4.        
  5.         $article = new ArticleModel();
  6.        
  7.         if (isset($data['art_id']))
  8.         {
  9.             $art_id = $data['art_id'];
  10.            
  11.             $row = $article->find($art_id);
  12.            
  13.             $row->artUdate  = $newDate;
  14.             $row->artTitle  = $data['art_title' ];
  15.             $row->artTeaser = $data['art_teaser'];
  16.             $row->artText   = $data['art_text'  ];
  17.            
  18.             $row->save();
  19.         }
  20.         else
  21.         {
  22.             $data['art_user_id'] = '1';
  23.             $data['art_cdate'  ] = $newDate;
  24.             $data['art_udate'  ] = $newDate;
  25.        
  26.             $art_id = $article->insert($data);
  27.         }
  28.        
  29.         $url = $this->getRewriteBase() . '/article/show/' . $art_id;
  30.        
  31.         $this->_redirect($url);
  32.     }

Wenn bereits eine Artikel Id vorhanden ist, wird der Datensatz aktualisiert, ansonsten wird ein neuer Datensatz angelegt. Bitte teste das Ganze einmal, indem du einen bestehenden Artikel veränderst.

Die saveData Methode ließe sich noch ein wenig optimieren, indem du das Aktualisieren und das Erstellen in eigene private Methoden auslagerst. Wir wollen es an dieser Stelle aber dabei belassen. Das Anlegen neuer Artikel funktioniert nun genauso gut, wie das Speichern vorhandener Artikel.

View Hilfsmethoden

Zend_View stellt einige nützliche Hilfsmethoden zum Erstellen von Formularelementen bereit. Dadurch wird die Ausgabe von Texteingabefeldern, Checkboxen und Submit Buttons ein wenig vereinfacht. Für weitere Details schaue bitte auch in das Kapitel zu den View Hilfsmethoden im Manual.

Die Verwendung der View Hilfsmethoden erschließt sich am einfachsten an einem praktischen Beispiel. Öffne deshalb noch einmal das Template für das Artikelformular "form.php" im Verzeichnis "/travelloblog/application/views/article" und ändere es wie folgt:

PHP:
  1. <form action="<?php echo $this->form_action; ?>" method="post">
  2. <?php if (isset($this->article['art_id'])) echo $this->formHidden('art_id', $this->article['art_id'], array('id' => 'art_id')); ?>
  3. <fieldset>
  4. <legend>Article data</legend>
  5. <table>
  6. <tr>
  7. <td><label for="art_title">Title</label></td>
  8. <td>
  9. <?php if (isset($this->errors['art_title'])) : ?><div class="error"><?php endif; ?>
  10. <?php echo $this->formText('art_title', $this->article['art_title'], array('id' => 'art_title', 'maxlength' => 64)); ?>
  11. <?php if (isset($this->errors['art_title'])) : ?><br/><?php echo $this->escape($this->errors['art_title']); ?></div><?php endif; ?>
  12. </td>
  13. </tr>
  14. <tr>
  15. <td><label for="art_teaser">Teaser</label></td>
  16. <td>
  17. <?php if (isset($this->errors['art_teaser'])) : ?><div class="error"><?php endif; ?>
  18. <?php echo $this->formText('art_teaser', $this->article['art_teaser'], array('id' => 'art_teaser', 'maxlength' => 255)); ?>
  19. <?php if (isset($this->errors['art_teaser'])) : ?><br/><?php echo $this->escape($this->errors['art_teaser']); ?></div><?php endif; ?>
  20. </td>
  21. </tr>
  22. <tr>
  23. <td><label for="art_text">Text</label></td>
  24. <td>
  25. <?php if (isset($this->errors['art_text'])) : ?><div class="error"><?php endif; ?>
  26. <?php echo $this->formTextarea('art_text', $this->article['art_text'], array('id' => 'art_text', 'rows' => 10)); ?>
  27. <?php if (isset($this->errors['art_text'])) : ?><br/><?php echo $this->escape($this->errors['art_text']); ?></div><?php endif; ?>
  28. </td>
  29. </tr>
  30. <tr>
  31. <td>&nbsp;</td>
  32. <td><?php echo $this->formSubmit('button_save', 'save article', array('class' => 'button')); ?></td>
  33. </tr>
  34. </table>
  35. </fieldset>
  36. </form>
  37. <hr>
  38. <a href="article/">back to list</a>

Achte besonders auf die Verwendung der Hilfsmethoden formHidden(), formText(), formTextarea() und formSubmit(). Ob du diese Hilfsmethoden verwendest, bleibt natürlich dir überlassen. Ich finde sie eigentlich recht nützlich, weshalb wir sie in diesem Tutorial in Zukunft weiter verwenden werden.

Übrigens kannst du dir auch eigene Hilfsmethoden für die Verwendung in deinen Views erstellen. Im Manual gibt es einen eigenen kurzen Abschnitt, wie man eigene Helfer schreibt.

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.php" mit einem Link zum Löschen des Artikels.

PHP:
  1. [...]
  2. <a href="article/">back to list</a> |
  3. <a href="article/change/<?php echo $this->escape($this->article['art_id']); ?>">change article</a> |
  4. <a href="article/delete/<?php echo $this->escape($this->article['art_id']); ?>">delete article</a>

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

PHP:
  1. <h2><?php echo $this->escape($this->article['art_title']); ?></h2>
  2. <p><em><?php echo $this->escape($this->article['art_cdate']); ?></em></p>
  3. <p><?php echo $this->escape($this->article['art_text']); ?></p>
  4. <hr>
  5. <p>
  6. <form action="<?php echo $this->form_action; ?>" method="post">
  7. <?php echo $this->formSubmit('button_delete', 'delete article', array('class' => 'button')); ?>
  8. </form>
  9. </p>
  10. <hr>
  11. <a href="article/">back to list</a>

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

PHP:
  1. public function deleteAction()
  2.     {
  3.         $art_id = $this->_getParam('id');
  4.        
  5.         $article = new ArticleModel();
  6.         $row = $article->find($art_id);
  7.        
  8.         $data = $row->toArray();
  9.        
  10.         $view = Zend::registry('view');
  11.        
  12.         $view->assign('title', 'TravelloBlog - Delete article');
  13.         $view->assign('form_action', 'article/doDelete/' . $art_id);
  14.         $view->assign('article', $data);
  15.         $view->assign('subtemplate', 'article/delete.php');
  16.        
  17.         echo $view->render('main.php');
  18.     }

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

Screen 5: Artikel löschen

Jetzt fehlt nur noch die neue Aktionsmethode doDeleteAction in unserem ArticleController:

PHP:
  1. public function doDeleteAction()
  2.     {
  3.         if (!isset($_POST['button_delete']))
  4.         {
  5.             $url = $this->getRewriteBase() . '/article/';
  6.            
  7.             $this->_redirect($url);
  8.         }
  9.        
  10.         $art_id = $this->_getParam('id');
  11.        
  12.         $article = new ArticleModel();
  13.         $db = $article->getAdapter();
  14.        
  15.         $where = $db->quoteInto('art_id = ?', $art_id);
  16.        
  17.         $article->delete($where);
  18.  
  19.         $url = $this->getRewriteBase() . '/article/';
  20.        
  21.         $this->_redirect($url);
  22.     }

Ähnlich wie bei validateAction fügen wir zu Beginn eine Sicherung ein, damit die Aktion nicht direkt aufgerufen wird. Danach ermitteln wir die Id des Artikels und löschen ihn. Zum Schluss leiten wir wieder auf die Liste der Artikel zurück. Das war es dann schon mit dem Löschen eines Artikels.

Ü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.

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 sechsten Teil kann herunter geladen werden. Hier sind auch alle Templates 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 sechsten Teil des Zend Framework Tutorials haben wir die Formularverarbeitung mit Hilfe des Zend Frameworks 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. Danach wird das TravelloBlog zumindest schon einmal rudimentär laufen.

Change Log

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

  • 28.09.2006: Fehler in Abschnitt Aufräumarbeiten korrigiert; dort stand im ersten Quellcode formAction statt validateAction (Danke Sven)
  • 08.10.2006: Erstellen eines neuen Datums vereinfacht (danke Peter)
  • 05.11.2006: Tutorial für neues Release 0.2.0 aktualisiert

Navigation

47 Antworten für “Zend Framework Tutorial Teil 6: MVC Design Pattern und Formularverarbeitung”

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

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

  2. Ralfs PHP Blog » Zend Framework Tutorial Teil 1: Einführung und Anforderungen sagt:

    [...] MVC Design Pattern und Formularverarbeitung [...]

  3. Kaiuwe sagt:

    Ersteinmal danke für die ausführliche Einführung in das Zend-Framework.

    Hier nun aber meine Frage: Wäre es nicht sinnvoll gewesen, die Klasse "Zend_Filter_Input" gleich zu verwenden bzw. eine Überarbeitung der Formularvalidierung im nächsten Teil des Tutorials zu behandeln?!
    Ich halte es für eine Pflicht, die Daten ordnungsgemäß auf Typ und Inhalt von Anfang an zu prüfen. Die Klasse "Filter_Input" greift uns hierbei doch wunderbar unter die Arme.

    Freue mich schon auf die nächsten Teile, aber leider sind das ja noch Wochen...! ;-)

  4. Ralf Eggert sagt:

    Hallo Kaiuwe,

    danke für dein Feedback. Natürlich ist es etwas suboptimal, wenn Zend_Filter_Input im Tutorial nicht direkt bei der Formularverarbeitung verwendet wird. Mein Ziel war es aber, im Grossen und Ganzen in jedem Teil des Tutorials eine Komponente vorzustellen. Zend_Filter_Input kommt aber später auf jeden Fall.

    http://www.ralfeggert.de/2006/08/26/einfuehrung-und-anforderungen/#aufbau

    Außerdem sind derzeit mit Zend_Validator und Zend_Form noch andere Komponenten in der Planung und Entwicklung, so dass dieses Tutorial Teil sowieso irgendwann überarbeitet werden muss, bzw. ein weiteres Kapitel für Zend_Form eingefügt werden muss. Das Tutorial wird sich also stetig weiter entwickeln.

    Gruß,

    Ralf

  5. Kaiuwe sagt:

    Das "Zend_Filter_Input" noch behandelt wird, hatte ich schon gesehen, nur war ich etwas verwirrt weshalb es nicht gleich genutzt bzw. nicht im darauffolgenden Teil behandelt wird. Aber keine Angst, es wurde ja alles verstanden! :-)

    Weiss man schon genaueres von "Zend_Form" bzw. "Zend_Validator"? Momentan sieht "Zend_Form" fast wie das PEAR-Paket "HTML_Quickform" aus. Nicht das ich Quickform schlecht finde, denn damit habe ich ebenfalls schon viel umgesetzt, aber irgendwie passt es nicht so ganz in das "Zend_Framework". (Da fällt mir auch gleich "Seagull" ein...!)

  6. Ralf Eggert sagt:

    Hallo Kaiuwe,

    das Proposal zu Zend_Form gibt derzeit nicht mehr den aktuellen Stand der Diskussion wieder. Ich sitze derzeit daran, das bestehende Proposal grundlegend zu überarbeiten. Danach wird es wohl nicht mehr allzuviele Ähnlichkeiten mit HTML_QuickForm haben. Die einzelne Teile wie Formaufbau, Validierung, Rendering oder Ausgabe werden dann nicht mehr so stark miteinander verbunden sein. Aber dennoch wird Zend_Form einfach zu bedienen und zugleich leicht zu erweitern sein.

    Gruß,

    Ralf

  7. Felix Pfeiffer sagt:

    Hallo Ralf,
    gibt es eine möglichkeit den Inhalt des Tutorials auszudrucken? Sowohl Firefox als auch Opera und IE zeigen zwar den Hed-Bereich und die Blöcke auf der rechten Seite an, aber der Inhalt wird irgendwie ausgeblendet.
    Mit nur einem monitor ist es nicht so einfach die Übersicht zwischen Tutorial und Programmierfenster zu behalten. Ausserdem lässt es sich auf Papier besser lesen ;-)

    Evtl. hast du ja eine Idee, wie das gehen könnte.

    Danke, Felix

  8. Tobias sagt:

    Hallo Felix,
    das hatte ich auch schon gefragt (irgendwo beim ersten oder zweiten Teil des Tutorials), aber leider ist das Druck Modul für die genutzte Blogsoftware nicht so leicht zu integrieren.

    Ich mache das zur Zeit so:
    Markieren - Kopieren - in Word einfügen - drucken

    Gruß
    Tobias

    PS: Wenn das Druckmodul nicht leicht einzurichten ist, wie ist es dann mit einem Export PDF Modul?

  9. Felix Pfeiffer sagt:

    Naja, was mich wundert ist, dass die "Board-Funktionen" der drei genannten Browser das nicht hinbekommen haben. Die drucken ja sonst alles ;-)

  10. Sven Klever sagt:

    Hallo Ralf,

    ersteinmal vielen Dank für dieses bisher sehr gelungene Tutorial über das Zend-Framework.

    Beim durchlesen und -arbeiten dieses Teils ist mir eine Kleinigkeit aufgefallen: Am Anfang der "Aufräumarbeiten" beim Einbau der Abfrage, ob das Formular abgeschickt wurde, sollte es da im Quelltext-Beispiel nicht "public function validateAction(){...}" anstatt "public function formAction(){...}" heißen?

    Gespannt auf die nächsten Teile des Tutorials verbleibe ich mit freundlichen Grüßen aus der Stadt, wo die Füherscheine Urlaub machen

    Sven

  11. Ralf Eggert sagt:

    Moin Tobias und Felix,

    leider zerschiesst das Theme, das ich hier im Blog einsetze, die Druckansicht total. Ich werde mal schauen, dass ich die entsprechende CSS Datei mal auf Vordermann bringe, damit man die Texte auch ausdrucken kann. Beim Ausdruck kann ich auf die meisten Dinge in der Ausgabe ja verzichten, entscheidend ist nur dass der Text und der Code richtig rüber kommt.

    Bitte ein wenig Geduld.

    Gruß,

    Ralf

  12. Ralf Eggert sagt:

    Moin Sven,

    danke für den Hinweis. Habe den Fehler korrigiert.

    Gruß,

    Ralf

  13. Kaiuwe sagt:

    Hallo Ralf,
    sehe gerade, das du ja an der Form-Komponente beteiligt bist. Nicht schlecht. Dann wollen wir mal hoffen, das es auch ein ausführliches Kapitel hier im Tutorial gibt! ;-)
    Wann kann man sich ein Bild vom Quellcode machen?

    Gruß
    Kaiuwe

  14. Ralf Eggert sagt:

    Hallo Kaiuwe,

    also für Zend_Form gibt es eigentlich noch keinen Quellcode außer ein paar Klassendefinitionen. Wir hoffen natürlich zumindest zur Version 1.0 eine nutzbare Zend_Form Komponente zu haben. Das kann aber noch ein wenig dauern.

    Viele Grüsse,

    Ralf

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

    [...] Im sechsten Teil vom Zend Framework Tutorial hhaben wir mit Hilfe der Zend_View Hilfsmethoden die Formularverarbeitung für unser TravelloBlog erstellt. Wir haben ein Formulartemplate erstellt, die Validierung eingerichtet und die Daten in der Datenbank gespeichert. Zudem haben wir Funktionen für das Ändern und Löschen bestehender Artikel eingerichtet. Wenn du die ersten sechs Teile noch nicht gelesen hast, hole dies bitte schnell nach. [...]

  16. Peter Schnitzel sagt:

    Hi Ralf,
    nur eine Frage kosmetischer Natur, warum erzeugst du dir dein Datum so verworren mit soviel tippen verbunden auf diese Art:
    $newDate = date('Y') . '-' . date('m') . '-' . date('d') . ' ';
    $newDate.= date('H') . ':' . date('i') . ':' . date('s');

    Wenn du doch auch mit dieser einen Zeile auskommen würdest:
    $newDate = date("Y-m-d H:i:s");

    Wahrscheinlich eine Stilfrage, was man lieber mag und im Endeffekt ist es auch egal, aber es ist halt doch tippfreundlicher und übersichtlicher (:

    mfg
    Peter

  17. Ralf Eggert sagt:

    Hallo Peter,

    das ist eine sehr gute Frage und, wenn ich ehrlich bin, weiss ich auch nicht, was mich da geritten hat. Natürlich ist deine Variante viel besser und vor allem einfacher. Manchmal sieht man den Wald vor lauter Bäumen nicht mehr... ;-)

    Gruß,

    Ralf

  18. Marc sagt:

    Hallo Ralf,
    zunächst einmal Vielen Dank für dieses hervoragende Tutorial :)

    Ich habe ein Problem mit dem Redirect z.B. bei "validate":
    Fatal error: Uncaught exception 'Zend_Controller_Action_Exception' with message 'Cannot redirect because headers have already been sent.' in /entwicklung/library/Zend/Controller/Action.php:192 Stack trace: #0 /entwicklung/application/controllers/ArticleController.php(154): Zend_Controller_Action->_redirect('/article/') #1 /entwicklung/library/Zend/Controller/Action.php(118): ArticleController->validateAction() #2 /entwicklung/library/Zend/Controller/Dispatcher.php(185): Zend_Controller_Action->run(Object(Zend_Controller_Dispatcher), Object(Zend_Controller_Dispatcher_Token)) #3 /entwicklung/library/Zend/Controller/Dispatcher.php(136): Zend_Controller_Dispatcher->_dispatch(Object(Zend_Controller_Dispatcher_Token), true) #4 /entwicklung/library/Zend/Controller/Front.php(254): Zend_Controller_Dispatcher->dis in /entwicklung/library/Zend/Controller/Action.php on line 192

    Ich habe mal zur Kontrolle deine .zip genommen, selber Fehler.. Die Zend Version ist die 0.1.5

    Hast Du evtl. eine Idee?

    Viele Grüsse,
    Marc

  19. Ralf Eggert sagt:

    Hallo Marc,

    da bin ich momentan auch überfragt, weil bei mir alles funktioniert. Das kann eigentlich nur auftreten, wenn vor dem Redirect schon irgend eine Ausgabe an den Browser übergeben worden ist. Da muss ich selber nochmal genauer schauen...

    Gruß,

    Ralf

  20. Marc sagt:

    Hey,
    wenn man nach einem Tag noch einmal schaut sieht man meistens mehr :)
    Als kleiner Tipp für andere die solche Probleme haben: Einfach ein header("Location: test.html"); einbauen. Dadurch bekommt man eine exakte Fehlermeldung wo die Ausgabe schon gestartet wird. Ich hatte in der set_include_path.php einfach 2 Leerzeilen drin..

    Ansonsten, weiter so :)

    Gruß,
    Marc

  21. Ralf Eggert sagt:

    Hallo Marc,

    ja genau, das hatte ich mir fast gedacht. Ist dann aber oft schwer so etwas zu finden.

    Gruß,

    Ralf

  22. tauven sagt:

    Hallo zu dem Problem von Marc:
    hatte das gleiche Problem und bei mir lag es dadran das meine datei utf8 kodiert war.
    von utf8 auf ansi gestellt und das problem ist weg.

    auswelchem grund das passiert weiss ich aber leider auch nicht.

    ciao,
    tauven

  23. J.Wachtel sagt:

    @tauven
    Wo hast du das umgestellt?
    Ich habe es in der main.php probiert, allerdings erfolglos.

    meine set_include_path sollte auch in Ordnung sein. Ich weiß nicht wie ich den Fehler wegbekomme.
    Nutze das xampp paket für Windows

  24. tauven sagt:

    Hall J. Wachtel,
    verwende notepad++ als editor dort kann man das encoding der dateien an sich auf utf8 bzw ansi umstellen.
    weiss mitllerweile nicht mehr welche datei es war, zur not halt alle dateienw elche du selbst geschrieben hast auf ansi umstellen.
    mehr kann ich dazu leider auch nicht sagen.
    ciao,
    tauven

  25. J.Wachtel sagt:

    Danke tauven!
    Leider ist auch das erfolglos, ich habe alles manuell mit Notepad auf "ANSI" geändert, kann leider so nicht mit dem Tutorial weitermachen.

    Es ist ja im Prinzip nur die Weiterleitung die nicht funktioniert. Eingetragen wird der Text ja und lässt sich auch über /article betrachten.

    Die Fehlermeldung ist diesselbe wie oben schonmals geschrieben.

    Ich habe die Dateien mittels Eclipse 3.2 geschrieben.
    Werde nachher mal probieren ob das zip package bei mir funktioniert.

  26. J.Wachtel sagt:

    Ich werd verrückt!
    Darauf muss man erstmal kommen.
    Ich konnte auf einer englischen Seite folgendes zu dem Problem entdecken.

    ----------------------------------------------------------------------------------------------------
    zitat:
    I ran into that problem myself, until I realized I had output buffering turned on in my php.ini (I use the recommended php.ini and tweak it where necessary).

    If you don't have access to (or don't want to change) php.ini, you can set this in .htaccess like so:

    php_value output_buffering "4096"

    You can change the number to any value you want, or just to "On".

    Hope this works for you and anyone else having this problem!
    -------------------------------------------------------------------------------------

    Das ganze hat geholfen, vielleicht könnte man das noch im Tutorial einfügen, damit andere nicht beim selben Problem stehen.

    gruß Jens

    endlich geht's weiter ;-)

  27. Michi sagt:

    Hallo

    Ich bin gerade dabei mit Hilfe diese Tutorials ein kleines Gästebuch zu bauen. Ich habe in meinem Controller die Funktion getRewriteBase() eingefühgt, wie in diesem Teil des Tutorials beschrieben und bekomme nun folgenden Fehler:

    Fatal error: Call to undefined method Zend_Controller_RewriteRouter::getRewriteBase() in C:\wamp\www\guestbook\application\controllers\EntryController.php on line 108

    (wird in der Funktion saveData() erzeugt, nachdem die Daten erfolgreich in der Datenbank gespeichert wurden und mit _redirect() wieder auf den Eintrag zurück geroutet werden sollte.)

    Ich habe den Router in der index.php erzeugt und in den Objektspeicher geschrieben, aber irgend etwas scheint nicht korrekt zu sein. Hat möglicherweise jemand einen Tipp, an was es liegen könnte? Ich komme nicht mehr weiter.

    Besten Dank im Voraus!

    Gruss
    Michi

  28. Ralf Eggert sagt:

    Hallo Michi,

    dieser Teil des Tutorials ist noch nicht auf das ZF Release 0.6.0 umgestellt. Deshalb kann es durchaus zu Problemen kommen, die durch den Wechsel entstanden sind. Bitte habe noch ein wenig Geduld, bis dieser Tutorial Teil auch umgestellt worden ist.

    Gruß,

    Ralf

  29. Nilson sagt:

    Hallo Michi...ich hatte den gleichen Fehler :)

    Also ganz einfach in deiner Bootstrap datei haste ja den Controller instanziert.

    Den lädste nun in die Registry, denn ab der Version 0.6 befindet sich der RewriteBaseUrl in dieser Klasse.

    Also Zend::register('front', $controller);

    Dann kannste in deinem Controller die Baseurl so holen:

    $controller = Zend::registry('front');
    $baseurl = $controller->getBaseUrl();

    Hoffe konnte dir damit helfen ;-)

    MFG Nilson

  30. Hias sagt:

    Hi Michi,

    du kannst auch einfach den Front Controller verwenden. Is ein Singleton.

    Also so:

    $url = Zend_Controller_Front::getInstance()->getBaseUrl();

    Vielleicht hilfts ja :)
    Hias

  31. Alex sagt:

    Hallo Ralf,

    ich bin jetzt bis zu dem Punkt gekommen bei dem du beschreibst:

    "Wenn bereits eine Artikel Id vorhanden ist, wird der Datensatz aktualisiert, ansonsten wird ein neuer Datensatz angelegt. Bitte teste das Ganze einmal, indem du einen bestehenden Artikel veränderst."

    Ich habe alle Warnungen miss achtet und deine Tutorial auf ZF 0.9 aufgesetzt, geht auch super soweit, die Exceptions sind recht aussagekräftig.

    Doch leider habe ich anscheinend etwas übersehen, wenn ich ein Article update, füllt er die Id falsch ein, z.b. versuche ich article 11 zu updaten, er schreibt die Änderungen aber immer
    in article id 1 rein.

    mir fehlt nur das dann hätte ich bis hier hin alles auf Version 0.9 laufen, falls du meine Änderungen haben willst kann ich dir die gerne zur Verfügung stellen, oder in einem wiki *blinzel*

    schönen gruss
    Alex

  32. Bernhard sagt:

    Ich habe das Framework 0.9.0 und habe nun die Version 6 Deines Tutorials heruntergeladen.
    Ich habe nun folgende Probleme:
    1. Ich bekomme einige Notices: Zend::loadClass deprecated since 0.9.0, use Zend_Loader::loadClass() instead in [..]/Zend.php
    2. ich bekomme den folgenden Fatal Error:Call to undefined method Zend_Controller_Router_Rewrite::setRewriteBase() in [..]/index.php
    Ich habe in der Doumentation zum Framework nachgeschaut, aber noch nichts gefunden. Nun trete ich auf der Stelle.

  33. Pierre Minnieur sagt:

    Bernhard:

    1) nutze stattdessen Zend_Loader::loadClass (so wie es die Fehlermeldung empfiehlt). Mit Version 0.9.0 wurden einige Dinge umgebaut, sodass dieses Tutorial nicht einwandfrei funktionsfähig ist. Das heißt, das nun einige Funktionen in anderen Klassen anzutreffen sind.

    2) Auch hier bist du Opfer des Wandels geworden. Benutze stattdessen die Funktion setBaseUrl im Front-Controller.

    Angehängt mal eine meiner Boostrap-Dateien, die für Version 0.9.0 überarbeitet wurde:

    framework->session->asArray(),
    array('save_path' => $tmp_session_dir)));

    // Initialize session
    Zend_Session::start();

    // Database connection
    $database = Zend_Db::factory($config->database->adapter, $config->database->params->asArray());
    Zend_Registry::set('database', $database);

    // Populate connection as default adapter for Zend_Db_Table
    Zend_Db_Table::setDefaultAdapter($database);

    // Front controller
    $controller = Zend_Controller_Front::getInstance();
    Zend_Registry::set('controller', $controller);

    // Bootstrap controller
    $controller->setControllerDirectory($app_controller_dir);
    $controller->setBaseUrl('/');

    // Set default controller / action
    $controller->setDefaultControllerName('default');
    $controller->setDefaultAction('index');

    // Rewrite router
    $router = $controller->getRouter();
    $router->removeDefaultRoutes();
    Zend_Registry::set('router', $router);

    // Add routes from configuration
    $router->addConfig($config, 'routes');

    // Request
    $request = $controller->getRequest();
    Zend_Registry::set('request', $request);

    // Response
    $response = $controller->getResponse();
    Zend_Registry::set('response', $response);

    // View
    $view = new Zend_View;
    Zend_Registry::set('view', $view);

    // Bootstrap view
    $view->setEncoding($config->framework->encoding);
    $view->setScriptPath($app_view_dir);
    $view->setHelperPath($app_helper_dir, $config->framework->classes->helper);

  34. Pierre Minnieur sagt:

    Huch, na da hat's wohl die Kommentarfunktion verschluckt. Eventuell kann Ralf ja mal das Kommentar bei Gelegenheit reparieren, die Bootstrap-Datei erscheint ja erst auf halber Strecke :)

  35. Bernhard sagt:

    Hallo Pierre,

    Vielen Dank für Deine prommte Hilfe.

    ich habe nun die Notices und den Fatal Error gefixt.
    Nun habe ich die URL mit "/article" aufgerufen und bekomme nun einen sehr langen Hinweis auf die Lizenzbedingungen.
    Danach habe ich den Fatal Error: Class 'Zend_Db_Table_Row_Abstract' not found in C:\projekte\www\testblog\library\zf\Zend\Db\Table\Row.php on line 40

    Watt nu?

    Bernhard

  36. Pierre Minnieur sagt:

    Saublöder Fehler Seitens Zend. Schau dir die Datei Zend\Db\Table\Row\Abstract.php mal in Zeile 1 an. Da fehlt eine spitze Klammer vor "?php" - die Datei wird folglich nicht von PHP interpretiert und die Klasse nicht gefunden. Vorerst reicht eine manuelle Korrektur indem du die spitze Klammer hinzufügst.

    Das mit den Lizenzbedingungen rührt übrigens auch daher ... ;)

  37. Bernhard sagt:

    Hallo Pierre,

    auch hier vielen Dank. Nun habe ich noch ein Problem:
    die Methode Zend_Db_Table->find gibt in jedem Falle ein Roeset zurück. In den Aktionen Ändern und löschen habe ich entsprechend $dta[0] statt $data übergeben. Nur beim Speichern der Änderung komme ich nicht richtig weiter.
    Mit Rowset->current() hole ich die aktuelle Row. var_dump zeigt mir auch genau was ich sehen will, aber danach bleibt die Seite leer und nichts passiert. kein Fehler und keine Verarbeitung.
    Hier mal mein Code:

    $art_id = $data['art_id'];

    $rowset = $article->find($art_id);
    $row = $rowset->current();

    var_dump($row); //Ergebnis Row mit Art_Id = $art_id

    $row->artUdate = $newDate;
    $row->artTitle = $data['art_title' ];
    $row->artTeaser = $data['art_teaser'];
    $row->artText = $data['art_text' ];

    $row->save();

    Was läuft hier falsch? In der Doku zum Framework steht auch, dass find ein Objekt vom Typ Row zurückliefert, wenn man nur eine Id übergibt.

    Bernhard

  38. Ole sagt:

    Hallo,

    habe ähnliche Probs wie Bernhard. Die Methode save() ist unbekannt. Liegt wohl daran, dass er mit find() ein rowset bekommt. Selbst wenn ich iteriere (dürfte ja nur eine Zeile sein bei der Suche auf dem Schlüssel) haut es nicht hin.

    Danke für Eure Hilfe

    Ole

  39. Micha sagt:

    Hatte auch ewig an dem Fehler gehangen. Das Problem bzw. die Probleme sind

    * die Methode find() liefert ein Rowset, obwohl wir nur ein Row anfassen und
    speichern wollen

    Hier kann man entweder mit fetchRow arbeiten oder aber mit einer foreach Schleife
    über das Rowset iterieren.

    * Das zweite Problem besteht darin, dass der Zugriff auf die Spalten nicht mehr im
    CamelCase erfolgen darf. Das Ändern der Atribute muss also folgendermaßen erfolgen:

    [...]
    $row->art_udate = $newDate;
    $row->art_title = $data['art_title' ];
    $row->art_teaser = $data['art_teaser'];
    $row->art_text = $data['art_text' ];
    $row->save();
    [...]

    Euch weiterhin viel Spass mit dem Tutorial & dem zend framework

    Micha

  40. Bernhard sagt:

    Hallo Ole und Micha,

    ich behelfe mir jetzt mit $row = $tablemodel->find($primaryKey)->current();

    Dann ist das Ergebnis eine Inzanz von Row, die man speichern kann.

    Mal am Rande:
    Wer kennt noch da Phänomen, dass Zend_Session offensichtlich nicht mit dem IE funktionieren. Ich muss das noch weiter testen, aber im Moment sieht es dnach aus.

    Grüße

    Bernhard

  41. Damian sagt:

    Hallo Pierre,

    die PHP-Welt ist wirklich klein.. Kennst du vergleichbare Tuts zur neuen Version?

    Viele Grüsse
    Damian

  42. www.simonfella.de » Blog Archiv » Tutorial Zend Framework ver 0.2 sagt:

    [...] MVC Design Pattern und Formularverarbeitung [...]

  43. Carsten sagt:

    Hallo,

    Ich habe im Zend Framework wie im Tutorial die Anpassung der createAction-Methode vorgenommen, um das Artikelformular zu erstellen.

    Leider wird das Artikelformular bei mir nicht erzeugt. Als Bildschirmmeldung erhalte ich lediglich den Text "ArticleController::createAction()", d.h. es wird die CreateAction-Methode und die buildForm-Methode aufgerufen.

    Meine Vermutung ist, daß irgendetwas in der buildForm-Methode nicht richtig funktioniert. Meiner Meinung funktioniert das Rendern der View in der folgenden Quelltextzeile nicht:
    echo $this->view->render('main.phtml');

    Kann es sein, daß möglicherweise der Pfad zum phtml-File gesetzt ist ?

  44. Carsten sagt:

    So, bei mir war tatsächlich die Datei "main.phtml" in einem falschen Ordner.

    Ich habe diese Datei vom Verzeichnis "..\application\views\" in das Verzeichnis "..\application\views\scripts\" verschoben.
    Das Artikelformular wird nun auch unter Zend Framework 1.5 korrekt erstellt.

  45. Carsten sagt:

    Kaum ist das alte Problem behoben, habe ich schon wieder ein neues Problem.

    Während das Speichern eines neuen Artikels funktioniert, funktioniert das Ändern eines bestehenden Datensatzes nicht. Unter Zend Framework 1.5 erhalte ich beim Versuch, eine Änderung vorzunehmen, nach dem Klick auf den "save article"-Button die folgende Fehlermeldung:
    Fatal error: Uncaught exception 'Zend_Db_Statement_Exception' with message 'SQLSTATE[HY093]:
    Invalid parameter number:
    no parameters were bound' in ..\travelloblog\library\Zend\Db\Statement\Pdo.php:238 Stack trace:
    #0 ..\travelloblog\library\Zend\Db\Statement.php(283): Zend_Db_Statement_Pdo->_execute(Array) #1 ..\travelloblog\library\Zend\Db\Adapter\Abstract.php(406): Zend_Db_Statement->execute(Array) #2 ..\travelloblog\library\Zend\Db\Adapter\Pdo\Abstract.php(206): Zend_Db_Adapter_Abstract->query(Object(Zend_Db_Table_Select), Array) #3 ..\travelloblog\library\Zend\Db\Table\Abstract.php(1185): Zend_Db_Adapter_Pdo_Abstract->query(Object(Zend_Db_Table_Select)) #4 ..\travelloblog\library\Zend\Db\Table\Abstract.php(1082): Zend_Db_Table_Abstract->_fetch(Object(Zend_Db_Table_Select)) #5 ..\travelloblog\application\controllers\ArticleController.php(85): Zend_Db_Table_Abs in ..\travelloblog\library\Zend\Db\Statement\Pdo.php on line 238

    Hat jemand ein ähnliches Problem und kann evtl. weiterhelfen ?

  46. Carsten sagt:

    Das Problem mit dem fehlerhaften Update habe ich gelöst.

    Grund war eine fehlerhafte Artikel-ID, und zwar fehlte in meiner "form.phtml"-Datei das "article['art_id']; ?>"

  47. Tobi sagt:

    So, zum Thema Formularverarbeitung und Eingabevalidierung hab ich nun auch ein Tutorial geschrieben. Vielleicht ja interessant für Leser dieses Artikels (und den Autoren ;). Tutorial - Eingabevalidierung mit dem Zend Framework

Hinterlasse eine Antwort