Zend Framework Tutorial Teil 6:
Zend_Db
Im fünften Teil des Zend Framework Tutorials haben wir die View Komponente unseres TravelloBlogs mit Hilfe der Zend_View und Zend_Layout Komponenten des Zend Frameworks realisiert. Wir haben mit Zend_Layout ein zentrales Template für die Anzeige der im nächsten Kapitel kommenden Artikelliste und die Ausgabe eines Artikels erstellt und dieses Template mit Hilfe von Zend_View ausgegeben. Zudem haben wir dem Projekt mit Hilfe von CSS ein wenig Design verpasst.
In diesem Teil dieses Tutorials kümmern wir uns um den Model Part unserer Anwendung. Dabei lernen wir die Zend_Db Komponente mit ihren diversen Teilkomponenten kennen und werden diese in unserem TravelloBlog auch einbinden.
Wenn du über neue Tutorial Teile informiert werden möchtest, abonniere am besten den Feed dieses Blogs. Dann verpasst du garantiert keinen Teil des Tutorials. Es gibt auch Übersicht mit den bisher erschienen Teilen des Tutorials.
---> ab hier noch nicht aktualisiert = v1.7.8 <---
Inhaltsverzeichnis
- Datenbankmodell
- Zend_Db
- Zend_Db_Adapter
- Zend_Db_Table
- Zend_Db_Table_Rowset und Zend_Db_Table_Row
- Aufräumarbeiten
- registerAutoload nutzen
- Zeilen lesen
- Zeilen ändern
- Zeilen anlegen
- Zeilen löschen
- __call() Methode
- Übung: die weiteren Model Klassen
- Download
- Zusammenfassung
- Navigation
- Kommentare
Datenbankmodell
Unsere Datenbank werden wir in einer MySQL Datenbank ablegen. Jedoch sollte das zu erstellende Datenbankmodell auch in SQLite sowie anderen Datenbanken verwendet werden können.
Um unser Datenbankmodell erstellen zu können, wenden wir uns wieder den Anforderungen an unser TravelloBlog aus dem ersten Teil dieses Tutorials zu. Hilfreich ist dabei auch die Liste der Entitäten, die wir im vierten Teil des Tutorials ermittelt haben.
Für jede der ermittelten Entitäten würde es sich anbieten, eine eigene Datenbanktabelle zu erstellen. Die einzige Ausnahme ist die Entität "Suchindex", weil wir den Suchindex erst später mit Hilfe der Zend_Search Komponente anlegen werden und wir uns dann um die Datenstruktur kümmern können. Folglich erstellen wir für die restlichen fünf Entitäten jeweils eine Datenbanktabelle.
Um die Datenbanktabelle "user" für die Benutzerdaten nicht zu sehr aufzublähen, lagere ich das in Anforderung 2 geforderte Profil in eine eigene Datenbanktabelle aus. Zudem benötigen wir für die in Anforderung 4 geforderten Zuordnungen von beliebig vielen Kategorien bzw. Tags zu einem Beitrag noch zwei weitere Verknüpfungstabellen. Insgesamt kommen wir also vorerst auf acht Tabellen:
- article
- comment
- tag
- category
- user
- profile
- art2tag (Verknüpfungstabelle zwischen article und tag)
- art2cat (Verknüpfungstabelle zwischen article und category)
Anhand der weiteren Anforderungen ermitteln wir dann, welche Tabelle welche Felder oder Spalten benötigt. Diese ergänzen wir dann um weitere sinnvolle Felder. Insgesamt sieht unser Datenbankmodell dann wie folgt aus:

Hinweis:
Erstellt habe ich das Datenbankmodell mit dem DBDesigner4, einer Software zum Modellieren von Datenbanken, die aktuell leider nicht mehr weiter entwickelt wird. Das Projekt wird aber von MySQL mit der MySQL Workbench fortgeführt, welche Bestandteil des MySQL GUI Tools Bundles ist. Leider ist die Workbench jedoch noch etwas fehlerbehaftet, so dass ich derzeit weiterhin mit DBDesigner4 arbeite.
In der Zip Datei, die du weiter unten downloaden kannst, ist ein MySQL Dump für die Tabellenstruktur enthalten. Ich habe den Dump noch um einige Beispieldaten angereichert, damit du beim Abfragen der Datenbank gleich etwas sehen kannst. Diesen Dump spielst du am besten in eine neue Datenbank ein. Ich habe meine der Einfachheit halber "travelloblog" benannt.
Zend_Db
Nun, wo die Datenbankstruktur steht und wir eine Datenbank angelegt und mit Daten befüllt haben, können wir endlich in die Zend_Db Komponente einsteigen. Die Zend_Db Komponente besteht derzeit (Version 1.7.0) aus sieben Teilkomponenten, die ich kurz vorstellen möchte.
Zend_Db_Adapter stellt die Datenbankabstraktionsschicht für das Zend Framework bereit und setzt auf die Erweiterung PDO auf, die seit PHP 5.1 fester Bestandteil von PHP ist. Zend_Db_Adapter ist für den Verbindungsaufbau zu einer Datenbank zuständig und stellt Funktionen für das Quoten von Parametern, für Transaktionen sowie für die Datenbankoperationen Einfügen (Insert), Aktualisieren (Update), Löschen (Delete) und Selektieren (Select) bereit.
Zend_Db_Statement basiert auf dem PDOStatement Objekt aus der PHP Data Objects Erweiterung, d.h es kann auch ein Statement-Objekt verwendet werden, um zusätzliche Möglichkeiten beim Ausführen von Abfragen und holen von Ergebnissätzen zu erhalten.
Zend_Db_Profiler ist eine nützliche Klasse für das Analysieren von Datenbankoperationen. Es können Profile erstellt und anhand bestimmter Kriterien ausgewertet werden.
Zend_Db_Select ist ein Werkzeug, mit dem man datenbankunabhängige Select-Abfragen erstellen kann. Es können Spalten ausgewählt und Tabellen miteinander verbunden werden. Es können WHERE und HAVING Bedingungen, GROUP BY und ORDER BY Klauseln sowie LIMIT Begrenzungen zu einer Select-Abfrage hinzugefügt werden. Durch die Datenbankunabhängigkeit der Abfragen kann einfach zwischen den von Zend_Db unterstützen Datenbanken gewechselt werden.
Zend_Db_Table ist ein Tabellenmodul für das Zend Framework, welches die Struktur einer Datenbanktabelle analysieren kann und dich beim Ändern und Selektieren von Daten aus einer Datenbanktabelle unterstützt. Eine von Zend_Db_Table abgeleitete Klasse bietet Methoden für das Selektieren und Speichern von Daten, ohne dass man sich um den Aufbau der diversen Datenbankoperationen kümmern muss.
Zend_Db_Table_Row repräsentiert eine Zeile einer Datenbank. Wenn über Zend_Db_Table eine Select-Abfrage durchgeführt wurde, wird als Ergebnis eine Objektinstanz von Zend_Db_Table_Row zurückgeliefert, über das man sehr einfach auf die Werte dieses Datensatzes zugreifen, sie verändern und wieder speichern kann.
Zend_Db_Table_Rowset wiederum stellt eine Sammlung von Zend_Db_Table_Row Objekten bereit. Über diese Ergebnismenge kann iteriert werden, so dass man sich Schritt für Schritt durch die Zend_Db_Table_Row Objekte bewegen kann.
Im weiteren Verlauf gehe ich primär auf Zend_Db_Adapter, Zend_Db_Table, Zend_Db_Table_Row und Zend_Db_Table_Rowset ein. Für eine tiefergehende Lektüre zu den anderen Teilkomponenten von Zend_Db empfehle ich die Lektüre des Zend Framework Manuals.
Zend_Db_Adapter
Um überhaupt mit Hilfe des Zend Frameworks auf eine Datenbank zugreifen zu können, musst du zuerst eine Instanz von Zend_Db_Adapter erstellen. Hierfür öffne bitte die Datei "ArticleController.php" im Verzeichnis "/travelloblog/application/controllers" und ändere die Methode "indexAction" wie folgt ab:
-
class ArticleController extends Zend_Controller_Action
-
{
-
public function indexAction()
-
{
-
require_once 'Zend/Db.php';
-
-
'username' => 'root',
-
'password' => '',
-
'dbname' => 'travelloblog');
-
-
$db = Zend_Db::factory('PDO_MYSQL', $params);
-
}
-
-
[...]
-
}
-
?>
Als erstes laden wir die Zend_Db Basisklasse. Danach erstellen wir ein Array mit den Zugangsdaten zu unserer MySQL Datenbank. Dort musst du natürlich deine eigenen Daten eintragen.
Als letztes rufen wir die statische Methode Zend_Db::factory auf und übergeben ihr zwei Parameter. Der erste Parameter ist der Name des Datenbankadapters, in unserem Fall wird PDO für MySQL verwendet. Neben PDO für MySQL stehen derzeit noch viele weitere Datenbankadapter bereit:
- für PDO Treiber:
- IBM DB2 und Informix Dynamic Server (IDS)
- MySQL
- Microsoft SQL Server
- Oracle
- PostgreSQL
- SQLite
- mit eigener Datenbank-Erweiterung:
- MySQL, mit der mysqli PHP Erweiterung
- Oracle, mit der oci8 PHP Erweiterung
- IBM DB2, mit der ibm_db2 PHP Erweiterung
- Firebird/Interbase, mit der php_interbase PHP Erweiterung
Um auf eine andere Datenbank als MySQL zugreifen zu können, muss lediglich der Name des Adapters im Aufruf von Zend_Db::factory ausgetauscht werden. Da die Verbindung zur Datenbank alleine noch keine Katze hinter dem Ofen hervor lockt, erweitern wir die indexAction Methode noch ein wenig mehr.
-
class ArticleController extends Zend_Controller_Action
-
{
-
public function indexAction()
-
{
-
require_once 'Zend/Db.php';
-
require_once 'Zend/Debug.php';
-
-
'username' => 'root',
-
'password' => '',
-
'dbname' => 'travelloblog');
-
-
$db = Zend_Db::factory('PDO_MYSQL', $params);
-
-
$result = $db->query('select * from article');
-
$rows = $result->fetchAll();
-
Zend_Debug::dump($rows);
-
}
-
-
[...]
-
}
-
?>
Wir senden über $db->query() eine Select-Abfrage ab, um die Tabelle article auszulesen. Dann holen wir uns per $result->fetchAll() die Ergebnisse und geben sie mit der nützlichen Methode Zend_Debug::dump() auf dem Bildschirm aus.
Wenn du nun wieder die Adresse "http://localhost/travelloblog/public/article" in deinem Browser aufrufst, solltest du die Ausgabe eines nummerierten Array mit zwei Elementen erhalten, in dem jeweils ein assoziatives Array mit den Spalten und Werten enthalten ist.
Der Zugriff auf die Datenbanktabelle article hat somit problemlos geklappt. Wer seine SQL-Abfragen sowieso immer zu Fuß erstellt, ist eventuell schon jetzt zufrieden. Wenn du dir die Arbeit aber weiter erleichtern möchtest, solltest du am besten weiter lesen.
Zend_Db_Table
Um Zend_Db_Table verwenden zu können, müssen wir eine Klasse erstellen, welche von Zend_Db_Table abgeleitet wird. Dafür erstelle bitte im Verzeichnis "/travelloblog/application/models" eine Datei mit Namen ArticleModel.php und folgendem rudimentären Code:
-
<?php
-
class ArticleModel extends Zend_Db_Table_Abstract {}
-
?>
Dann ändere bitte wieder die indexAction Methode in unserem ArticleController wie folgt ab:
-
<?php
-
-
class ArticleController extends Zend_Controller_Action
-
{
-
public function indexAction()
-
{
-
require_once 'Zend/Db.php';
-
require_once 'Zend/Debug.php';
-
-
'username' => 'root',
-
'password' => '',
-
'dbname' => 'travelloblog');
-
-
$db = Zend_Db::factory('PDO_MYSQL', $params);
-
-
require_once 'Zend/Db/Table.php';
-
Zend_Db_Table::setDefaultAdapter($db);
-
-
require_once '../application/models/ArticleModel.php';
-
-
$article = new ArticleModel();
-
$rowset = $article->fetchAll();
-
-
Zend_Debug::dump($rowset);
-
}
-
-
[...]
-
}
-
?>
Jetzt rufe bitte wieder die Adresse "http://localhost/travelloblog/public/article" in deinem Browser auf. Wir erhalten eine Fehlermeldung, in der unter anderem folgendes steht:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'travelloblog.articlemodel' doesn't exist
Zend_Db versucht also automatisch vom Namen der Model Klasse auf den Namen der Datenbanktabelle zu schließen. Die Tabelle article_model konnte somit nicht gefunden werden. Dies ist ja auch logisch, schließlich heißt unsere Tabelle article. Jetzt könntest du auf die Idee kommen, die Model Klasse einfach in Article statt ArticleModel um zu nennen. Dies wäre aber eher suboptimal, da solch sehr einfach benannten Klassen irgendwann mit anderen Klassen kollidieren könnten.
Das Problem lässt sich einfach lösen, da wir in der Klasse ArticleModel auch einen anderen Namen für die Tabelle angeben können. Öffne bitte wieder die Datei ArticleModel.php im Verzeichnis "/travelloblog/application/models" und erweitere die Klasse wie folgt:
-
<?php
-
class ArticleModel extends Zend_Db_Table
-
{
-
protected $_name = 'article';
-
}
-
?>
Bei einem erneuten Aufruf der Adresse "http://localhost/travelloblog/public/article" in deinem Browser wird dir dann ein Objekt vom Typ Zend_Db_Table_Rowset ausgegeben. Dieses Objekt enthält unter anderem auch ein Array mit den Daten aus der Tabelle. Was du alles mit einem Zend_Db_Table_Rowset Objekt anfangen kannst, siehst du im nächsten Kapitel.
Zend_Db_Table_Rowset und Zend_Db_Table_Row
Wie schon weiter oben beschrieben handelt es sich bei Zend_Db_Table_Rowset um eine Sammlung von Zend_Db_Table_Row Objekten, die einfach durchlaufen werden können.
Um durch die Ergebnismenge zu iterieren und einzelne Zeilen ausgeben zu können, ändere bitte wieder die "indexAction" Methode im ArticleController ab.
-
<?php
-
-
class ArticleController extends Zend_Controller_Action
-
{
-
public function indexAction()
-
{
-
[...]
-
-
$rowset = $article->fetchAll();
-
-
echo '<h3>Rowset</h3>';
-
Zend_Debug::dump($rowset->toArray());
-
-
foreach($rowset as $key => $row)
-
{
-
Zend_Debug::dump($row->toArray());
-
-
Zend_Debug::dump($row->art_title);
-
}
-
}
-
-
[...]
-
}
-
-
?>
Wenn du nun erneut die Adresse "http://localhost/travelloblog/public/article" in deinem Browser aufrufst, siehst du mehrere durch Überschriften getrennte Ausgaben. Zuerst werden über $rowset->toArray() alle Ergebnisse in einem gesamten Array ausgegeben. Danach werden dann für jede Zeile mit Hilfe von $row->toArray() alle Spalten ausgegeben.
Neben dem Zugriff über die $row->toArray() Methode kann auch direkt auf einzelne Spalten zugegriffen werden.
Aufräumarbeiten
Bevor wir weitermachen, schaue dir bitte einmal den Code in ArticleController::indexAction genauer an. Es macht keinen großen Sinn, in einer Aktionsmethode, die eine Datenbank verwendet, die Parameter für den Zugriff auf die Datenbank abzulegen. Controller Klassen sollten derartige Konfigurationsparametern nicht enthalten.
Außerdem stören mich auch die viele Aufrufe von require_once(), die mehrmals in ArticleController::indexAction zu finden sind, und die Angabe des Verzeichnisses, in dem unsere Model Klassen liegen.
Kopiere bitte aus ArticleController::indexAction die Zeilen von require_once 'Zend/Db.php'; bis einschließlich require_once '../application/models/ArticleModel.php';. Öffne dann unsere Bootstrap Datei bootstrap.php im Verzeichnis "/travelloblog/application" und füge den kopierten Code wieder ein:
Die Bootstrap Datei sollte nun wie folgt aussehen:
-
<?php
-
[...]
-
-
require_once 'Zend/Controller/Front.php';
-
require_once 'Zend/Layout.php';
-
require_once 'Zend/Db.php';
-
require_once 'Zend/Db/Table.php';
-
require_once 'Zend/Debug.php';
-
-
'username' => 'root',
-
'password' => '',
-
'dbname' => 'travelloblog');
-
-
$db = Zend_Db::factory('PDO_MYSQL', $params);
-
Zend_Db_Table::setDefaultAdapter($db);
-
-
require_once '../application/models/ArticleModel.php';
-
-
//-- Setup Controller
-
$frontController = Zend_Controller_Front::getInstance();
-
$frontController->setControllerDirectory('../application/controllers');
-
-
[...]
-
?>
Die kopierten Zeilen kannst du dann aus ArticleController::indexAction entfernen, so dass diese Aktionsmethode deutlich weniger Code enthält:
-
<?php
-
[...]
-
-
public function indexAction()
-
{
-
$article = new ArticleModel();
-
$rowset = $article->fetchAll();
-
-
echo '<h3>Rowset</h3>';
-
Zend_Debug::dump($rowset->toArray());
-
-
foreach($rowset as $key => $row)
-
{
-
Zend_Debug::dump($row->toArray());
-
-
Zend_Debug::dump($row->art_title);
-
}
-
}
-
-
[...]
-
?>
Wenn du wieder die Adresse "http://localhost/travelloblog/public/article" aufrufst, sollten alle Einträge aus der Tabelle article weiterhin angezeigt werden.
Jetzt stören mich vorerst noch die vielen Aufrufe von require_once. Bisher haben wir in unserer Bootstrap Datei bereits sechs Aufrufe von require_once und unser Projekt steht erst am Anfang. Um die Bootstrap Datei zu entschlacken hilft uns die Methode registerAutoload.
registerAutoload nutzen
Die Verwendung von registerAutoload ist recht simpel. Wenn du diese Methode des Zend_Loaders aufrufst, werden Klassen automatisch geladen, sobald sie benötigt werden.
In unserer Bootstrap Datei ersetze die sechs require_once Einträge durch:
-
[...]
-
-
require_once "Zend/Loader.php";
-
-
//-- Set up Autoload
-
Zend_Loader::registerAutoload();
-
-
[...]
Und wenn du bootstrap.php schon offen hast, dann vereinfachen wir auch noch das Laden unserer Model Klasse indem wir das Verzeichnis mit unseren Model Klassen zum include_path hinzufügen:
-
[...]
-
-
//-- Include Pfade setzen
-
'../library' . PATH_SEPARATOR .
-
'../application/models/' . PATH_SEPARATOR .
-
[...]
Nach einem erneuten Aufrufe der Adresse "http://localhost/travelloblog/public/article" in deinem Browser sollte weiterhin alles funktionieren.
Die Bootstrap Datei ist zwar immer noch nicht optimal, aber dazu kommen wir später noch einmal zurück. Immerhin ist unsere Aktionsmethode nun deutlich übersichtlicher geworden.
Zeilen lesen
Da die Ausgabe von Ergebnismengen aus einer Datenbank per Zend_Db_Table_Rowset gut geklappt hat, möchten wir nun einmal das Lesen, Ändern, Erstellen und Löschen von einzelnen Zeilen aus der Datenbank testen. Wir belassen die indexAction Methode im ArticleController so wie sie momentan ist.
Für das Lesen einer Zeile öffne bitte den ArticleController und ändere die showAction Methode wie folgt:
-
<?php
-
-
class ArticleController extends Zend_Controller_Action
-
{
-
[...]
-
-
public function showAction()
-
{
-
$article = new ArticleModel();
-
-
$row = $article->fetchRow('art_id = 1');
-
-
Zend_Debug::dump($row->toArray());
-
}
-
-
[...]
-
?>
Über die Methode $article->fetchRow() kannst du direkt eine Zeile aus der Tabelle lesen. Als ersten Parameter kannst du eine WHERE Klausel und als zweiten eine ORDER BY Klausel angeben. Rufe einfach die Adresse "http://localhost/travelloblog/public/article/show" in deinem Browser auf, dann siehst du, dass das Lesen eines einzelnen Datensatzes aus unserer Artikeltabelle anhand des Primärschlüssels art_id sehr einfach funktioniert.
Zeilen ändern
Kommen wir zum Ändern eines Datensatzes. Dafür gebe in der Methode changeAction bitte folgendes ein:
-
<?php
-
-
class ArticleController extends Zend_Controller_Action
-
{
-
[...]
-
-
public function changeAction()
-
{
-
$article = new ArticleModel();
-
-
$row = $article->fetchRow('art_id = 1');
-
$row->art_udate = $newDate;
-
$row->save();
-
-
Zend_Debug::dump($row->toArray());
-
}
-
-
[...]
-
?>
Zum Ändern der Werte eines Zend_Db_Table_Row Objektes musst du den Eigenschaften einfach nur die geänderten Werte zuweisen. Danach rufst du die Funktion $row->save() auf, um die Zeile in der Datenbank zu aktualisieren.
Rufe einfach die Adresse "http://localhost/travelloblog/public/article/change" in deinem Browser auf, um das Datum zu ändern. Wenn du nicht glaubst, dass das Datum wirklich geändert wurde, rufe danach wieder "http://localhost/travelloblog/public/article/show" auf. Dort sollte dann ein aktueller Wert für die Spalte art_udate angezeigt werden.
Zeilen anlegen
Als nächsten schauen wir uns das Anlegen eines neuen Datensatzes an. Dafür gebe in der Methode createAction bitte folgendes ein:
-
<?php
-
-
class ArticleController extends Zend_Controller_Action
-
{
-
[...]
-
-
public function createAction()
-
{
-
$article = new ArticleModel();
-
-
-
'art_user_id' => 1,
-
'art_cdate' => $newDate,
-
'art_udate' => $newDate,
-
'art_title' => 'Our new entry',
-
'art_text' => 'Here will be lots and lots of text.',
-
'art_teaser' => 'New teaser'
-
);
-
-
$id = $article->insert($data);
-
$row = $article->fetchRow('art_id = ' . $id);
-
-
Zend_Debug::dump($row->toArray());
-
}
-
-
[...]
-
?>
Zuerst wird ein Array mit allen Spalten (außer dem Primärschlüssel) erstellt und dann über die Methode $article->insert($data) in die Datenbank geschrieben. Von dieser Methode erhalten wir den Primärschlüssel des neuen Datensatzes zurück. Danach lesen wir den neuen Datensatz gleich wieder aus und zeigen ihn ein.
Bitte rufe die Adresse "http://localhost/travelloblog/public/article/create" auf, um den Datensatz anzulegen und auszugeben. Du solltest die Adresse aber nicht zu oft aufrufen, weil ansonsten jedes Mal ein neuer Datensatz angelegt wird. Diese könntest du dann aber auch wieder manuell aus deiner Datenbank löschen.
Zeilen löschen
Das ist auch das Stichwort für den letzten Teil diese Kapitels. Nun möchten wir einen Datensatz löschen. Dies geschieht in der Methode deleteAction von unserem ArticleController:
-
<?php
-
-
class ArticleController extends Zend_Controller_Action
-
{
-
[...]
-
-
public function deleteAction()
-
{
-
$article = new ArticleModel();
-
-
-
'art_user_id' => 1,
-
'art_cdate' => $newDate,
-
'art_udate' => $newDate,
-
'art_title' => 'Our new entry',
-
'art_text' => 'Here will be lots and lots of text.',
-
'art_teaser' => 'New teaser'
-
);
-
-
$id = $article->insert($data);
-
$article->delete('art_id = ' . $id);
-
-
}
-
-
[...]
-
?>
Wir legen zuerst einen neuen Datensatz an und nutzen dann den zurückgegebenen Primärschlüssel, um den Datensatz gleich wieder zu löschen. Wenn du in deinem Browser die Adresse "http://localhost/travelloblog/public/article/delete" aufrufst, sollte der kurze Hinweistext ausgegeben werden.
__call() Methode
Um eine etwas aussagekräftigere Fehlermeldung zu bekommen, wenn eine fehlerhafte oder nicht existierende Route eingegeben wird (z.B. http://localhost/travelloblog/public/article/test), erweitern wir unsere Controller Klasse um die Methode __call():
-
<?php
-
-
class ArticleController extends Zend_Controller_Action
-
{
-
[...]
-
-
public function __call($methodName, $args)
-
{
-
echo "ArticleController::__call()<br />";
-
}
-
}
-
-
?>
Ruf eifach mal "http://localhost/travelloblog/public/article/test" mit und ohne der __call() Methode auf, dann siehst du den Unterschied.
Übung: die weiteren Model Klassen
Als kleine Übung bis zum nächsten Teil dieses Tutorials erstelle zwei weitere Controller Klassen: CategoryController und TagController und erweitere diese dann um den Zugriff auf die jeweilige Model Klasse. Erstelle dafür als erstes die beiden Model Klassen und erweitere dann die vorhandenen Aktionsmethoden wie folgt:
- indexAction: zeige alle Daten der Tabelle an.
- createAction: erstelle einen neuen Eintrag in der Tabelle.
- changeAction: ändere einen bestehenden Eintrag.
- deleteAction: erstelle einen neuen Eintrag in der Tabelle und lösche ihn gleich wieder.
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 hier herunter geladen werden:
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 Model Komponente unseres TravelloBlogs mit Hilfe der Zend_Db Komponente des Zend Frameworks realisiert. Dabei haben wir die verschiedenen Teilkomponenten wie Zend_Db_Adapter und Zend_Db_Table kennen und nutzen gelernt.
Die Ausgabe der Daten ist zwar korrekt, optisch aber noch nicht zufriedenstellend. Das ändern wir jedoch im nächsten Teil dieses Tutorials.
Fragen, Probleme und Anregungen bitte nicht per E-Mail senden, sondern hier in die Kommentare stellen. Dann haben alle etwas davon.

Donnerstag, 29. Januar 2009 8:42
auf einmal wird
require_once ‘Zend/View.php’;
eingebunden.
Leider finde ich die Stelle nicht, wo das sein soll. In Tutorial #5 war es noch nicht drin. Jetzt wandert es ohne Erklärung bei den Aufräumarbeiten einfach rein?
Donnerstag, 29. Januar 2009 12:40
grummel, grummel, ist noch ein Relikt vom Probieren verschiedener Sachen. Man brauchte es nicht und ich hatte es anscheinend vergessen zu löschen.
Ich nehm’s raus.
Mittwoch, 10. Juni 2009 13:43
Auch hier meine Änderungen um das ganze mit 1.8.2 lauffähig zu machen.
Zunächst mal zum Zend_Db_Adapter:
Die Login-Parameter sollte man in die applications.ini im application/configs-Dir eintragen. Dazu in den [production]-Blog folgende Zeilen anhängen:
resources.db.params.host = localhost
resources.db.params.username = root
resources.db.params.password =
resources.db.params.dbname = travelloblog
Das reicht schon – man muss nun gar nicht mehr diese Parameter irgendwohin (an die factory) übergeben. Außer wenn man das kleine Demo mit dem Zend_debug::dump ausführen möchte, dann natürlich schon.
Damit unser AutoLoad mit dem ArticleModel arbeiten kann, sollten wir es mehr nach den Zend-Konventionen benennen: Der Name einer Klasse ist der Name der Datei incl. Pfad wobei die / durch _ ersetzt werden. Der Name der Klasse wäre dann also
Model_ArticleModel
wobei im PDF-Tutorial in Models sogar noch ein Unterverzeichnis DbTable erstellt wird und das Model dann in der Datei Articles.php läge und Model_DbTable_Articles hieße. Das kann man aber halten wie ein Dachdecker – nur würde das Autoload nichts bringen wenn man die Klasse so benennt, wie Uwe das getan hat (was in seinem Fall okay ist, da er kein Autoload eingebaut hat). Dann müsste man die Datei immer mit requires einbinden.
Ich leite zudem die Klasse nicht von Zend_Db_Table_Abstract sondern von Zend_Db_Table ab (was Uwe ein Listing später übrigens auch tut).
Auf jeden Fall muss man der Klasse noch den Namen der Tabelle sagen. Dazu einfach in die Klassendefinition
protected $_name = ‘article’;
reinschreiben.
In der IndexAction des ArticleControllers kann man dann – um einen Dump zu erhalten – folgendes schreiben:
$article = new Model_DbTable_Articles();
$rowset = $article->fetchAll();
Zend_Debug::dump($rowset);
Das folgende Beispiel (mit der foreach-Schleife) kann man genau so übernehmen.
Zu den Aufräumarbeiten:
- Die ganzen requires brauchten wir ja eh nicht durch das Autoload. Das führt Uwe direkt nach dem Aufräumen auch ein – haben wir ja schon (wenn auch etwas anders als er) gemacht.
- Und die DB-Parameter haben wir ja eh gleich in application.ini abgelegt – da liegen sie auch sehr gut.
(Kleine Anmerkung: Ich arbeite selbser gerade das Tutorial durch, weiß also nicht was Uwe demnächst macht und wusste bei Einführung meines Autoloads nicht, dass Uwe das später soundso macht. Nur: Wenn ich jetzt nicht aufschreibe, was ich anders mache damit das Tut bei mir unter 1.8.2 auch läuft, dann mache ich es vermutlich später erstrecht nicht… Uwe darf diese Kommentare natürlich löschen sobald er sein angekündigtes Tut-Update online gestellt hat. Bis dahin hab ich ja vielleicht sogar jemandem geholfen…)
Die showAction muss nicht verändert werden und funktioniert genau so.
Auch changeAction funktioniert genau so.
Ebenso createAction und deleteAction.
Die __call-Methode ist m.E. nicht mehr erforderlich, da die Fehlermeldung alle Infos enthält.
Donnerstag, 27. August 2009 8:52
Bei “Zend_Form in Action” ist es nicht nötig “->setRequired(true)” und “->addValidator(‘NotEmpty’)” aufzurufen, da Beides das Gleiche ist.
Freitag, 28. August 2009 13:14
Nur mal so am Rande zu mysql: man sollte sich nie alle Datensätze wie mit ‘select * from tablename’ ausgeben lassen, sondern immer explizit angeben, welche Spalten man haben möchte.
Montag, 31. August 2009 12:29
Hallo,
die Methode “loaderregisterautoload” ist veraltet.
http://wolf-u.li/2966/zend-framework-18-zend_loaderregisterautoload-ist-veraltet/
Hab es eben in der 1.9.2 umgebaut doch dann findet er nicht mehr die ArticleModel Klasse. mmh
Dienstag, 15. September 2009 13:20
Hallo,
irgendwie funktioniert das mit dem automatischen laden der Model-Klasse nicht ich muss immer vorher die Zeile
require_once ‘../application/models/ArticleModel.php’;
einfügen. Ich nutze 1.9.2 hat vielleicht jemand einen Tipp?
Danke
Sonntag, 27. September 2009 18:30
Hi,
ich schließe mich Martin an!!
Lösung? Ist laut meiner Analyse ein AutoLoader Problem.
VG
Dienstag, 29. September 2009 17:49
@Martin
ich habe jetzt auf Zend_Application umgestellt.
Jetzt funtioniert es.
Bis auf das Routing
Ich lande immer im IndexController. Mal sehen wird auch noch werden!
VG
Sonntag, 13. Dezember 2009 23:57
Also ich verstehe das ganze da oben nicht so ganz, hinzu kommt das sich im Zend Framework einiges geändert hat. Die Bootstrap besteht jetzt aus einer klasse usw…
Wenn ich meine Database settings in application.ini eintrage findet Zend_DB::factory die iwi nicht und ich hänge nun an dieser stelle hier… hab auch schon ewig gegoogelt und gesucht sowie rumprobiert (insegsammt 5h) aber irgendwie scheiter ich hier.
Ich möchte eigentlich nur meine database settings global verfügbar machen so das ich diese nicht jedesmal in jedem script eintragen muss. Genauso verstehe ich nicht warum ich diesen autoloader eintragen muss da im neuen Framework wohl schon zendklassen automatisch geladen werden zumindest muss ich keine requier…. zend_debug usw, eintragen da diese einfach funktionieren wenn ich diese aufrufe.
Hab jetzt auch schon mal ne eigene database.ini erstellt und soweit geschafft das ich diese auslesen kann, doch die daten in $dbconfig sind dann nur einmal verfügbar auf der seite public/article sagt er dann das es eine undefinierte variable ist obwohl sie auf der indexpage (public) verfügbar ist.
Dann habe ich versucht das irgenwie in die bootstrap einzubauen aber da ist das selbe problem.
Es wäre wirklich sehr schön wenn du das Tutorial weiter anpassen kannst. Wäre nämlich schade wenn es hier aufhört da es kein einziges zu gebrauchendes aktuelles tutorial gibt und ich schon am verzweiflen bin. Hatte eigentlich gedacht nen framework macht es einfacher aber bis jetzt bin ich sehr enttäuscht davon.
mfg Maik
Dienstag, 2. März 2010 10:52
sehr schönes Tutorial bis hierher – nur schade, dass es hier für >=1.8 aufhört, aktuell zu sein…
ich wäre dafür, dieses Tutorial in Form eines Wiki weiterzuführen – dann könnten mehrere Leute sich drum kümmern, es aktuell zu halten / alternative Wege zu erklären (z.B. mit den Datenbank-Settings per ini), etc.
Dienstag, 2. März 2010 11:07
und noch eine Erweiterung des application.ini-Codes von Marcus:
resources.db.adapter = “pdo_mysql”
resources.db.params.host = localhost
resources.db.params.username = root
resources.db.params.password =
resources.db.params.dbname = travelloblog
resources.db.isDefaultTableAdapter = true
http://framework.zend.com/manual/de/zend.application.available-resources.html
Mittwoch, 21. Juli 2010 17:02
Hallo,
vielleicht kann mir kurz einer von euch die Blockade lösen… Folgendes habe ich in der Bootstrap-Klasse in der Methode _initViewHelpers stehen:
require_once ‘Zend/Loader/Autoloader.php’;
$loader=Zend_Loader_Autoloader::getInstance();
In meiner saveData-Methode muss ich
require_once “ArticleModel.php”;
einfügen, da ich sonst die Klasse Model_ArticleModel nicht verwenden kann (Class.. not found in…)
In der run_app.php habe ich als IncludePfad noch das stehen…
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . ‘/../library’),
realpath(APPLICATION_PATH . ‘/../application/models/’),
get_include_path(),
)));