Programmer's Reference Guide

Ein Layout erstellen

Ein Modell und eine Datenbank Tabelle erstellen

Bevor wir anfangen nehmen wie etwas an: Wo werden diese Klassen leben, und wie werden wir Sie finden? Das Standardprojekt welches wir erstellt haben instanziert einen Autoloader. Wir können Ihm andere Autoloader anhängen damit er weiss wo andere Klassen zu finden sind. Typischerweise wollen wir das unsere verschiedenen MVC Klassen im selben Baum gruppiert sind -- in diesem Fall application/ -- und meistens einen gemeinsamen Präfix verwenden.

Zend_Controller_Front hat den Begriff von "Modulen", welche individuelle Mini-Anwendungen sind. Module mimen die Verzeichnisstruktur welche das zf Tool unter application/ einrichtet, und von allen Klassen in Ihm wird angenommen das Sie mit einen gemeinsamen Präfix beginnen, dem Namen des Moduls. application/ selbst ist ein Modul -- das "default" oder "application" Modul. Als solches richten wir das Autoloading für Ressourcen in diesem Verzeichnis ein.

Zend_Application_Module_Autoloader bietet die Funktionalität welche benötigt wird um die verschiedenen Ressourcen unter einem Modul mit den richtigen Verzeichnissen zu verbinden, und auch einen standardmäßigen Namensmechanismus. Standardmäßig wird eine Instanz der Klasse wärend der Initialisierung des Bootstrap Objekts erstellt; unser Application Bootstrap verwendet standardmäßig das Modulpräfix "Application". Daher beginnen alle unsere Modelle, Formulare, und Tabellenklassen mit dem Klassenpräfix "Application_".

Nehmen wir jetzt also an was ein Guestbook ausmacht. Typischerweise sind Sie einfach eine Liste ein Einträgen mit einem Kommentar (comment), einem Zeitpunkt (timestamp) und oft einer Email Adresse. Angenommen wir speichern diese in einer Datenbank, dann wollen wir auch einen eindeutigen Identifikator für jeden Eintrag. Wir wollen in der Lage sein einen Eintrag zu speichern, individuelle Einträge zu holen, und alle Einträge zu empfangen. Als solches könnte das Modell einer einfachen Guestbook API wie folgt aussehen:

  1. // application/models/Guestbook.php
  2.  
  3. class Application_Model_Guestbook
  4. {
  5.     protected $_comment;
  6.     protected $_created;
  7.     protected $_email;
  8.     protected $_id;
  9.  
  10.     public function __set($name, $value);
  11.     public function __get($name);
  12.  
  13.     public function setComment($text);
  14.     public function getComment();
  15.  
  16.     public function setEmail($email);
  17.     public function getEmail();
  18.  
  19.     public function setCreated($ts);
  20.     public function getCreated();
  21.  
  22.     public function setId($id);
  23.     public function getId();
  24. }
  25.  
  26. class Application_Model_GuestbookMapper
  27. {
  28.     public function save(Application_Model_Guestbook $guestbook);
  29.     public function find($id);
  30.     public function fetchAll();
  31. }

__get() und __set() bieten uns bequeme Mechanismen an um auf individuelle Eigenschaften von Einträgen zuzugreifen und auf andere Getter und Setter zu verweisen. Sie stellen auch sicher das nur Eigenschaften im Objekt vorhanden sind die wir freigegeben haben.

find() und fetchAll() bieten die Fähigkeit einen einzelnen Eintrag oder alle Einträge zu holen, wärend save() das Speichern der Einträge im Datenspeicher übernimmt.

Von hier an können wir über die Einrichtung unserer Datenbank nachdenken.

Zuerst muss unsere Db Ressource initialisiert werden. Wie bei der Layout und View kann die Konfiguration für die Db Ressource angegeben werden. Dies kann mit dem Befehl zf configure db-adapter getan werden:

  1. % zf configure db-adapter \
  2. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
  3. > production
  4. A db configuration for the production has been written to the application config file.
  5.  
  6. % zf configure db-adapter \
  7. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \
  8. > testing
  9. A db configuration for the production has been written to the application config file.
  10.  
  11. % zf configure db-adapter \
  12. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \
  13. > development
  14. A db configuration for the production has been written to the application config file.

Jetzt muss die Datei application/configs/application.ini bearbeitet werden, und man kann sehen das die folgenden Zeilen in den betreffenden Abschnitten hinzugefügt wurden.

  1. ; application/configs/application.ini
  2.  
  3. [production]
  4. ; ...
  5. resources.db.adapter       = "PDO_SQLITE"
  6. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  7.  
  8. [testing : production]
  9. ; ...
  10. resources.db.adapter = "PDO_SQLITE"
  11. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  12.  
  13. [development : production]
  14. ; ...
  15. resources.db.adapter = "PDO_SQLITE"
  16. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

Die endgültige Konfigurationsdatei sollte wie folgt aussehen:

  1. ; application/configs/application.ini
  2.  
  3. [production]
  4. phpSettings.display_startup_errors = 0
  5. phpSettings.display_errors = 0
  6. bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
  7. bootstrap.class = "Bootstrap"
  8. appnamespace = "Application"
  9. resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
  10. resources.frontController.params.displayExceptions = 0
  11. resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
  12. resources.view[] =
  13. resources.db.adapter = "PDO_SQLITE"
  14. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  15.  
  16. [staging : production]
  17.  
  18. [testing : production]
  19. phpSettings.display_startup_errors = 1
  20. phpSettings.display_errors = 1
  21. resources.db.adapter = "PDO_SQLITE"
  22. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  23.  
  24. [development : production]
  25. phpSettings.display_startup_errors = 1
  26. phpSettings.display_errors = 1
  27. resources.db.adapter = "PDO_SQLITE"
  28. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

Es ist zu beachten das die Datenbank(en) unter data/db/ gespeichert wird. Diese Verzeichnisse sind zu erstellen und weltweit-schreibbar zu machen. Auf Unix-artigen Systemen kann man das wie folgt durchführen:

  1. % mkdir -p data/db; chmod -R a+rwX data

Unter Windows muss man die Verzeichnisse im Explorer erstellen und die Zugriffsrechte so zu setzen das jeder in das Verzeichnis schreiben darf.

Ab diesem Punkt haben wir eine Verbindung zu einer Datenbank; in unserem Fall ist es eine verbindung zu einer Sqlite Datenbank die in unserem application/data/ Verzeichnis ist. Designen wir also eine einfache Tabelle die unsere Guestbook Einträge enthalten wird.

  1. -- scripts/schema.sqlite.sql
  2. --
  3. -- Man muss das Datenbank Schema mit diesem SQL laden.
  4.  
  5. CREATE TABLE guestbook (
  6.     id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  7.     email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
  8.     comment TEXT NULL,
  9.     created DATETIME NOT NULL
  10. );
  11.  
  12. CREATE INDEX "id" ON "guestbook" ("id");

Und damit wir gleich einige Arbeitsdaten haben, erstellen wir ein paar Zeilen an Information um unsere Anwendung interessant zu machen.

  1. -- scripts/data.sqlite.sql
  2. --
  3. -- Man kann damit beginnen die Datenbank zu befüllen indem die folgenden SQL
  4. -- Anweisungen ausgeführt werden.
  5.  
  6. INSERT INTO guestbook (email, comment, created) VALUES
  7.     ('ralph.schindler@zend.com',
  8.     'Hallo! Hoffentlich geniesst Ihr dieses Beispiel einer ZF Anwendung!
  9.     DATETIME('NOW'));
  10. INSERT INTO guestbook (email, comment, created) VALUES
  11.     ('foo@bar.com',
  12.     'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
  13.     DATETIME('NOW'));

Jetzt haben wir sowohl das Schema als auch einige Daten definiert. Schreiben wir also ein Skript das wir jetzt ausführen können um diese Datenbank zu erstellen. Natürlich wird das nicht in der Produktion benötigt, aber dieses Skriupt hilft Entwicklern die Notwendigkeiten der Datenbank lokal zu erstellen damit Sie eine voll funktionsfähige Anwendung haben. Das Skript ist als scripts/load.sqlite.php mit dem folgenden Inhalt zu erstellen:

  1. // scripts/load.sqlite.php
  2.  
  3. /**
  4. * Skript für das erstellen und Laden der Datenbank
  5. */
  6.  
  7. // Initialisiert den Pfad und das Autoloading der Anwendung
  8. defined('APPLICATION_PATH')
  9.     || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
  10. set_include_path(implode(PATH_SEPARATOR, array(
  11.     APPLICATION_PATH . '/../library',
  12. )));
  13. require_once 'Zend/Loader/Autoloader.php';
  14. Zend_Loader_Autoloader::getInstance();
  15.  
  16. // Definiert einige CLI Optionen
  17. $getopt = new Zend_Console_Getopt(array(
  18.     'withdata|w' => 'Datenbank mit einigen Daten laden',
  19.     'env|e-s'    => "Anwendungsumgebung für welche die Datenbank "
  20.                   . "erstellt wird (Standard ist Development)",
  21.     'help|h'     => 'Hilfe -- Verwendung',
  22. ));
  23. try {
  24.     $getopt->parse();
  25. } catch (Zend_Console_Getopt_Exception $e) {
  26.     // Schlechte Option übergeben: Verwendung ausgeben
  27.     echo $e->getUsageMessage();
  28.     return false;
  29. }
  30.  
  31. // Wenn Hilfe angefragt wurde, Verwendung ausgeben
  32. if ($getopt->getOption('h')) {
  33.     echo $getopt->getUsageMessage();
  34.     return true;
  35. }
  36.  
  37. // Werte basierend auf Ihrer Anwesenheit oder Abwesenheit von CLI Optionen initialisieren
  38. $withData = $getopt->getOption('w');
  39. $env      = $getopt->getOption('e');
  40. defined('APPLICATION_ENV')
  41.     || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);
  42.  
  43. // Zend_Application initialisieren
  44. $application = new Zend_Application(
  45.     APPLICATION_ENV,
  46.     APPLICATION_PATH . '/configs/application.ini'
  47. );
  48.  
  49. // Die DB Ressource initialisieren und empfangen
  50. $bootstrap = $application->getBootstrap();
  51. $bootstrap->bootstrap('db');
  52. $dbAdapter = $bootstrap->getResource('db');
  53.  
  54. // Den Benutzer informieren was abgeht
  55. // (wir erstellen hier aktuell eine Datenbank)
  56. if ('testing' != APPLICATION_ENV) {
  57.     echo 'Schreiben in die Guestbook Datenbank (control-c um abzubrechen): ' . PHP_EOL;
  58.     for ($x = 5; $x > 0; $x--) {
  59.         echo $x . "\r"; sleep(1);
  60.     }
  61. }
  62.  
  63. // Prüfen um zu sehen ob wie bereits eine Datenbankdatei haben
  64. $options = $bootstrap->getOption('resources');
  65. $dbFile  = $options['db']['params']['dbname'];
  66. if (file_exists($dbFile)) {
  67.     unlink($dbFile);
  68. }
  69.  
  70. // Dieser Block führt die aktuellen Statements aus welche von der Schemadatei
  71. // geladen werden.
  72. try {
  73.     $schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
  74.     // Die Verbindung direkt verwenden um SQL im Block zu laden
  75.     $dbAdapter->getConnection()->exec($schemaSql);
  76.     chmod($dbFile, 0666);
  77.  
  78.     if ('testing' != APPLICATION_ENV) {
  79.         echo PHP_EOL;
  80.         echo 'Datenbank erstellt';
  81.         echo PHP_EOL;
  82.     }
  83.  
  84.     if ($withData) {
  85.         $dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
  86.         // Die Verbindung direkt verwenden um SQL in Blöcken zu laden
  87.         $dbAdapter->getConnection()->exec($dataSql);
  88.         if ('testing' != APPLICATION_ENV) {
  89.             echo 'Daten geladen.';
  90.             echo PHP_EOL;
  91.         }
  92.     }
  93.  
  94. } catch (Exception $e) {
  95.     echo 'EIN FEHLER IST AUFGETRETEN:' . PHP_EOL;
  96.     echo $e->getMessage() . PHP_EOL;
  97.     return false;
  98. }
  99.  
  100. // Generell gesprochen wird dieses Skript von der Kommandozeile aus aufgerufen
  101. return true;

Jetzt führen wir dieses Skript aus. Von einem Terminal oder der DOS Kommandozeile ist das folgende zu tun:

  1. % php scripts/load.sqlite.php --withdata

Man sollte eine ähnliche Ausgabe wie folgt sehen:

  1. path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata
  2. Schreiben in die Guestbook Datenbank (control-c um abzubrechen):
  3. 1
  4. Datenbank erstellt
  5. Daten geladen.

Jetzt haben wir eine voll funktionsfähige Datenbank und eine Tabelle für unsere Guestbook Anwendung. Unsere nächsten paar Schritte sind die Ausarbeitung unseres Anwendungscodes. Das inkludiert das Bauen einer Datenquelle (in unserem Fall verwenden wir Zend_Db_Table), und einen Daten Mapper um diese Datenquelle mit unserem Domain Modell zu verbinden. Letztendlich erstellen wir den Controller der mit diesem Modell interagiert damit sowohl existierende Einträge angezeigt als auch neue Einträge bearbeitet werden.

Wir verwenden ein » Table Data Gateway um uns mit unserer Datenquelle zu verbinden; Zend_Db_Table bietet diese Funktionalität. Um anzufangen erstellen wir eine Zend_Db_Table-basierende Tabellenklasse. Wie wir es für Layouts und den Datenbank Adapter getan haben, können wir das zf Tool verwenden um uns zu assistieren indem der Befehl create db-table verwendet wird. Dieser nimmt mindestens zwei Argumente, den Namen mit dem man auf die Klasse referenzieren will, und die Datenbanktabelle auf die Sie zeigt.

  1. % zf create db-table Guestbook guestbook
  2. Creating a DbTable at application/models/DbTable/Guestbook.php
  3. Updating project profile 'zfproject.xml'

Wenn man in der Verzeichnisbaum sieht, dann wird man jetzt sehen das ein neues Verzeichnis application/models/DbTable/ zusammen mit der Datei Guestbook.php erstellt wurde. Wenn man die Datei öffnet wird man den folgenden Inhalt sehen:

  1. // application/models/DbTable/Guestbook.php
  2.  
  3. /**
  4. * Das ist die DbTable Klasse für die Guestbook Tabelle.
  5. */
  6. class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
  7. {
  8.     /** Tabellenname */
  9.     protected $_name    = 'guestbook';
  10. }

Der Klassenpräfix ist zu beachten: Application_Model_DbTable. Der Klassenpräfix für unser Modul "Application" ist das erste Segment, und dann haben wir die Komponente "Model_DbTable"; die letztere verweist auf das Verzeichnis models/DbTable/ des Moduls.

Alles das ist wirklich notwendig wenn Zend_Db_Table erweitert wird um einen Tabellennamen anzubieten und optional den primären Schlüssel (wenn es nicht die "id" ist).

Jetzt erstellen wir einen » Daten Mapper. Ein Daten Mapper bildet ein Domain Objekt in der Datenbank ab. In unserem Fall bildet es unser Modell Application_Model_Guestbook auf unsere Datenquelle, Application_Model_DbTable_Guestbook, ab. Eine typische API für einen Daten Mapper ist wie folgt:

  1. // application/models/GuestbookMapper.php
  2.  
  3. class Application_Model_GuestbookMapper
  4. {
  5.     public function save($model);
  6.     public function find($id, $model);
  7.     public function fetchAll();
  8. }

Zusätzlich zu diesen Methoden, fügen wir Methoden für das Setzen und Holen des Table Data Gateways hinzu. Um die initiale Klasse zu erstellen kann das zf CLI Tool verwendet werden:

  1. % zf create model GuestbookMapper
  2. Creating a model at application/models/GuestbookMapper.php
  3. Updating project profile '.zfproject.xml'

Jetzt muss die Klasse Application_Model_GuestbookMapper welche in application/models/GuestbookMapper.php gefunden werden kann so geändert werden dass Sie wie folgt zu lesen ist:

  1. // application/models/GuestbookMapper.php
  2.  
  3. class Application_Model_GuestbookMapper
  4. {
  5.     protected $_dbTable;
  6.  
  7.     public function setDbTable($dbTable)
  8.     {
  9.         if (is_string($dbTable)) {
  10.             $dbTable = new $dbTable();
  11.         }
  12.         if (!$dbTable instanceof Zend_Db_Table_Abstract) {
  13.             throw new Exception('Ungültiges Table Data Gateway angegeben');
  14.         }
  15.         $this->_dbTable = $dbTable;
  16.         return $this;
  17.     }
  18.  
  19.     public function getDbTable()
  20.     {
  21.         if (null === $this->_dbTable) {
  22.             $this->setDbTable('Application_Model_DbTable_Guestbook');
  23.         }
  24.         return $this->_dbTable;
  25.     }
  26.  
  27.     public function save(Application_Model_Guestbook $guestbook)
  28.     {
  29.         $data = array(
  30.             'email'   => $guestbook->getEmail(),
  31.             'comment' => $guestbook->getComment(),
  32.             'created' => date('Y-m-d H:i:s'),
  33.         );
  34.  
  35.         if (null === ($id = $guestbook->getId())) {
  36.             unset($data['id']);
  37.             $this->getDbTable()->insert($data);
  38.         } else {
  39.             $this->getDbTable()->update($data, array('id = ?' => $id));
  40.         }
  41.     }
  42.  
  43.     public function find($id, Application_Model_Guestbook $guestbook)
  44.     {
  45.         $result = $this->getDbTable()->find($id);
  46.         if (0 == count($result)) {
  47.             return;
  48.         }
  49.         $row = $result->current();
  50.         $guestbook->setId($row->id)
  51.                   ->setEmail($row->email)
  52.                   ->setComment($row->comment)
  53.                   ->setCreated($row->created);
  54.     }
  55.  
  56.     public function fetchAll()
  57.     {
  58.         $resultSet = $this->getDbTable()->fetchAll();
  59.         $entries   = array();
  60.         foreach ($resultSet as $row) {
  61.             $entry = new Application_Model_Guestbook();
  62.             $entry->setId($row->id)
  63.                   ->setEmail($row->email)
  64.                   ->setComment($row->comment)
  65.                   ->setCreated($row->created);
  66.             $entries[] = $entry;
  67.         }
  68.         return $entries;
  69.     }
  70. }

Jetzt ist es Zeit unsere Modellklasse zu erstellen. Wir machen dies indem wieder das Kommando zf create model verwendet wird:

  1. % zf create model Guestbook
  2. Creating a model at application/models/Guestbook.php
  3. Updating project profile '.zfproject.xml'

Wir verändern diese leere PHP Klasse um es einfach zu machen das Modell bekanntzugeben indem ein Array an Daten entweder an den Constructor oder an die setOptions() Methode übergeben wird. Das endgültige Modell, welches in application/models/Guestbook.php ist, sollte wie folgt aussehen:

  1. // application/models/Guestbook.php
  2.  
  3. class Application_Model_Guestbook
  4. {
  5.     protected $_comment;
  6.     protected $_created;
  7.     protected $_email;
  8.     protected $_id;
  9.  
  10.     public function __construct(array $options = null)
  11.     {
  12.         if (is_array($options)) {
  13.             $this->setOptions($options);
  14.         }
  15.     }
  16.  
  17.     public function __set($name, $value)
  18.     {
  19.         $method = 'set' . $name;
  20.         if (('mapper' == $name) || !method_exists($this, $method)) {
  21.             throw new Exception('Ungültige Guestbook Eigenschaft');
  22.         }
  23.         $this->$method($value);
  24.     }
  25.  
  26.     public function __get($name)
  27.     {
  28.         $method = 'get' . $name;
  29.         if (('mapper' == $name) || !method_exists($this, $method)) {
  30.             throw new Exception('Ungültige Guestbook Eigenschaft');
  31.         }
  32.         return $this->$method();
  33.     }
  34.  
  35.     public function setOptions(array $options)
  36.     {
  37.         $methods = get_class_methods($this);
  38.         foreach ($options as $key => $value) {
  39.             $method = 'set' . ucfirst($key);
  40.             if (in_array($method, $methods)) {
  41.                 $this->$method($value);
  42.             }
  43.         }
  44.         return $this;
  45.     }
  46.  
  47.     public function setComment($text)
  48.     {
  49.         $this->_comment = (string) $text;
  50.         return $this;
  51.     }
  52.  
  53.     public function getComment()
  54.     {
  55.         return $this->_comment;
  56.     }
  57.  
  58.     public function setEmail($email)
  59.     {
  60.         $this->_email = (string) $email;
  61.         return $this;
  62.     }
  63.  
  64.     public function getEmail()
  65.     {
  66.         return $this->_email;
  67.     }
  68.  
  69.     public function setCreated($ts)
  70.     {
  71.         $this->_created = $ts;
  72.         return $this;
  73.     }
  74.  
  75.     public function getCreated()
  76.     {
  77.         return $this->_created;
  78.     }
  79.  
  80.     public function setId($id)
  81.     {
  82.         $this->_id = (int) $id;
  83.         return $this;
  84.     }
  85.  
  86.     public function getId()
  87.     {
  88.         return $this->_id;
  89.     }
  90. }

Letztendlich, um diese Elemente alle zusammen zu verbinden, erstellen wir einen Guestbook Controller der die Einträge auflistet welche aktuell in der Datenbank sind.

Um einen neuen Controller zu erstellen muss das Kommando zf create controller verwendet werden:

  1. % zf create controller Guestbook
  2. Creating a controller at
  3.     application/controllers/GuestbookController.php
  4. Creating an index action method in controller Guestbook
  5. Creating a view script for the index action method at
  6.     application/views/scripts/guestbook/index.phtml
  7. Creating a controller test file at
  8.     tests/application/controllers/GuestbookControllerTest.php
  9. Updating project profile '.zfproject.xml'

Das erstellt einen neuen Controller, GuestbookController, in application/controllers/GuestbookController.php mit einer einzelnen Aktions Methode, indexAction(). Er erstellt auch ein View Skript Verzeichnis für den Controller, application/views/scripts/guestbook/, mit einem View Skript für die Index Aktion.

Wir verwenden die "index" Aktion als Landeseite um alle Guestbook Einträge anzusehen.

Jetzt betrachten wir die grundsätzliche Anwendungslogik. Bei einem Treffer auf indexAction() zeigen wir alle Guestbook Einträge an. Das würde wie folgt aussehen:

  1. // application/controllers/GuestbookController.php
  2.  
  3. class GuestbookController extends Zend_Controller_Action
  4. {
  5.     public function indexAction()
  6.     {
  7.         $guestbook = new Application_Model_GuestbookMapper();
  8.         $this->view->entries = $guestbook->fetchAll();
  9.     }
  10. }

Und natürlich benötigen wir ein View Skript um damit weiterzumachen. application/views/scripts/guestbook/index.phtml ist zu bearbeiten damit Sie wie folgt aussieht:

  1. <!-- application/views/scripts/guestbook/index.phtml -->
  2.  
  3. <p><a href="<?php echo $this->url(
  4.     array(
  5.         'controller' => 'guestbook',
  6.         'action'     => 'sign'
  7.     ),
  8.     'default',
  9.     true) ?>">Im Guestbook eintragen</a></p>
  10.  
  11. Guestbook Einträge: <br />
  12. <dl>
  13.     <?php foreach ($this->entries as $entry): ?>
  14.     <dt><?php echo $this->escape($entry->email) ?></dt>
  15.     <dd><?php echo $this->escape($entry->comment) ?></dd>
  16.     <?php endforeach ?>
  17. </dl>

Hinweis: Checkpoint
Jetzt gehen wir auf "http://localhost/guestbook". Man sollte das folgende im Browser sehen:

learning.quickstart.create-model.png

Hinweis: Das Datenlade Skript verwenden
Das Datenlade Skript welches in diesem Kapitel beschrieben wird (scripts/load.sqlite.php) kann verwendet werden um die Datenbank, für jede Umgebung die man definiert hat, zu erstellen sowie Sie mit Beispieldaten zu laden. Intern verwendet es Zend_Console_Getopt, was es erlaubt eine Anzahl von Kommandozeilen Schalter anzubieten. Wenn man den "-h" oder "--help" Schalter übergibt, werden die folgenden Optionen angegeben:

  1. Usage: load.sqlite.php [ options ]
  2. --withdata|-w         Datenbank mit einigen Daten laden
  3. --env|-e [  ]         Anwendungsumgebung für welche die Datenbank erstellt wird
  4.                       (Standard ist Development)
  5. --help|-h             Hilfe -- Verwendung)]]
Der "-e" Schalter erlaubt es den Wert zu spezifizieren der für die Konstante APPLICATION_ENV verwendet wird -- welcher es erlaubt eine SQLite Datenbank für jede Umgebung zu erstellen die man definiert. Man sollte sicherstellen dass das Skript für die Umgebung gestartet wird welche man für die eigene Anwendung ausgewählt hat wenn man in Betrieb geht.


Ein Layout erstellen

Comments

The example configuring the database adapter with zf configure db-adapter does not work for me running the command from both NetBeans IDE and Windows 7 command prompt.

Executing the command as:

zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH \"/../data/db/guestbook.db\"" -s production

zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH \"/../data/db/guestbook-testing.db\"" -s testing

works, but writes
resources.db.params.dbname = "APPLICATION_PATH /../data/db/guestbook.db"
to the configuration, which ofcourse should be
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

Also, trying to configure the development section php raises a notice and does not configure anything (even though it said it did)

PHP Notice:  Undefined offset: 28 in C:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\library\Zend\Tool\Project\Provider\DbAdapter.php on line 182

So if you're finding problems with this, for now just manually add the lines to your application.ini

I had the following problem: when I accessed the guestbook controller it showed an error:

Fatal error: Class 'Application_Model_GuestbookMapper' not found in path\to\quickstart\application\controllers\GuestbookController.php on line 13

After some time of searching the web I found a solution. Just add this to your Bootstrap.php, at the end of the _initDoctype function:

$loader = new Zend_Loader_Autoloader_Resource (array (
'basePath' => APPLICATION_PATH,
'namespace' => 'Application',
));

$loader -> addResourceType ( 'model', 'models', 'Model');
When executing the load.sqlite.php (on a Windows machine) it would fail to work and just output the script to the console.

To make it work I had to add the <?php and ?> tags to the beginning and end of the script like so below:


<?php
// scripts/load.sqlite.php

...

// generally speaking, this script will be run from the command line
return true;
?>
/GuestbookMapper.php
<pre>
if (null === ($id = $guestbook->getId())) {

unset($data['id']); //<--- this should be unset($data[$id]);

$this->getDbTable()->insert($data);

} else {

$this->getDbTable()->update($data, array('id = ?' => $id));

}

</pre>
I wish there was an alternative version of this tutorial that used MySQL.
If you carefully follow all the steps it is working fine but two things are missing here.

In a regular php installation the pdo_sqlite is not enable. Make sure this is set in your php.ini file.

Second and in case you get this following error when you run the Guestbook:
SQLSTATE[HY000] [14] unable to open database file

For some reason the DB folder and files need to be inside the /public/ folder which isn't mentioned as far as I can see.
And for the zf configure db-adapter in Windows I forgot to mention:

Reverse the quotation marks
Hence this:
'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"'

should be this
"adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook.db'"
Missing an image after this text:

Note: Checkpoint
Now browse to "http://localhost/guestbook". You should see the following in your browser:
Just to clarify. These are the commands that worked for me in Windows XP:

zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook.db'" -s production
zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook-testing.db'" -s testing
zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook-dev.db'" -s development


Also, the data folder should go in the same directory as application directory is, not inside the application directory.
@adrian >> For some reason the DB folder and files need to be inside the /public/ folder which isn't mentioned as far as I can see.

you're wrong about the fact that db folder needs to be in /public/ folder & you're wrong about the fact it's not mentioned.

i invite you to look better :)

anyway, i'm on mac os and have no problem.

for people didn't see that php tags where missing maybe you have to pay more attention what you're doing and not just copy/paste what you see :) the load file is a php script ;)

@tchaOo°
@adrian >> For some reason the DB folder and files need to be inside the /public/ folder which isn't mentioned as far as I can see.

you're wrong about the fact that db folder needs to be in /public/ folder & you're wrong about the fact it's not mentioned.

i invite you to look better :)

anyway, i'm on mac os and have no problem.

for people didn't see that php tags where missing maybe you have to pay more attention what you're doing and not just copy/paste what you see :) the load file is a php script ;)

@tchaOo°
I've got the same error:
Fatal error: Class 'Application_Model_Guestbook' not found in...

I've found the following solution:

// Add this method to your Bootstrap class

protected function _initAutoload()
{
$loader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Application',
'basePath' => APPLICATION_PATH
));
return $loader;
}
I just wonder why creating a class "GuestbookMapper" instead of using the rowClass attribute in DbTable_Guestbook and have the class Guessbook extending Zend_Db_Table_Row_Abstract ?
Hello,
Is anyone could explain the way how apache server will proceed request http://zendtest.local/guestbook?
I have problem, my server show OK for http://zendtest.local, http://zendtest.local/guestbook bring me:
The requested URL /guestbook was not found on this server.
I have been playing with parameters of httpd.conf, but nothing good...
The main thing I do not understand how server should know that such request actiolly should be shown index of view of guestbook?
Thank you in advance.
zf configure db-adapter "adapter=MySQLi&dbname=zend&username=root&password=12&charset=utf8"
don't know why this tutorial does not mention creating the db connection to a mysql db. pdo_sqlite does not come working by default. You have to include like four different pdo* libraries in your .ini file to make this work. There is nothing in this article about setting this up. It required me to search like an hour to find this info. Very poorly written tutorial.

to use mysql instead of sqlite i found this somewhere to add to application.ini

resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "mysqlusername"
resources.db.params.password = "mysqlpassword"
resources.db.params.dbname = "dbname"

I just added this to each production, development and testing sections.

so I skipped the whole create db script and just executed the sql in navicat.

my question is do we need to run elements of that load.sqlite.sql even for a existing mysql db to make the connection work?

I created all the model, view mapper etc.... Got to the end and now get a 404 error saying it cant even find guestbook







I was having trouble running the CLI file scripts/load.sqlite.php with messages about not finding several files. It turns out it was that the CLI was using a different php.ini than the main zend php.ini, so I created a symbolic link from the one the CLI found to the correct one: sudo ln -s /usr/local/zend/etc/php.ini /etc/php5/cli/php.ini

This fixed the problem.
andy
"to use mysql instead of sqlite i found this somewhere to add to application.ini"

You did right, it should work, it works for me.

You don´t need to run load.sqlite.sql at all.

Check every other step in case you missed something. Don´t forget to name your database and tables correctly and to grant all privileges to yourself. Check in your apache settings if rewrite_module is enabled, otherwise you'll get 404 errors in all actions other than IndexAction.
Another half-ased written tutorial that makes you frustrated because you have to search for answers to the holes it leaves open.

Why do people write tutorials as if you are supposed to know what they are talking about?

After all, we came to learn, not guess!
Another half-ased written tutorial that makes you frustrated because you have to search for answers to the holes it leaves open.

Why do people write tutorials as if you are supposed to know what they are talking about?

After all, we came to learn, not guess!
for people who are getting 404/505 at 'http://localhost/guestbook'
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

in your /path/to/quickstart/public/
it worked on my pc.

I think it's better to remove comment line "application/models/Guestbook.php" from first code block, because now it's look like user shoud create this file and paste the mentioned code there (both classes). However it's only description of interface, which we will implement later.
I added this code in application.ini

resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "mysqlusername"
resources.db.params.password = "mysqlpassword"
resources.db.params.dbname = "dbname"

It works:)
Como faço para buscar dois campos, por exemplo:
Controller:
function searchAction(){
//mostrar o form de pesquisa
}

function viewAction(){
//pega os dados passados e faz a pesquisa no bando dados
$resultado = model->getSearch($nome, $cidade);
$this->view->resultado = $resultado;
}

Model:
function getSearch($nome, $cidade){

??????

return $result;
}
I went with pdo_mysql, with the following zf commands.

zf configure db-adapter 'adapter=Pdo_Mysql&host=localhost&username=name&password=pass&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' production

zf configure db-adapter 'adapter=Pdo_Mysql&host=localhost&username=name&password=pass&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' test

zf configure db-adapter 'adapter=Pdo_Mysql&host=localhost&username=name&password=pass&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' development

Hope this helps someone else not get as confused as I was.


Two tips:

1. Note that the database(s) will be stored in data/db/. Create those directories, and make them world-writeable. On unix-like systems, you can do that as...

Instead of making these directories world-writeable, use the web server processes user (defined in the User and Group directive in Apache as daemon or www-data) for the directory's user and group, as they will be the PHP process effective user and group. Try the following:

$ pwd
/usr/local/apache/htdocs/example/application
$ sudo chown daemon.daemon data/db


2. In the Application_Model_Guestbook class __get() and __set() magic methods defines that getters and setters might be defines as getproperty() instead of getProperty. If you use getPropertyName and setProperty flavor, change the first line in the magic methods to:

$method = 'get' . ucfirst($name)

and

$method = 'set' . ucfirst($name)

Hi everyone,

I had trouble adapting this to Microsoft SQL Server. I figured it out eventually.

Here is what you do:

1. Make sure MSSQL works normally with a simple php file.
2. Now to use it with Zend, have the application.ini file look like this:
resources.db.adapter = "sqlsrv"
resources.db.params.host = "***.***.***.***"
resources.db.params.dbname = "Database"
resources.db.params.username = "*******"
resources.db.params.password = "*******"

It should be this simple (hopefully). But also note that youll probably have to create the database and stuff on your own, this is mainly for the important part (i.e. connection to the database for use with other parts of the tutorial).

note: I am on windows server 2008 using IIS7 and Sql Server 2008
MySQL, not SQLITE, is standard nowdays, but editing the .ini file with those lines dose the job for MySQL users:

resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "mysqlusername"
resources.db.params.password = "mysqlpassword"
resources.db.params.dbname = "dbname"

The problem not addressed here is: how do I access data across more then one database? I need a sort of multiadapter for a JOIN that includes a clause like:
db1.table1.id = db2.table1.id

As this example makes the mapping a dependent class?
If anyone is having trouble understanding the zf configure db-adapter because they are getting the response "Nothing to do!", note that the first line is meant to be read as:

zf configure db-adapter \

Once that is entered you will notice the ">" on the left, that matches the ">" in this tutorial...just keep copying and pasting till the next ">" and you'll be great!
Hello again,

If anyone is unsure of where to put the DB (php and sql) files, you must make a "scripts" folder in your root (quickstart) folder.

Name the files without "scripts/" in front and let the terminal take over
In the data mapper, the find() and fetchAll() methods could be simplified by making use of the toArray() method of Zend_Db_Table_Row_Abstract:

$entry->setOptions($row->toArray());

This also would eliminate the need to modify the find() and fetchAll() methods if the table structure changes during development. And had it not been for the created field that the save() method sets to the current datetime, one could implement a toArray() method in the model and use it to initialize $data in the save() method, which would eliminate the need to modify any part of the mapper if the table structure changes. Plus, the same mapper code could then be used for all models in the application. Or would any of that be considered in any way bad practice?

Another suggestion I have is to expand the if condition in the save() method such that the insert occurs if $id is null or 0. This would make life easier when implementing an editAction() in the controller.

Youssef Eldakar
Bibliotheca Alexandrina
for MySQL:


CREATE TABLE guestbook (
  id int(11) NOT NULL AUTO_INCREMENT,
  email varchar(32) NOT NULL DEFAULT 'noemail@test.com',
  `comment` text,
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)




INSERT INTO guestbook (email, comment, created) VALUES
    ('ralph.schindler@zend.com',
    'Hello! Hope you enjoy this sample zf application!',
    NOW()),
    ('foo@bar.com',
    'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
    NOW());

for MySQL:


CREATE TABLE guestbook (
  id int(11) NOT NULL AUTO_INCREMENT,
  email varchar(32) NOT NULL DEFAULT 'noemail@test.com',
  `comment` text,
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)




INSERT INTO guestbook (email, comment, created) VALUES
    ('ralph.schindler@zend.com',
    'Hello! Hope you enjoy this sample zf application!',
    NOW()),
    ('foo@bar.com',
    'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
    NOW());

I see two problems on this page.

First, the chapter opens with the idea of specifying a prefix ("Application_") to the class files generated by the zf tool, but there's a procedure to cause that to happen, and someone forgot to write it up (?). So far my application.ini is similar to the one shown after the db adapter configuration, but when I create the database table class its class name is Model_DbTable_Guestbook instead of Application_Model_DbTable_Guestbook. It's not too much work to add the prefix manually, but clearly it's not the way things are supposed to work at this point.

Also, the code for the GuestbookMapper class is repeated, it appears first in application/model/Guestbook.php, and then again on its own. I'm pretty sure it should only show up in its own file.
Comment 1

Regarding the "Fatal error: Class 'Application_Model_Guestbook' not found in..." problem, I encountered it too. Plamena marinova's solution above is the answer, not Joao Portelo's, because it makes clear what you are doing - initialising the autoloader, not the document type, although well done Joao for tracking down the required lines of code.

Comment 2

I also had a problem with the class Model_Db_Table_Guestbook not being found. When I used,

zf create db-table Guestbook guestbook

the class that was created was Model_DbTable_Guestbook and not Application_Model_DbTable_Guestbook, with the result that the autoloader was unable to find it.

Changing all references to the class to include the Application_ prefix made it work.

I am using Zend Framework 1.10.7. Is this a bug? If not, is there a different fix?

At least in Zend Framework 1.10.3, which is what I am currently using, the error controller's error action view script that the zf command generates is a full HTML with <html> and </html>, not a layout segment like other view scripts in this quick start. Thus, when layout is enabled, error pages become misformatted as they contain two <html> tags and two </html> tags. To correct this, insert the following right at the beginning of ErrorController::errorAction():

$this->view->layout()->disableLayout();

Youssef Eldakar
Bibliotheca Alexandrina


thanx for that Youssef Eldakar :)
Just a fix for another comment:

@Finau Kaufusi on: 2010-02-20 16:50:38


/GuestbookMapper.php
<pre>
if (null === ($id = $guestbook->getId())) {
unset($data['id']); //<--- this should be unset($data[$id]);
$this->getDbTable()->insert($data);
}


The "unset($data['id'])" is correct. If it should be $id it would be null so that the code "unset($data[null])" wouldn't make sense.

Sidtj
Sumaré, SP, Brazil
Thank you for a fantastic tutorial. I've developed more than my share of applications deeep into unmanagability using homespun ideas and patchwork frameworks. I look forward to giving this framework a try.

Application_Model_Page::__set, __get and setOptions are particularly brilliant and instructional. They are generic enough to abstract out into their own Model Parent class and use with any tables that require field based access. Is there a recommended way to do this that fits tightly into the Zend architecture?

My first inclination is to the create a ZendExtensions directory next to the Zend directory in the library, then subpath based on the Zend namespace to keep it all organized (ie: ZendExtensions/Model/ModelExtension.php).

Does this parallel directory structure make sense? Should I contribute ideas like this to the community instead?

Thanks again,
David
Thank you for a fantastic tutorial. I've developed more than my share of applications deeep into unmanagability using homespun ideas and patchwork frameworks. I look forward to giving this framework a try.

Application_Model_Page::__set, __get and setOptions are particularly brilliant and instructional. They are generic enough to abstract out into their own Model Parent class and use with any tables that require field based access. Is there a recommended way to do this that fits tightly into the Zend architecture?

My first inclination is to the create a ZendExtensions directory next to the Zend directory in the library, then subpath based on the Zend namespace to keep it all organized (ie: ZendExtensions/Model/ModelExtension.php).

Does this parallel directory structure make sense? Should I contribute ideas like this to the community instead?

Thanks again,
David
Note that when doing this for MySQL or other non-sqllite db, you do not need to create the data folder or set the file path in zf configure command. You need to specify the database name, host, user, and password. Also, there is no need to repeat those elements that are the same for different configurations. For example:

zf configure db-adapter "adapter=PDO_MYSQL&dbname=crowdom&host=localhost&username=crowdom_user&password=crowdom_password" production

zf configure db-adapter "dbname=crowdom-test&username=test_user&password=test_password" testing

zf configure db-adapter "dbname=crowdom-dev&username=dev_user&password=dev_password" development

Stop it. Just stop.
http://www.joelonsoftware.com/items/2009/09/23.html
http://www.joelonsoftware.com/articles/fog0000000018.html

it's ridiculous how intead of saying "create a file and put this inside", the author try to automate things with autogenerating scripts...
instead of saying "execute sqlite 3 < schema.sql", it writes a complicated php script to do the same...
So, where is the 'intro' to zend framework.

To me it seems that I first have to finish my master of computer science to understand this tutorial.

And the 30 minutes (as said at the beginning of this mess) have passed some hours ago.

What worth is a tutorial, when there are obviously mistakes in it, so that you get stuck at least twice a page? And placing the correct lines of code in the comment section is not helpful.

My first impression of zend: complicate and just frustrating

At this point I will quit this
and try a piece of cake(php) or some fat free framework.

Bye and good luck

Is it ok to check in mapper's save:


if (null === ($id = $guestbook->getId()))
// ^^^^^^^


while in the model we have:


public function setId($id)
{
        $this->_id = (int) $id;
//                     ^^^^^^^
        return $this;
}
[code]
Just a question ;> 

http://pl.php.net/manual/en/language.types.null.php
I followed the tutoriel carefully.
I have something when I go to http://localhost:portNumber
but when I add http://localhost:portNumber/guestbook I have a 500 error.
There is nothing in the error.log or access.log.
I've still tried what said Plamena Marinova but it doesn't work for me.
Any clue?
can someone please go thru the GuestbookMapper.php line by line so as to explain what is going on? i m not a computer science major and would like a better explanation. also, any other resources that will explain this better would be great. thank you.
I had the same "Fatal error: Class 'Application_Model_Guestbook' not found in... error. The reason for this was an old ZendFramework verion delivered with xampp under PEAR/Zend. I just removed the directory to solve this.
Please help!
I am struggling with this error:
An Error Has Occurred
Action 'configure' is not a valid action.
I do not have any clue. I have successfully used the command mentioned in previous chapters.
I am using this and getting the above error:
>zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook.db'" production
Please help!
I am struggling with this error:
An Error Has Occurred
Action 'configure' is not a valid action.
I do not have any clue. I have successfully used the command mentioned in previous chapters.
I am using this and getting the above error:
>zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook.db'" production
@Nigel King comment has saved me. I have changed the Class name in Guestbook.php from Model_DbTable_Guestbook to Application_Model_DbTable_Guestbook and it is working.
But what is the real solution? I think it is a bug in code generation.

(Even this comment form is very unfriendly. )
I have written an article based on the too friendly doc. I cannot mention the link as that will be flagged. Search satya61229 and you may get my blog: satya-weblog dot com. For XAMPP user, it should be very very helpful.
I am configuring Zend for first time and getting following error .... can any body help


Catchable fatal error: Argument 1 passed to Zend_Db_Select::__construct() must be an instance of Zend_Db_Adapter_Abstract, null given, called in G:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\library\Zend\Db\Table\Select.php on line 76 and defined in G:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\library\Zend\Db\Select.php on line 163



Thanks in advance for proving solution
I am configuring Zend for first time and getting following error .... can any body help


Catchable fatal error: Argument 1 passed to Zend_Db_Select::__construct() must be an instance of Zend_Db_Adapter_Abstract, null given, called in G:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\library\Zend\Db\Table\Select.php on line 76 and defined in G:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\library\Zend\Db\Select.php on line 163



Thanks in advance for proving solution
I recive:
"Action 'configure' is not a valid action"
for:
"zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook.db'" -s production",
and renaming class not help( What a problem can be?
Please remove the # from the beginning of lines... it makes the code hard to copy+paste.
If you see the header line followed by Application error

Make sure in your mysql configuration file(my.cnf)
skip-networking is commented.

comment out the line at my.cnf then restart mysql.

VEry very important. I was pulling my hair out for last two weeks. now got the Solution. It feels like I'm the king of the world :D
I have the same error as Amardeep :
Catchable fatal error: Argument 1 passed to Zend_Db_Select::__construct() must be an instance of Zend_Db_Adapter_Abstract, null given, called in D:\xampp\php\PEAR\Zend\Db\Table\Select.php on line 76 and defined in D:\xampp\php\PEAR\Zend\Db\Select.php on line 163
I can't figure out what the error in the code could be. :-(
Anyone has already faced and fixed that one ?
thanks
My only problem here was that in the previous tutorial I set up my application without setting the APPLICATION_ENV variable to Development... and therefore I 'm actually in production... And the database was not created!
Example should have a "red alert" for not being able to connect to the database
My only problem here was that in the previous tutorial I set up my application without setting the APPLICATION_ENV variable to Development... and therefore I 'm actually in production... And the database was not created!
Example should have a "red alert" for not being able to connect to the database

PS:
The captcha system is crap...
1)it is human unreadable;
2) It always tell me that the message was posted...
3) I really must be blind... (just to say I've been trying lots of times now)
4) This is impossible... I got it right this time
5) #/¤/(Q/&¤=
My only problem here was that in the previous tutorial I set up my application without setting the APPLICATION_ENV variable to Development... and therefore I 'm actually in production... And the database was not created!
Example should have a "red alert" for not being able to connect to the database

PS:
The captcha system is crap...
1)it is human unreadable;
2) It always tell me that the message was posted...
3) I really must be blind... (just to say I've been trying lots of times now)
4) This is impossible... I got it right this time
My only problem here was that in the previous tutorial I set up my application without setting the APPLICATION_ENV variable to Development... and therefore I 'm actually in production... And the database was not created!
Example should have a "red alert" for not being able to connect to the database

PS:
The captcha system is crap...
1)it is human unreadable;
2) It always tell me that the message was posted...
3) I really must be blind... (just to say I've been trying lots of times now)
4) This is impossible... I got it right this time
My only problem here was that in the previous tutorial I set up my application without setting the APPLICATION_ENV variable to Development... and therefore I 'm actually in production... And the database was not created!
Example should have a "red alert" for not being able to connect to the database

PS:
The captcha system is crap...
1)it is human unreadable;
2) It always tell me that the message was posted...
3) I really must be blind... (just to say I've been trying lots of times now)
4) This is impossible... I got it right this time
I have been followed the complete steps as given in this quickstart toturial. Once i complete this step and tried to access the guestbook page, i am getting 404 file not found error.

I am using Windows XP and iis 5.1

Please help me to cross out this hurdle.
This tutorial makes the simplest things sound complicated and misses out important information. Even after following the tutorial step by step, something always does not work as it should and I have to read the comments or do internet searches to sort out the problem.

In my view, this tutorial makes Zend a frustrating learning experience.
This tutorial help me a lot, informations are very usefull, My ZF application based on this architecture works well :)
I have made some improvements on the code structure, particularly on Map classes. Here is the result:

All Mapper classes extends from an abstract class, which refactor majority of the code. Some static functions make instanciation of mapper optional.

Be careful: this code works for PHP >= 5.3, because of static attribute.

------------------------------------------------------------------------------------------
abstract class Model_Mapper_Abstract
{
protected static $_dbTableName;
protected $_dbTable;


public function setDbTable($dbTable) {
if (is_string ( $dbTable )) {
$dbTable = new $dbTable ( );
}
if (! $dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception ( 'Invalid table data gateway provided' );
}
$this->_dbTable = $dbTable;
return $this;
}

/**
* @return Zend_Db_Table_Abstract
*/
public function getDbTable() {
if (null === $this->_dbTable) {
$this->setDbTable ( 'Model_DbTable_' . ucfirst(static::$_dbTableName) );
}
return $this->_dbTable;
}

public function find($id) {
$result = $this->getDbTable ()->find ( $id );
if (0 == count ( $result )) {
return null;
}
$row = $result->current ();
$model_className = "Model_" . ucfirst(static::$_dbTableName);
$customer = new $model_className ( $row->toArray () );
return $customer;
}

public function getAll() {
return ($this->fetchResults($this->getDbTable ()->fetchAll ()));
}

protected function fetchResults($resultSet) {
$entries = array ();
$model_className = "Model_" . ucfirst(static::$_dbTableName);
foreach ( $resultSet as $row ) {
$entries [] = new $model_className ( $row );
}
return $entries;
}

public static function getAllResults() {
$dbTable_className = 'Model_DbTable_' . ucfirst(static::$_dbTableName);
$model_className = "Model_" . ucfirst(static::$_dbTableName);
$dbTable = new $dbTable_className ( );
$resultSet = $dbTable->fetchAll ();
$entries = array ();
foreach ( $resultSet as $row ) {
$entries [] = new $model_className ( $row->toArray() );
}
return $entries;
}

public static function findById($id) {

$dbTable_className = 'Model_DbTable_' . ucfirst(static::$_dbTableName);
$dbTable = new $dbTable_className ( );
$result = $dbTable->find ( $id );
if (0 == count ( $result )) {
return null;
}
$row = $result->current ();
$model_className = "Model_" . ucfirst(static::$_dbTableName);
$object = new $model_className ( $row->toArray () );
return $object;
}
}
------------------------------------------------------------------------------------------



Having said that, here is the structure of a concrete Mapper. The save function is still here, because of the specificity for each class. This method can be implemented in abstract class thanks to toArray() method in the model (as Youssef Eldakar said), but I don't recommand it:
- responsibility of dababase schema must remains in Zend_DbTable and Mapper classes
- responsibility of Model classes must remains in Model_* and Mapper classes.
------------------------------------------------------------------------------------------
class Model_Map_GuestBook extends Model_Mapper_Abstract {
protected static $_dbTableName = "guestBook";

public function save(Model_Guestbook $guestbook)
{
$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'created' => date('Y-m-d H:i:s'),
);

if (null === ($id = $guestbook->getId())) {
unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id));
}
}
}
------------------------------------------------------------------------------------------


Last Tip: here is some functions I suggest to integrate in mapper during development phase. There is no value-added code here, but this permit a full completion (Type Hinting) support in environments like PHP Eclipse, Zend Studio...
------------------------------------------------------------------------------------------
/**
* @return Model_GuestBook
**/
public function find($id) {
return parent::find($id);
}

/**
* @return Model_GuestBook
**/
public static function findById($id) {
return parent::findById($id);
}

/**
* @return Model_DbTable_GuestBook
**/
public function getDbTable() {
return parent::getDbTable();
}
------------------------------------------------------------------------------------------

Hope this helps :)

Regards,
Damien THIESSON

Anyone who wants to enable mysql for this demo also has to make sure that his/her php5 is configured to use mysql with the PDO adapter, IE:

./configure --with-apxs2=/usr/local/apache/bin/apxs --with-mysql --enable-pdo --with-pdo-mysql=shared

After that I had to add the pdo-mysql.so extension to php.ini, and it worked.

-Sean

Why does the find method in the mapper class take an instance of the guestbook model as a second parameter?
Maybe I am mission something but shouldn't the find method instantiate the model as the fetchAll method does in it's foreach loop?
Or should I create an instance of the guestbook model before calling the find so that I can pass the second parameter.

*** application/models/GuestbookMapper.php    (web)
--- application/models/GuestbookMapper.php    (maybe)
***************
*** 42,44 ****
   
!     public function find($id, Application_Model_Guestbook $guestbook)
      {
--- 42,44 ----
   
!     public function find($id)
      {
***************
*** 49,50 ****
--- 49,51 ----
          $row = $result->current();
+         $guestbook = new Application_Model_Guestbook();
          $guestbook->setId($row->id)
I wish this manual would explain the creation and application of a db adapter in pure PHP, without the % zf magic. I am missing the connection to the database in the model.
Hm, also die Beschreibung (DE) hat unmengen von schaibfeelar. Es ist nicht beim ersten mal lesen zu erkennen welche Schritte gelesen und welche auszuführen sind. Die Codeansicht liefert keine Informationen ob einleitende <?php und abschliesende ?> benötigt werden. Pfadangaben mangelhaft (wer so beschreibt frisst bestimmt auch kleine Kinder), von wo aus soll was getan werden (zb c:\Zend\...\...\> zf mach was ich sage)?, Befehls unterscheidungen je OS nicht vollständig angegeben.

Comments: Sagt mal wollt Ihr hier überhaupt hilfe erhalten, bitte immer OS und Datenbank Typ angeben, eine Baumansicht der Verzeichnisse würde auch helfen.

Meine Schwierigkeiten bisher: (Vista, MySql | SQLITE)
Erstes war zu erkennen das man den (database excel sheet) nicht wie angegeben bei Windows verwenden kann sondern mittels c:\Zend\Apache2\meineTest\> zf create db-table Guestbook guestbook.
Tja und zwischendurch habe ich bemerkt das die NaviMenüpunk nach http://localhost/test/public/guestbook weist.

Fazit: Diese Beschreibung sollte man ignorieren da auch die Comments grösstenteils unbrauchbar sind. Es stellt sich jetzt für mich die Frage doch weiter ein eigenes Framework zu nutzen und weiter meine Lebenszeit mit eigenem KauderwelchFramework zu arbeiten.

Im übrigen gibt es gute beschreibungen wie man gute beschreibungen anfertigt. Es müsste ein Gesetz dagegen geben solche Schriftstücke auf die Menschheit loszulassen.




I get "Warning: Invalid argument supplied for foreach() " on my guestbook page, everything else works fine.

To get mysql working I had to add these lines to my php.ini:
extension=pdo.so
extension=pdo_mysql.so

and these lines to my application.ini under [production]

resources.db.adapter="PDO_MYSQL"
resources.db.params.host="localhost"
resources.db.params.username="bobandst"
resources.db.params.password="p1ssw2rd"
resources.db.params.dbname="bobandst_Main"


I also had to add this line to my .htaccess file to get the development environment:
SetEnv APPLICATION_ENV development

My application still seems to have issues connecting to the database, are there more config lines that I am missing?
This tutorial doesn't work at all. I'm having Fatal error: Class 'Application_Model_GuestbookMapper' any any tips from comments don't help..
i ma new to zend i know that construct use setOptions but $options is null can anyone explain me how does it work __construct and __get and __set


public function setOptions(array $options)

{
$methods = get_class_methods($this);
foreach ($options as $key => $value) {

$method = 'set' . ucfirst($key);

if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
This example is wrong working with DB.

If you use DB then class constructor mus have
class Application_Model_Guestbook
{
protected $_comment;
protected $_created;
protected $_email;
protected $_id;

public function __construct(array $options = null)
{
parent::__construct($options); // This line must be to set DB adapter
if (is_array($options)) {
$this->setOptions($options);
}
}
}
I'm still unsure about whether my domain model should be returning Zend_Db_Table_Rowsets or arrays of custom objects. I've used Zend_Paginator with the DbTableSelect adapter and found it very useful. How would I handle pagination when my dataMappers are not passing back Zend_Db_Table_Rowsets but rather arrays of my model objects? Would I use Zend_Paginator in the dbTable resource files, allow the mapper to pull out the rows and create model objects from them and then pass the paginator object back some other way?
I have been followed the complete steps as given in this quickstart toturial. Once i complete this step and tried to access the guestbook page, i am getting 404 file not found error.

I am using Windows 7 Zend Server CE

Thanks!!!
I don't understand this point in the Mapper code:

$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'created' => date('Y-m-d H:i:s'),
//--> maybe here we should be adding 'id'=> $guestbook->getId();
);

if (null === ($id = $guestbook->getId())) {
unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id));
}


Why are we 'unset'-ing a variable that was never set? Should we add $data['id'] first? Are we assuming Id is an auto_increment field? That's why we are not inserting it to the table? What am I missing here?
@Marie-Helene, the reason to not use the Zend_Db_Table_Row directly is that the author is trying to demonstrate a method for decoupling DOMAIN objects from persistent database records. In MANY scenarios, your point makes sense, but there are many places where it falls apart and it is better to just build the right plumbing initially to save time later.

@Youssef -- You seem to be exposed to this as well by trying to reflect on the incoming array in order to derive the table's column names. You should consider always implementing a mapper between domain objects and the storage of the data.

Ok, I wrote reams of text and then realized that I should Google Data Mapper Pattern to see if anybody said it more succinctly so I deleted mine and I direct you to Martin Fowler's description... (the point that I had written reams about was collection of objects in objects. This is something that can be handled by a mapper -- although if you're going to be doing this extensively, it would be worth looking into a full-blow ORM solution like Hibernate, or Doctrine/Outlet)

http://martinfowler.com/eaaCatalog/dataMapper.html
Magnus Olsson on: 2011-02-07 07:30:40:
Why does the find() method in the mapper class take an instance of the guestbook model as a second parameter?

This is something that I don't understand either. Can someone please clarify this for us?
matttrach on: 2011-04-18 18:22:02:
I don't understand this point in the Mapper code:
public function save(Application_Model_Guestbook $guestbook)
{
    $data = array(
        'email'   => $guestbook->getEmail(),
        'comment' => $guestbook->getComment(),
        'created' => date('Y-m-d H:i:s'),
    );

     if (null === ($id = $guestbook->getId())) {
        unset($data['id']); // <<< It is about this code. What's it doing here?
        $this->getDbTable()->insert($data);
    } else {
        $this->getDbTable()->update($data, array('id = ?' => $id));
    }
}

Why are we 'unset'-ing a variable that was never set?

I wonder how this code ended up in here. Right now it is clearly unnecessary, so I will not implement this line of code in my applications.
But hey, someone willing to relief us with the thruth would be welcome, 'cause this code is bugging me. LOL
It has been a rough task to learn this framework. I am still stuck at quick start.

I am using PDO_MYSQL as my adapter. I have followed the tutorial to the letters.

At a point, it says to create application/models/GuestbookMapper.php and put the following code

class Application_Model_GuestbookMapper
{
public function save($model);
public function find($id, $model);
public function fetchAll();
}

Then it say to run this command

zf create model GuestbookMapper

The tutorials claims to insert additional methods. But in my case, it emptied the my GuestbookMapper class with this

class Application_Model_GuestbookMapper
{

}

Same goes with another command zf create model Guestbook. It empties the scripts, with just plain class defination.

Please help me !
For all of you cannot reach the guestbook page or any page other then the front page. You remember to add:

<Directory "C:\Zend\Apache2/htdocs/Quickstart/public">
DirectoryIndex index.php
AllowOverride All
Order allow,deny
Allow from all
</Directory>

I didn't pay attention - I only added:

<VirtualHost *:80>
ServerName hello.localhost
DocumentRoot "C:\Zend\Apache2/htdocs/newapp/HelloWorld/public"
#DocumentRoot "C:\Zend\Apache2/htdocs/Quickstart/public"

SetEnv APPLICATION_ENV development

</VirtualHost>

I hope this can help others with the same issue ; )
Hi,

For those who r using Abyss web server, dun forget to set the URL rewriting.. if not you will get error 404.

http://www.aprelium.com/abyssws/articles/urlrewriting-modrewrite-conversion.html
The "unset($data['id'])" - doesn't make sense. And it should be removed. Right ?

Why isn't ?
why the auto loading not initiate by its own?
I USE in WIN 7
zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook.db'" production
I guess this solution is more easy and implement very fast.

$resultSet = $this->getDbTable()->fetchAll();
$entries = array();
foreach ($resultSet as $row)
{
$entry = new Application_Model_Guestbook();
foreach ($row as $key => $value)
{
$method = 'set'.ucfirst($key);
$entry->$method($value);
}
$entries[] = $entry;
}
return $entries;

Thanks the community for the best framework of the world!

JCROOT
when i use the ZF tool to create a model ... it does so inside /applications/models/DbTable/ModelName.php ... is the model in this tutorial analogous to that ZF created model? supplemental? i ask because i have noticed that the details tend to shift over each iteration of the ZF framework. the path to the Zend includes being one of those details that has shifter since 1.7 ... to 1.11 (current). if this tutorial is 'current' ... why not use the ZF tool?
is this tutorial even relevant to someone using MySQL server?
why use an MVC framework to write to what is basically a flat file? sql lite ... when does anyone ever use that db?
los comandos zf configure db_adapter tal cual como estan escritos en el tutorial, utlizando netbeans 6.9.1 "NO FUNCIONAN".
La unica manera de hacerlos andar fue asi:

zf configure db-adapter "adapter=Mysql&dbname=APPLICATION_PATH '/../data/db/guestbook.db' " -s production

cambiando para cada section el archivo y el valor de -s.

Espero le sirva a alguien
fdgdf
if your documentroot doesn't point directly to the public folder you'll need to set the rewritebase

ex: 127.0.0.1/asdf/jkl/public/

in .htaccess add

RewriteBase /asdf/jkl/public/

you'll get a 404 w/o
This is a really poor tutorial. Installed Zend Server on a Ubuntu VM and it broke my other Apache/PHP install. Finally got it sorted out and back to a running state and installed a standalone Zend Framework into my existing Apache/PHP stack.

The tutorial then:
- fails to tell you exactly where to put files (like the database and SQL/loader scripts)
- contains incomplete code (people have to insert the <?php ?> tags themselves)
- doesn't explain enough as it goes along - I feel like I'm learning how to build a very simple app without the tutorial explaining WHY I'm doing certain things, like creating the Application_Model_GuestbookMapper class, or creating a huge long script to set up my database

And now...on top of all that...I'm stuck because the load.sqlite.php script won't define the APPLICATION_PATH and so the script can't find the application.ini

Do I really want to learn a framework for developing apps when the developers of the framework can't even write a decent tutorial?

1/2 hour? It's taken me all day to get this far and I'm giving up.
Can anyone provide me a step by step tutorial of zend Framework.
it started from basic knowledge such as folder structure or cover all the area
of web application like database connectivity ,query to database.

please reply as soon as possible It is argent.
So there's a lot of stuff going around here that i don't really get. Most of the code provided above is quite easy to understand if you've worked with the framework a little bit and thread throughoutly.

But there's a few lines i don't get:
public function find($id, Application_Model_Guestbook $guestbook)
    {
        $result = $this->getDbTable()->find($id);
        if (0 == count($result)) {
            return;
        }
        $row = $result->current();
        $guestbook->setId($row->id)
                  ->setEmail($row->email)
                  ->setComment($row->comment)
                  ->setCreated($row->created);
    }

1) How is one supposed to make use of that function?
So i assume i have to be like
$table = new Application_Model_GuestbookMapper();
$row = new Application_Model_Guestbook();
$row_that_i_want = $table->find(42, $row);

Even if that were correct, the code would still not du anything? It does not give anything back!? There is no return, so that assignment has no use...


2) Then what i don't understand either with the three-layered abstraction is,
We have a tableMapper-class
We have a tableRowset-class
We have a tableRow-class

The only thing that extends something from the framewok is the tableMapper
Shouldn't the tableRowset and tableRow extend the specified Zend-Classes, too?

Because:
How am i supposed to built relationships between tables with the code provided above?
I can assign the relationships inside the tableMapper class, but how do i access them?

I would want to be like:
$table = new tableMapper();
$row = $table->find(1); // eventually $table->find(1)->current();
Lets say i got an Author with this, from this author i want to retrieve all books
$row->getBooks();

The getBooks(); funktion in the rowclass would call something like findDependentRowset();
But the rowClass doesn't know that functiuon, als there is no connection.


Now i have built relationships of tables in a previous project where i simply used a rowsetClass and a rowClass - with the tableMapper on top i don't know how i would be able to do this at all. it's just a little bit weird.

As many people have problems with understanding this quickstart, i think the quality should be checked again
And please just use mysql or a sql server - no one wants to "copy and see how it works" with a sqLite file.. ;)

I found the quick start document make me more confused.
For those of you who feel you have followed the guidelines perfectly, and has configured the rewrite rules and enabled these in apache, but still get a 404.
Try looking at the vhost configuration. If AllowOverride is not set to All, it will not work!
I must say one thing.. zend is good but this article is very poorly written.

I agree with most of the people here who are having issues with Mysql as there is nothing specific given for that.

I request you guys to please post or edit this article and mention , how to configure the quickstart project with mysql.

I will be waiting

Noddy
I suggest to all, do not follow this tutorial. Find better with uncle google help.
bad tutorial
Really bad tutorial...... Here are some links which may be useful,

http://www.phpeveryday.com/articles/Zend-Framework-Basic-Tutorial-P840.html
http://www.survivethedeepend.com/
Learning ZF has been frustrating as hell. Most ZF tutorials I have read so far are just like this one: twisted, incomplete and full of errors.

I appreciate the good intentions of the author, but the results are very frustrating for programmers trying to learn this framework.

Why not use MySQL?
Why create a twisted script to create the database?
Why do I have to guess the directories I have to use?
Why make assumptions?

Please, keep it simple, and be thorough in the explanation. I am not giving up on ZF, but I am really disappointed in the Zend communitiy efforts to educate the new comers.
Why is this tutorial for SQLITE as long as the ZendServer CE is shiped with mysql?
In adition you cannot create any Database in this MySQL-Server.
How can one test their application if one have no right to create the database?

But nice to read, that I'm not the only frustrated one.
I fully agree with Manolo. I've been stuck at the following error "Fatal error: Class 'Application_Model_GuestbookMapper' not found in C:\xampp\htdocs\blog\application\controllers\GuestbookController.php on line 13".

I find that there should be small steps instead of making a high level tutorial especially while talking about a quick tutorial for beginners.
Hi,
I did this tutorial and everything worked after setting up my httpd.conf und my paths for php and zf tool. But if I send up my form to write into my database there was a problem and I got error "page not found".Look at code below:

if ($this->getRequest()->isPost())
{
if ($form->isValid($request->getPost()))
{
$model = new Application_Model_Guestbook($form->getValues());
// line that doesn't work is here:
$model->save();
return $this->_helper->redirector('index');
}
}

I solved it this way:
if ($this->getRequest()->isPost())
{
if ($form->isValid($request->getPost()))
{
$model = new Application_Model_Guestbook($form->getValues());
// my solution
$guestbook = new Application_Model_GuestbookMapper();
$guestbook->save($model);
// end of my solution
return $this->_helper->redirector('index');
}
}

I'm not the real ZF-Crack. I see, the Guestbook mapper is initiated in the IndexAction(). Now I'm not sure how PHP handles this. Does PHP create this instance of class only for the IndexAction() or does it create this instance global? In second case it must work without my solution.... Is there anyone with a better solution or the same problem? (And sorry for my bad english.. :) )
Sorry, my last post belongs to GuestbookController.php :)
To practice on mysql databse please use add below lines to [production] section in application.ini

resources.db.adapter = "pdo_mysql"
resources.db.params.host = "localhost"
resources.db.params.username = "root"
resources.db.params.password = ""
resources.db.params.dbname = "my_database_name"
resources.db.isDefaultTableAdapter = true

and execute below queries in your mysql database



CREATE TABLE guestbook (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
comment TEXT NULL,
created DATETIME NOT NULL
);

CREATE INDEX id ON guestbook (id);

INSERT INTO guestbook (email, comment, created) VALUES
('ralph.schindler@zend.com',
'Hello! Hope you enjoy this sample zf application!',
NOW());

INSERT INTO guestbook (email, comment, created) VALUES
('foo@bar.com',
'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
NOW());

Keep other classes same as mentioned above.
This section of tutorial has some bugs.

0. Please remember to surround the load.sqlite.php content with <?php and ?>

1. In case you see "The sqlite driver is not currently install"
For basic LAMP installation you might need to do
>sudo apt-get install php5-sqlite
To install sqlite driver.

2. In case you see "SQLSTATE[HY000] [14] unable to open database file
Remember to move data and scripts in the correct folder

Put "scripts" and "data" folders in the same folder of
"application data docs library public scripts tests"

where there are:
scripts/load.sqlite.php
data/db/
Congrats Zend Team for messing up with your tutorial.
I don't know if it's only me but i find setting up Zend to work is a tedious task. instead of making the development faster, just slows it down plus this messed up tutorial. Nice!
If you're getting a 404 or 403 on the guestbook page you might want to check that:
- you set the absolute path to your installation on both the DocumentRoot and Directory directive in your httpd.conf.
- you have Options +FollowSymLinks in either your .htaccess or your httpd.conf VirtualHost > Directory directive.
hth
If you are using xampp and getting 404 errrors, you need to set Apache's DocumentRoot as your 'Public' folder "C:\...\xampp_dir\...\projectname\Public".

This is done in the Apache configuration file: "C:\...\xampp_dir\apache\conf\httpd.conf"
JOB OFFER TO ALL INTERESTED APPLICANTS .
I am Mrs Antonia Benson , I work in Sunshine Dairy Foods Company here in Canada ,

we need workers from all parts of the world to join the company , whether skill or

unskilled they are all qualified to join the company .
You can also invite any of your friends and relatives to join us either the branch

in Canada or United kingdom.
All approved applicants are to be granted free air plane ticket and free

accommodation , applicants are only responsible for work permit visa requirements

with the Canada Immigration Bureau here upon received of employment form.
Contact us through this email:sunshineemploymentinfo@inmail.sk , or

(sun.shinecompany@yahoo.ca)

Your best Cooperation is highly appreciated .
Mrs Antonia Benson,
Employment Consultant Officer ,
Human Resources Department .
150 - 6TH AVENUE SW CALGARY
ALBERTA T2P 3Y7,CANADA.
Piotr ;) I can tell you that with a little bit more patience and effort, you will get it running. Check your errors and you'll be fine.
MICROSOFT is making very good tutorials for asp.net TRY LEARN FROM THEM!!!

Ouch, do not forget to realize, this whole project is open source and free.

Thanks for this tutorial guys!! Loving ZF!
Hallo

Ein kleiner Schönheitsfehler beim INSERT von data.sqlite.sql


INSERT INTO guestbook (email, comment, created) VALUES
    ('ralph.schindler@zend.com',
    'Hallo! Hoffentlich geniesst Ihr dieses Beispiel einer ZF Anwendung!
    DATETIME('NOW'));


Es fehlt das ' und das komma danach!


'Hallo! Hoffentlich geniesst Ihr dieses Beispiel einer ZF Anwendung!',

gruß
Is it really necessary to show what has changed and then the whole file again? Or is it just done to make this tutorial look bigger than it is?
A Zend tutorial that's not terrible:

http://www.phpeveryday.com/articles/Zend-Framework-Basic-Tutorial-P840.html
I've just run through the quickstart using a fresh copy of ZendFramework-1.11.9 (Mac OSX 10.6.8) and at this point I haven't had any major problems at all yet.

I skipped the 'zf configure db-adapter' portion and simply added the mysql details in the application.ini as mentioned above:

resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "mysqlusername"
resources.db.params.password = "mysqlpassword"
resources.db.params.dbname = "dbname"


I appreciate there are a lot of comments (and good info) above and maybe as a result the tutorial may have been amended over time to where it is now.

New users running through this for the first time might simply give up after reading all the comments, however, it's really not that bad :)



There is an answer at the bottom of this message.

Scroll down if you're in a hurry.




--------------- Problem --------------------

Running zf configure db-adapter on windows with the arguments given in this tutorial, does not work.

There are a lot of comments about not being able to run the commands given to configure the db-adapter on windows machines.

The commands given are formatted for linux and aren't easily converted.




--------------- Issue -----------------

Command Given:

% zf configure db-adapter \
> 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
> production

The trick is that the argument:

'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"'

contains spaces, double quotes, and the & symbol.




--------------- Working out the solution ------------------

spaces delimit arguments. Resolve by wrapping in double quotes.
& is used when writing multiple commands on a single line. as in
dir&tree
will give you a directory listing followed by a tree. Resolve by escaping the & with ^ when the & lies outside of a literal string.

I'm assuming the intention of wrapping the entire argument in single quotes on linux is to pass it as a literal string. On windows you pass an argument as a literal string by wrapping it with double quotes. So first convert the single quotes to double quotes.

"adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db""

Then notice that the command won't work. This is because the argument contains double quotes and ends up being parsed as several arguments instead of one.

So step 2, find all the double quotes inside the argument and double them.

"adapter=PDO_SQLITE&dbname=APPLICATION_PATH ""/../data/db/guestbook.db"""

Now you might be thinking about escaping the &, don't. The & is interpreted literally, not as a control character or anything special. If the & or any other special character ends up outside of the literal string, then you need to escape them with ^.




--------------- Solution ---------------------------

PLEASE INCLUDE THIS ALTERNATE SET OF COMMANDS FOR WINDOWS USERS. :D

The whole thing ends up converting to this:

C:\path\to\project\root\> zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH ""/../data/db/guestbook.db""" production


C:\path\to\project\root\> zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH ""/../data/db/guestbook-testing.db""" testing


C:\path\to\project\root\> zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH ""/../data/db/guestbook-dev.db""" development

********** convert C:\path\to\project\root\ to the location of your project folder ( parent of application folder ) **********




--------------- Results ---------------

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
appnamespace = "Application"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"
resources.view[] =

resources.db.adapter = "PDO_SQLITE"
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

resources.db.adapter = "PDO_SQLITE"
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1

resources.db.adapter = "PDO_SQLITE"
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"


********** Notice that **********

resources.db.adapter
and
resources.db.params.dbname

both have exactly the same values as given in the tutorial when using the commands given in my solution.



----- Side note --------

Could we run zf.php with the CLI and avoid a lot of confusion? Interactive mode is still broken on windows machines as far as I know, but I work around it with:

<?php
while (1) {
fputs(STDOUT, "\r\nPHP_MODE: ");
eval(trim(fgets(STDIN)));
}
?>

I save that to a file called interactive.phps and start it with:

C:\path\to\php.exe -f "C:\path\to\interactive.phps"

and php interprets everything I type. There's no error handling, so if you type anything wrong the window will close. When you're done type exit; and you'll leave PHP_MODE and be back to the shell you were in before.

If say. . . the environment variables could be set with a php file and this snippet had some sort of error handling then we could forget about a lot of differences between linux and windows command line syntax. . . maybe. . .


... or maybe a web interface for common . . . I don't know what I'm getting into. . ..






--------------- Quick Solution For the Impatient ---------------------------

PLEASE INCLUDE THIS ALTERNATE SET OF COMMANDS FOR WINDOWS USERS. :D

The whole thing ends up converting to this:

C:\path\to\project\root\> zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH ""/../data/db/guestbook.db""" production


C:\path\to\project\root\> zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH ""/../data/db/guestbook-testing.db""" testing


C:\path\to\project\root\> zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH ""/../data/db/guestbook-dev.db""" development

********** convert C:\path\to\project\root\ to the location of your project folder ( parent of application folder ) **********
In the generated index.php file contained in the quickstart/public folder for this project it defines:

defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

APPLICATION_PATH seems to be a sibling folder of the folder containing index.php, specifically it would resolve to quickstart/application/ unless intentionally changed.

So APPLICATION_PATH = quickstart/application

then in application.ini we set the databases for test dev and production to all go into one folder located at:

resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

APPLICATION_PATH/../data/db/guestbook-dev.db

quickstart/application/../data/db/guestbook-dev.db

quickstart/data/db/guestbook-dev.db

This is also the file structure in the zip file of the completed tutorial. So it is safe to assume that the folders "data" and "application" are siblings whose parent is the folder "quickstart".



Please edit this section of the tutorial:

---- Quote ------

Note that the database(s) will be stored in data/db/. Create those directories, and make them world-writeable. On unix-like systems, you can do that as follows:

% mkdir -p data/db; chmod -R a+rwX data

On Windows, you will need to create the directories in Explorer and set the permissions to allow anyone to write to the directory.

At this point we have a connection to a database; in our case, its a connection to a Sqlite database located inside our application/data/ directory. So, let's design a simple table that will hold our guestbook entries.

---- End Quote -----

Specifically, the directories confuse me and there are other comments saying the same thing. If you could change the reference to "data/db/" into "quickstart/data/db/" then it would be very clear where the data directory belongs. Also, change the reference to "application/data/". I didn't see any instruction to create this folder and it was also not present in the completed project.


quickstart was the name of the initial folder we made on the second page of this tutorial. It serves as an effective point of reference when we're going through this tutorial where we're not familiar with the file structure or methods or basically anything. I don't even remember what I was reading because I've wasted so much time reading typos and converting linux command syntax into something that works on windows so I could use the batch file referenced in these very instructions.


I AM NOT A HAPPY DUCK. :(


Is the Zend Framework really worth all this effort?


I will be back to try doing all this by hand again. Don't delete my comments. I'll need them for next time. . .
Anyone that receives the 500 Error or a "File not found" error when attempting to access localhost/public/guestbook needs to ensure they added the <Virtualhost> settings to their httpd.conf file.
Also, to everyone complaining about this tutorial not being perfect, don't use it. In programming and scripting you are going to run across problems and issues which you need to be able to solve on your own.

The writer for this had alot of content to cover, and cannot compensate for everything that everyone may or may not already know. If you're even attempting to learn a framework then you should already have some common coding sense and problem solving skills or else you failed before you even came here.
@matttrach: There is mistake in view/scripts/guestbook/index.phtml. There should be:

Guestbook Entries: <br />

<dl>
<?php foreach ($this->entires as $entry): ?>
<dt><?php echo $this->escape($entry->email) ?></dt>
<dd><?php echo $this->escape($entry->comment) ?></dd>
<?php endforeach ?>
</dl>

but ther is:
Guestbook Entries: <br />

<dl>
<?php foreach ($this->entries as $entry): ?>
<dt><?php echo $this->escape($entry->email) ?></dt>
<dd><?php echo $this->escape($entry->comment) ?></dd>
<?php endforeach ?>
</dl>

Best regards

Krzysiek

Ive just added the following lines to application.ini:
resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "username"
resources.db.params.password = "pass"
resources.db.params.dbname = "dbname"
resources.db.isDefaultTableAdapter = true

Try just modifying localhost to 127.0.0.1 like the following:

resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "127.0.0.1"
resources.db.params.username = "username"
resources.db.params.password = "pass"
resources.db.params.dbname = "dbname"
resources.db.isDefaultTableAdapter = true

This way worked for me.
I can't believe that there isn't a complete example using MySQL!!! Following this SQLITE we're getting "lost in the sauce"!
Wow, this can be quick tricky in the corners, but that's a brilliant framework so it can't be too easy.

In my case I am using a mac with Zend Studio 8 and Zend Server 5.5. This quickstart is the zend framework example in Zend studio and almost everything is already written. but I wanted to get the php script to run and got stuck a bit trying to get this include_path to work.

At the end, I changed the APPLICATION_PATH and it works :

defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
set_include_path(implode(PATH_SEPARATOR, array(
APPLICATION_PATH . '.:/usr/local/zend/share/ZendFramework/library',
get_include_path(),
)));

good luck guys ;)
This tutorial sucks.
please streamline it.
thank you.
I follow these steps but to access the guestbook controller the browser displays 'not found'

What's problem?
In my Models I have a function:

public function getOptions(array $exceptions = array())
{
$data = array();
foreach ($this->options as $key => $value) {
$data[$key] = $this->__get($key);
}
return array_diff_key($data, array_flip($exceptions));
}

which allows me to get all of the data with one call rather than individually grabbing all options to store in a data array during something like a save:

public function save(Application_Model_Guestbook $guestbook)
{
$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'submitted' => date('Y-m-d H:i:s'),
);

public function save(Application_Model_Guestbook $guestbook)
{
$data = $guestbook->getOptions(array('id'));
% php scripts/load.sqlite.php --withdata production!!!
This is the worst documentation i have ever saw,helpless , thinking of moving to symfony .
shit
I agree, this is shit
Sorry everyone... we are way to busy to even bother reading, let alone update this tutorial. Once we get our thumbs out of our you-know-whats, we might get around to fixing this.
Hello everyboy,

Please, someone can tell me from where came these 'set' and 'mapper' in application/models/Guestbook.php?

public function __set($name, $value) {

//This set I'm asking
$method = 'set' . $name;

//This mapper I'm asking
if (('mapper' == $name) || !method_exists($this, $method)) {

throw new Exception('Invalid guestbook property');
}
$this->$method($value);
}

Also I would like suggest to Zend's people who make the quick start to write comments in the main example code. Maybe it can help better newbies like me.

Thanks!
too much problem with CLI, i found this solution, it's quick and easy:
1. just copy the 3 files data.sqlite.sql, schema.sqlite.sql and load.sqlite.php in public than
2. excute it from the browser just li this
http://quickstart.local/load.sqlite.php?w
you should see

Writing Database Guestbook in (control-c to cancel): 5 4 3 2 1 Database Created

don't mess with CLI, you will waste your time just like I did.
Bye

p.s.
PHP Version 5.3.2-1ubuntu4.10
eclipse Helios (still problem using zend CE modules)

extreamly hard to learn this framework
really wasted hours an hours to learn how to connect to db only.
Still no success
Just a note. I had to add the line ...
<?php
... as the first line of the file load.sqlite.php and add as the last line of this file ...
?>

probably obvious to experience php programers ... but not :)
"Not Found
The requested URL /quickstart/guestbook was not found on this server."

this complete source code http://framework.zend.com/demos/ZendFrameworkQuickstart.zip doesn't work too.

This is the second part of this tutorial that simply doesn't work. Still getting error messages (or the ZF default index page if I put in .../public/index.php).

I think this "quickstart" tutorial is poorly written and not properly tested in the real world.

I'm not an inexperienced php programmer and I'm struggling to get this to work. Very poor Zend....
Hi,
the document is very good, however few questions and hints arise that I want to share with you all.
First of all, my programming idea is DOWIN - Do Only What Is Necessary. An illustration: there is a framework-builtin mechanism that you may use 'as is' or modify/interface for your own. Do you REALLY need interfacing this mechanism? YES? Then go on. NO? Then leave it as it is, please.
Zend framework is a BRILLIANT thing, it's a diamond among the MVC frameworks. Thanks to the hard work of many brilliant programmers, developers, analysts, managers, it contains anything a PHP MVC programmer needs.

As for the models described in the article, let's see what we want to achieve by making them. Separation of data logic and data storage mechanisms? Then we/you are right about making separate "mapper" classes for them. Also, separation of mappers from classes extending Zend_Db_Table is much safer than introducing our own functionalities to the class that contains thousands of lines of code; at least we don't risk breaking anything defined in the parent, abstract class. So a "has-a" solution is as great as can be: we just make a class for table defining the database details, pack it in a nice and tidy suitcase of getter/setter, and we find it a shelf inside our model. Great.

As for the model for data item: I really think it's unnecessary to create getter/setter methods for all data.
For the basic functionality, it's absolutely reduntant. So according to DOWIN, let's think whether we really-really
need some extra functionality for each field? Do we? Then let's create getters and/or setters for the fields
we need the functionality, leaving others alone. It's enough to create class properties corresponding to each field
and checking in __get()/__set() methods if they exist in the class. For getters/setters as getXXXX() and setXXXX()
we/you can use __call() magic as well.

I got this same error:

And now...on top of all that...I'm stuck because the load.sqlite.php script won't define the APPLICATION_PATH and so the script can't find the application.ini

It is because the script folder for load.sqlite.php, schema.sqlite.sql and data.sqlite.sql should be in the same folder as:

"application data docs library public scripts tests"
In indexAction() method of IndexController I have called the method of model which returns the list of employees(employeeList) from database.And then add this this employeeList to $view and then call $view->render('index.phtml') and index .phtml shows the employeeList.Now I want to start the execution from indexAction() method.But how to do this?In request parameter the controller will be Index and action will be index.So please help me in resolving this issue.What should be url as the request in browser??Thanks in advance..
a really awful tutorial, seriously.
Poor news - Syria's 'mutilation mystery' increases...
nginx users this is my conf for handling the rewrites


server {
        listen 80;
        server_name vac.local;
    access_log /srv/projects/php/vac.local.access.log;
    error_log /srv/projects/php/vac.local.error.log;

 
    root   /srv/projects/php/vac/public;

        location / {
                index index.php;
        }
 
        # serve static files directly
        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt)$ {
            access_log        off;
            expires           30d;
        }

    location ~ \.htaccess {
        deny all;
    }

    if (!-e $request_filename) {
        rewrite ^.*$ /index.php last;
    }
 
        location ~ \.php$ {
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME /srv/projects/php/vac/public$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_script_name;
                include /etc/nginx/conf/fastcgi_params;
        }
}
=========== Best Practice for Mysql here ============
==Step 1: add adapter
zf configure db-adapter 'adapter=PDO_MYSQL&dbname=guestbookdb' production
zf configure db-adapter 'adapter=PDO_MYSQL&dbname=guestbookdb_test' testing
zf configure db-adapter 'adapter=PDO_MYSQL&dbname=guestbookdb_dev' development

==Step2: edit sql, create schema & data
1)
mkdir scripts
2)
vi scripts/schema.mysql.sql
DROP DATABASE IF EXISTS guestbookdb;
CREATE DATABASE guestbookdb;
USE guestbookdb;

DROP TABLE IF EXISTS guestbook;

SET @saved_cs_client = @@character_set_client;
SET character_set_client = 'utf8';
SET character_set_connection= 'utf8';
SET character_set_results='utf8';
CREATE TABLE guestbook (
id int NOT NULL AUTO_INCREMENT,
email varchar(32) NOT NULL DEFAULT 'noemail@test.com',
comment TEXT NULL,
created DATETIME NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE INDEX id ON guestbook(id);

3)
vi scripts/data.mysql.sql
USE guestbookdb;

INSERT INTO guestbook (email, comment) VALUES
('ralph.schindler@zend.com',
'Hello! Hope you enjoy this sample zf application!');
INSERT INTO guestbook (email, comment) VALUES
('foo@bar.com',
'Baz baz baz, baz baz Baz baz baz - baz baz baz.');

4) execute:
mysql -uroot -p < scripts/schema.mysql.sql
mysql -uroot -p < scripts/data.mysql.sql

==Step3: just as standard steps to create following
zf create db-table Guestbook guestbook
zf create model GuestbookMapper
zf create model Guestbook
zf create controller Guestbook
add following configs to application/configs/application.ini at each section

resources.db.params.host = "localhost"
resources.db.params.username = "root"
resources.db.params.password = ""


=========nginx config=========
server {
listen 8000;
server_name quickstart.local;

location / {
root /home/thes/www/app/quick2/public;
index index.php;

if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
}

location ~ \.php$ {
root /home/thes/www/app/quick2/public;
fastcgi_connect_timeout 600;
fastcgi_read_timeout 600;
fastcgi_send_timeout 600;
fastcgi_buffer_size 4k;

fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/thes/www/app/quick2/public/$fastcgi_script_name;
fastcgi_param APPLICATION_ENV development;
#fastcgi_param include_path /home/thes/www/app/quickstart/library/Zend;
include fastcgi_params;
}

}


nohup /usr/local/bin/php-cgi -b localhost:9000 &
<b>Dear ' "zf configure db-adapter" ' users,</b>
for windows the right usage is as follows (you have to change the order of the quotation marks):

zf configure db-adapter "adapter=PDO_SQLITE&dbname=APPLICATION_PATH '/../data/db/guestbook-dev.db' " development

Best regards
<b>Axel Arnold Bangert</b>
Wolfstrasse 2
52134 Herzogenrath, 14.01.2012


Dear users,
in the above script data.sqllite is a syntax error at the end of line 8 (missing quotation mark and missing komma!

Best regards
Axel Arnold Bangert
Wolfstrasse 2
52134 Herzogenrath, 14.01.2012


INSERT INTO guestbook (email, comment, created) VALUES
('ralph.schindler@zend.com',
'Hallo! Hoffentlich geniesst Ihr dieses Beispiel einer ZF Anwendung',
DATETIME('NOW'));
I agree with the others. This tut is horrible and generally useless to ZF beginners. I'm trying to follow these general guidelines but with a MySQL database and it's not working. The Zend Framework team really needs to update this documentation to include a real-world MySQL example.
In it something is also to me it appears it truly is excellent idea. I agree with you.
Why don't use the follow code in order to avoid writing a lot of getter/setter method?


    public function __set($name, $value)
    {
        $method = 'set' . $name;
        if (('mapper' == $name) || !method_exists($this, $method)) {
            if(array_key_exists('_'.$name, get_object_vars($this))){
                $this->$name = $value;
                return $value;
            }
                       
            throw new Exception('Invalid entity property');
        }
        $this->$method($value);
    }
 
    public function __get($name)
    {
        $method = 'get' . $name;
        if (('mapper' == $name) || !method_exists($this, $method)) {
            if(array_key_exists($name, get_object_vars($this))){
                return $this->$name;
            }           
            
            throw new Exception('Invalid entity property');            
        }
        return $this->$method();
    }
 
    public function setOptions(array $options)
    {
        $methods = get_class_methods($this);
        foreach ($options as $key => $value) {
            echo $key;            
            $method = 'set' . ucfirst($key);            
            if (in_array($method, $methods)) {
                $this->$method($value);                
            }elseif(array_key_exists('_'.$key, get_object_vars($this))){
                $this->$key = $value;                
            }else{
                throw new Exception('Invalid entity property');
            }        
        }
        return $this;
    }
@ Andrzej:
- First, proper IDEs come with getter/setter generation build in. So no need to write them!
- I prefer if my IDE can hint me about what properties i can get/set, in other words, hint me what methods i can use on a certain object. No way an IDE can still hint you with above code.
- Your code allows access to all properties. In many, many use-cases there's properties you dont want other code to be able to access.
- .... plenty of more reasons
FYI:
the commands executed on command-line assume this kind of folder tree (when followed from the start of the guide):

- quickstart/layouts/scripts/ (including load.sqlite.php and other .sql files) should be located in the quickstart directory quickstart/scripts/ (its obvious because layouts is all about layouts). So I guess this is also wrong in the application/configs/application.ini file:
...
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"
...

- also data/db/ should be located in the quickstart directory quickstart/data/db

This solved the problem with:
% php scripts/load.sqlite.php --withdata
... and created sqlite database (for sqlite database you have to enable sqlite in the php.ini file).

This documentation is really bad and complicated which also makes the use of Zend Framework difficult. I didn't even bother to follow up to the end of this manual. It is reasonable to use only some parts of the framework and make some customised MVC architecture of your own. There are alot better and simpler explanations how to use Zend Framework out there, then it is provided in here.

Cheers
Hello guys, I found this tutorial remake for MySQL:
http://www.webpixel.gr/blog/zend-quickstart-tutorial
php scripts/load.sqlite.php --withdata
this command is totaly ignored by my windows... normal ?
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam dictum nulla ac erat auctor vel lobortis justo pretium. Nam ligula magna, malesuada non gravida quis, luctus et nisi. Integer non neque arcu, sed porta elit. Maecenas sollicitudin vehicula sapien vel condimentum. In hac habitasse platea dictumst. <a href=http://losvazquezsounds.org/>los vazquez sounds</a>
Hi guys,

I Have a problem with db scripts
my data file are in quickstart directory, i have check thausend time all my file but i have always this error :

command : php scripts/load.sqlite.php

' > Writing blabla:
AN ERROR HAS OCCURED
SQLSTATE[HY000]: general error: 1 near "'< CREATE": syntax error

Why, i check all my file no error to the tuto ?
My 3 files in scripts :
directory
quickstart -> scripts

data.sqlite.sql

INSERT INTO guestbook (email, comment, created) VALUES
('ralph.schindler@zend.com',
'Hello! Hope you enjoy this sample zf application!',
DATETIME('NOW'));
INSERT INTO guestbook (email, comment, created) VALUES
('foo@bar.com',
'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
DATETIME('NOW'));

schema.sqlite.sql

CREATE TABLE guestbook (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
comment TEXT NULL,
created DATETIME NOT NULL
);

load.sqlite.php

<?php
/**
* Script pour créer et charger la base
*/

// Initialise le chemin vers l'application et l'autoload
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
set_include_path(implode(PATH_SEPARATOR, array(
APPLICATION_PATH . '/../library',
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();

// Definit des options CLI
$getopt = new Zend_Console_Getopt(array(
'withdata|w' => 'Load database with sample data',
'env|e-s' => 'Application environment for which to create database (defaults to development)',
'help|h' => 'Help -- usage message',
));
try {
$getopt->parse();
} catch (Zend_Console_Getopt_Exception $e) {
// Mauvaises options passées: afficher l'aide
echo $e->getUsageMessage();
return false;
}

// Si l'aid eest demandée, l'afficher
if ($getopt->getOption('h')) {
echo $getopt->getUsageMessage();
return true;
}

// Initialise des valeurs selon la présence ou absence d'options CLI
$withData = $getopt->getOption('w');
$env = $getopt->getOption('e');
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (null === $env) ? 'development' : $env);

// Initialise Zend_Application
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);

// Initialise et récupère la ressoucre DB
$bootstrap = $application->getBootstrap();
$bootstrap->bootstrap('db');
$dbAdapter = $bootstrap->getResource('db');

// Informons l'utilisateur de ce qui se passe (nous créons une base de données
// ici)
if ('testing' != APPLICATION_ENV) {
echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;
for ($x = 5; $x > 0; $x--) {
echo $x . "\r"; sleep(1);
}
}

// Vérifions si un fichier pour la base existe déja
$options = $bootstrap->getOption('resources');
$dbFile = $options['db']['params']['dbname'];
if (file_exists($dbFile)) {
unlink($dbFile);
}

// Chargement du fichier de la base de données.
try {
$schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
// utilise la connexion directement pour charger le sql
$dbAdapter->getConnection()->exec($schemaSql);
chmod($dbFile, 0666);

if ('testing' != APPLICATION_ENV) {
echo PHP_EOL;
echo 'Database Created';
echo PHP_EOL;
}

if ($withData) {
$dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
// utilise la connexion directement pour charger le sql
$dbAdapter->getConnection()->exec($dataSql);
if ('testing' != APPLICATION_ENV) {
echo 'Data Loaded.';
echo PHP_EOL;
}
}

} catch (Exception $e) {
echo 'AN ERROR HAS OCCURED:' . PHP_EOL;
echo $e->getMessage() . PHP_EOL;
return false;
}

// Ce script sera lancé depuis la ligne de commandes
return true;
?>

lo



CREATE INDEX "id" ON "guestbook" ("id");
(Now browse to "http://localhost/guestbook") didn't work for me.
I had to browse to http://quickstart.local/index.php/guestbook.
I had troubles displaying the guestbook entries using the given code:

Guestbook Entries: <br />
<dl>
<?php foreach ($this->entries as $entry): ?>
<dt><?php echo $this->escape($entry->email) ?></dt>
<dd><?php echo $this->escape($entry->comment) ?></dd>
<?php endforeach ?>
</dl>

To fix it, I had to remove $this->escape() and use the Guestbook getter on comment and email. It now looks like:

Guestbook Entries: <br />
<dl>
<?php foreach ($this->entries as $entry): ?>
<dt><?php echo $entry->getEmail(); ?></dt>
<dd><?php echo $entry->getComment(); ?></dd>
<?php endforeach ?>
</dl>

I don't know is it's a secure way of doing it (removing the escape() doesn't look like a good idea) but it's the only way I found to make the entries show up.
Hope this helps.

+ Add A Comment

Please do not report issues via comments; use the ZF Issue Tracker.

If you have a JIRA/Crowd account, we suggest you login first before commenting.

  • BBCode is allowed in the comment markup

  • Select a Version

    Languages Available

    Components

    Search the Manual