|
|
@@ -0,0 +1,753 @@
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<!-- EN-Revision: 22312 -->
|
|
|
+<!-- Reviewed: no -->
|
|
|
+<sect1 id="learning.quickstart.create-model">
|
|
|
+ <title>Créer un modèle et une table en base de données</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Avant de démarrer, considérons ceci: où vont se trouver ces classes et comment les retrouver?
|
|
|
+ Le projet par défaut que nous avons conçu instancie un autoloader. Nous pouvons lui attacher
|
|
|
+ d'autres autoloaders pour qu'il puisse trouver des classes différentes. Typiquement nous
|
|
|
+ voulons que nos classes MVC soient groupées sous une même arborescence -- dans ce cas,
|
|
|
+ <filename>application/</filename> -- et nous utiliserons un préfixe commun.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ <classname>Zend_Controller_Front</classname> a une notion de "modules", qui sont des
|
|
|
+ mini-applications individuelles. Les modules reflètent la structure de répertoires que la
|
|
|
+ commande <command>zf</command> crée sous <filename>application/</filename>, et toutes les
|
|
|
+ classes à l'intérieur sont supposées commencer par un préfixe étant le nom du module.
|
|
|
+ <filename>application/</filename> est lui-même un module -- le module "default" ou
|
|
|
+ "application". Ainsi, nous allons vouloir configurer un autoload pour les ressources sous
|
|
|
+ ce dossier.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ <classname>Zend_Application_Module_Autoloader</classname> propose la fonctionnalité nécessaire
|
|
|
+ à la correspondance entre les ressources d'un module et ses dossiers, il propose pour cela
|
|
|
+ un mécanisme de nommage standard. Une instance de la classe est créee par défaut pendant
|
|
|
+ l'initialisation de l'objet de bootstrap et utilisera le préfixe de module "Application".
|
|
|
+ De ce fait, nos classes de modèles, formulaires, et tables commenceront toutes par le préfixe
|
|
|
+ de classe "Application_".
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Maintenant voyons de quoi est fait un livre d'or. Typiquement il existe simplement une liste
|
|
|
+ d'entrées avec un <emphasis>commentaire</emphasis>, <emphasis>timestamp</emphasis>, et souvent
|
|
|
+ une <emphasis>adresse email</emphasis>. En supposant que nous stockons cela dans une base de
|
|
|
+ données, nous aurons aussi besoin d'un <emphasis>identifiant unique</emphasis> pour chaque
|
|
|
+ entrée. Nous voudrons aussi sauvegarder une entrée, récupérer une entrée individuelle ou encore
|
|
|
+ récupérer toutes les entrées. De ce fait, l'<acronym>API</acronym> du modèle d'un simple livre
|
|
|
+ d'or ressemblerait à ceci:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// application/models/Guestbook.php
|
|
|
+
|
|
|
+class Application_Model_Guestbook
|
|
|
+{
|
|
|
+ protected $_comment;
|
|
|
+ protected $_created;
|
|
|
+ protected $_email;
|
|
|
+ protected $_id;
|
|
|
+
|
|
|
+ public function __set($name, $value);
|
|
|
+ public function __get($name);
|
|
|
+
|
|
|
+ public function setComment($text);
|
|
|
+ public function getComment();
|
|
|
+
|
|
|
+ public function setEmail($email);
|
|
|
+ public function getEmail();
|
|
|
+
|
|
|
+ public function setCreated($ts);
|
|
|
+ public function getCreated();
|
|
|
+
|
|
|
+ public function setId($id);
|
|
|
+ public function getId();
|
|
|
+}
|
|
|
+
|
|
|
+class Application_Model_GuestbookMapper
|
|
|
+{
|
|
|
+ public function save(Application_Model_Guestbook $guestbook);
|
|
|
+ public function find($id);
|
|
|
+ public function fetchAll();
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ <methodname>__get()</methodname> et <methodname>__set()</methodname> nous simpliferons l'accès
|
|
|
+ aux attributs et proxieront vers les autres getters et setters. Ils nous permettront de même
|
|
|
+ de nous assurer que seuls les attributs que nous avons définis seront accessibles dans l'objet.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ <methodname>find()</methodname> et <methodname>fetchAll()</methodname> permettent de récupérer
|
|
|
+ une seule entrée ou toutes les entrées alors que <methodname>save()</methodname> offrira la
|
|
|
+ possibilité de stocker une entrée dans le support de stockage.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Maintenant à partir de là, nous pouvons commecer à penser en terme de base de données.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Nous devons d'abord intialiser une ressource <classname>Db</classname>. Comme pour les
|
|
|
+ ressources <classname>Layout</classname> et <classname>View</classname>, nous pouvons utiliser
|
|
|
+ de la configuration pour <classname>Db</classname>. Cela est possible au moyen de la commande
|
|
|
+ <command>zf configure db-adapter</command>:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="shell"><![CDATA[
|
|
|
+% zf configure db-adapter \
|
|
|
+> 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
|
|
|
+> production
|
|
|
+A db configuration for the production has been written to the application config file.
|
|
|
+
|
|
|
+% zf configure db-adapter \
|
|
|
+> 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \
|
|
|
+> testing
|
|
|
+A db configuration for the production has been written to the application config file.
|
|
|
+
|
|
|
+% zf configure db-adapter \
|
|
|
+> 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \
|
|
|
+> development
|
|
|
+A db configuration for the production has been written to the application config file.
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Editez maintenant le fichier <filename>application/configs/application.ini</filename>, vous
|
|
|
+ verrez que les lignes suivantes ont été ajoutées dans les sections appropriées:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="ini"><![CDATA[
|
|
|
+; application/configs/application.ini
|
|
|
+
|
|
|
+[production]
|
|
|
+; ...
|
|
|
+resources.db.adapter = "PDO_SQLITE"
|
|
|
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
|
|
|
+
|
|
|
+[testing : production]
|
|
|
+; ...
|
|
|
+resources.db.adapter = "PDO_SQLITE"
|
|
|
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
|
|
|
+
|
|
|
+[development : production]
|
|
|
+; ...
|
|
|
+resources.db.adapter = "PDO_SQLITE"
|
|
|
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Votre fichier de configuration final devrait ressembler à ceci:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="ini"><![CDATA[
|
|
|
+; application/configs/application.ini
|
|
|
+
|
|
|
+[production]
|
|
|
+phpSettings.display_startup_errors = 0
|
|
|
+phpSettings.display_errors = 0
|
|
|
+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.db.adapter = "PDO_SQLITE"
|
|
|
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Notez que la/les base(s) de données seront stockées sous <filename>data/db/</filename>. Créez ces dossiers
|
|
|
+ et affectez leur les bons droits. Sur les systèmes Unix utilisez:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="shell"><![CDATA[
|
|
|
+% mkdir -p data/db; chmod -R a+rwX data
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Sur Windows, vous devrez créer le dossier avec l'explorateur et lui donner les bonnes permissions pour que
|
|
|
+ tout le monde puisse y écrire.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Dès lors, nous possédons une connexion à une base de données, dans notre cas il s'agit de Sqlite et la base
|
|
|
+ est placée sous le dossier <filename>application/data/</filename>. Créons maintenant une table pour
|
|
|
+ stocker nos entrées de livre d'or.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="sql"><![CDATA[
|
|
|
+-- scripts/schema.sqlite.sql
|
|
|
+--
|
|
|
+-- You will need load your database schema with this 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
|
|
|
+);
|
|
|
+
|
|
|
+CREATE INDEX "id" ON "guestbook" ("id");
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Puis pour ne pas travailler dans le vide, créons quelques enregistrements de départ.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="sql"><![CDATA[
|
|
|
+-- scripts/data.sqlite.sql
|
|
|
+--
|
|
|
+-- You can begin populating the database with the following SQL statements.
|
|
|
+
|
|
|
+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'));
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Maintenant que nous avons la définition de la base de données ainsi que des données, créons un
|
|
|
+ script qui pourra être lancé pour entièrement initialiser la base de données de manière
|
|
|
+ autonomme. Bien sûr cela ne sera pas nécessaire en production. Créez le script
|
|
|
+ <filename>scripts/load.sqlite.php</filename> avec le contenu suivant:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// scripts/load.sqlite.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;
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Exécutons ce script. Depuis un terminal ou un invite DOS, effectuez:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="shell"><![CDATA[
|
|
|
+% php scripts/load.sqlite.php --withdata
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Vous devriez voir ceci:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="text"><![CDATA[
|
|
|
+path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata
|
|
|
+Writing Database Guestbook in (control-c to cancel):
|
|
|
+1
|
|
|
+Database Created
|
|
|
+Data Loaded.
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Nous avons maintenant une base de données et une table pour notre application de livre d'or.
|
|
|
+ Les prochaines étapes seront de créer le code applicatif. Ceci incluera une source de données
|
|
|
+ (dans notre cas nous utiliserons <classname>Zend_Db_Table</classname>), un datamapper pour
|
|
|
+ connecter cette source à notre modèle et enfin un contrôleur pour intéragir avec le modèle
|
|
|
+ et afficher du contenu divers.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Nous allons utiliser un <ulink url="http://martinfowler.com/eaaCatalog/tableDataGateway.html">Table
|
|
|
+ Data Gateway</ulink> pour se connecter à notre source de données; <classname>Zend_Db_Table</classname>
|
|
|
+ propose cette fonctionnalité. Créons les classes basées sur <classname>Zend_Db_Table</classname>.
|
|
|
+ Comme nous avons opéré pour les layouts ou la base, nous pouvons utiliser la commande
|
|
|
+ <command>zf</command> pour nous aider, avec la commande complète
|
|
|
+ <command>create db-table</command>. Celle-ci prend deux arguments au minimum, le nom de la classe à
|
|
|
+ créer et la table qui y fera référence.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="shell"><![CDATA[
|
|
|
+% zf create db-table Guestbook guestbook
|
|
|
+Creating a DbTable at application/models/DbTable/Guestbook.php
|
|
|
+Updating project profile 'zfproject.xml'
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ En regardant l'orborescence du projet, un nouveau dossier
|
|
|
+ <filename>application/models/DbTable/</filename> a été crée contenant le fichier
|
|
|
+ <filename>Guestbook.php</filename>. Si vous ouvrez ce fichier, vous y verrez le contenu suivant:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// application/models/DbTable/Guestbook.php
|
|
|
+
|
|
|
+/**
|
|
|
+ * This is the DbTable class for the guestbook table.
|
|
|
+ */
|
|
|
+class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
|
|
|
+{
|
|
|
+ /** Table name */
|
|
|
+ protected $_name = 'guestbook';
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Notez le préfixe de classe: <classname>Application_Model_DbTable</classname>. Le premier segment
|
|
|
+ est "Application", le nom du module, puis vient le nom du composant "Model_DbTable" qui est lié
|
|
|
+ au dossier <filename>models/DbTable/</filename> du module.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Pour étendre <classname>Zend_Db_Table</classname>, seuls un nom de table et éventuellement un
|
|
|
+ nom de clé primaire (si ce n'est pas "id") sont nécessaires.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Créons maintenant un <ulink url="http://martinfowler.com/eaaCatalog/dataMapper.html">Data
|
|
|
+ Mapper</ulink>. Un <emphasis>Data Mapper</emphasis> fait correspondre un objet métier à la
|
|
|
+ base de données. Dans notre cas <classname>Application_Model_Guestbook</classname> vers la
|
|
|
+ source de données <classname>Application_Model_DbTable_Guestbook</classname>. Une
|
|
|
+ <acronym>API</acronym> typique pour un data mapper est:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// application/models/GuestbookMapper.php
|
|
|
+
|
|
|
+class Application_Model_GuestbookMapper
|
|
|
+{
|
|
|
+ public function save($model);
|
|
|
+ public function find($id, $model);
|
|
|
+ public function fetchAll();
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ En plus de ces méthodes nous allons ajouter des méthodes pour affecter/récupérer l'objet
|
|
|
+ Table Data Gateway. Pour créer la classe initiale, utilsez l'outil CLI
|
|
|
+ <command>zf</command>:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="shell"><![CDATA[
|
|
|
+% zf create model GuestbookMapper
|
|
|
+Creating a model at application/models/GuestbookMapper.php
|
|
|
+Updating project profile '.zfproject.xml'
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Maintenant, éditez la classe <classname>Application_Model_GuestbookMapper</classname> dans
|
|
|
+ <filename>application/models/GuestbookMapper.php</filename> pour y voir ceci:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// application/models/GuestbookMapper.php
|
|
|
+
|
|
|
+class Application_Model_GuestbookMapper
|
|
|
+{
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getDbTable()
|
|
|
+ {
|
|
|
+ if (null === $this->_dbTable) {
|
|
|
+ $this->setDbTable('Application_Model_DbTable_Guestbook');
|
|
|
+ }
|
|
|
+ return $this->_dbTable;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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']);
|
|
|
+ $this->getDbTable()->insert($data);
|
|
|
+ } else {
|
|
|
+ $this->getDbTable()->update($data, array('id = ?' => $id));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function fetchAll()
|
|
|
+ {
|
|
|
+ $resultSet = $this->getDbTable()->fetchAll();
|
|
|
+ $entries = array();
|
|
|
+ foreach ($resultSet as $row) {
|
|
|
+ $entry = new Application_Model_Guestbook();
|
|
|
+ $entry->setId($row->id)
|
|
|
+ ->setEmail($row->email)
|
|
|
+ ->setComment($row->comment)
|
|
|
+ ->setCreated($row->created);
|
|
|
+ $entries[] = $entry;
|
|
|
+ }
|
|
|
+ return $entries;
|
|
|
+ }
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Maintenant il faut créer la classe de modèle. Une fois de plus, nous utiliserons la commande
|
|
|
+ <command>zf create model</command>:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="shell"><![CDATA[
|
|
|
+% zf create model Guestbook
|
|
|
+Creating a model at application/models/Guestbook.php
|
|
|
+Updating project profile '.zfproject.xml'
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Nous allons modifier cette classe <acronym>PHP</acronym> vide pour simplifier le remplissage
|
|
|
+ du modèle via un tableau dans le constructeur ou une méthode
|
|
|
+ <methodname>setOptions()</methodname>. Le code final de la classe de modèle stockée dans
|
|
|
+ <filename>application/models/Guestbook.php</filename> devrait ressembler à ceci:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// application/models/Guestbook.php
|
|
|
+
|
|
|
+class Application_Model_Guestbook
|
|
|
+{
|
|
|
+ protected $_comment;
|
|
|
+ protected $_created;
|
|
|
+ protected $_email;
|
|
|
+ protected $_id;
|
|
|
+
|
|
|
+ public function __construct(array $options = null)
|
|
|
+ {
|
|
|
+ if (is_array($options)) {
|
|
|
+ $this->setOptions($options);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function __set($name, $value)
|
|
|
+ {
|
|
|
+ $method = 'set' . $name;
|
|
|
+ if (('mapper' == $name) || !method_exists($this, $method)) {
|
|
|
+ throw new Exception('Invalid guestbook property');
|
|
|
+ }
|
|
|
+ $this->$method($value);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function __get($name)
|
|
|
+ {
|
|
|
+ $method = 'get' . $name;
|
|
|
+ if (('mapper' == $name) || !method_exists($this, $method)) {
|
|
|
+ throw new Exception('Invalid guestbook property');
|
|
|
+ }
|
|
|
+ return $this->$method();
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setComment($text)
|
|
|
+ {
|
|
|
+ $this->_comment = (string) $text;
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getComment()
|
|
|
+ {
|
|
|
+ return $this->_comment;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setEmail($email)
|
|
|
+ {
|
|
|
+ $this->_email = (string) $email;
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getEmail()
|
|
|
+ {
|
|
|
+ return $this->_email;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setCreated($ts)
|
|
|
+ {
|
|
|
+ $this->_created = $ts;
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getCreated()
|
|
|
+ {
|
|
|
+ return $this->_created;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setId($id)
|
|
|
+ {
|
|
|
+ $this->_id = (int) $id;
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getId()
|
|
|
+ {
|
|
|
+ return $this->_id;
|
|
|
+ }
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Enfin, pour connecter tous ces éléments ensemble, créons un contrôleur qui listera les entrées
|
|
|
+ de la base de données.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Pour créer le nouveau contrôleur, utilisez la commande <command>zf create controller</command>:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="shell"><![CDATA[
|
|
|
+% zf create controller Guestbook
|
|
|
+Creating a controller at
|
|
|
+ application/controllers/GuestbookController.php
|
|
|
+Creating an index action method in controller Guestbook
|
|
|
+Creating a view script for the index action method at
|
|
|
+ application/views/scripts/guestbook/index.phtml
|
|
|
+Creating a controller test file at
|
|
|
+ tests/application/controllers/GuestbookControllerTest.php
|
|
|
+Updating project profile '.zfproject.xml'
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Ceci va créer <classname>GuestbookController</classname> dans
|
|
|
+ <filename>application/controllers/GuestbookController.php</filename>, avec une seule action
|
|
|
+ <methodname>indexAction()</methodname>. Un script de vue sera aussi crée pour ce contrôleur,
|
|
|
+ il sera logé dans <filename>application/views/scripts/guestbook/</filename>, avec une vue
|
|
|
+ pour l'action index.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Nous allons utiliser l'action "index" pour lister toutes les entrées du livre d'or.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Un aterrissage sur <methodname>indexAction()</methodname> devra lister toutes les
|
|
|
+ entrées du livre d'or. Ceci ressemblera à ce qui suit:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+// application/controllers/GuestbookController.php
|
|
|
+
|
|
|
+class GuestbookController extends Zend_Controller_Action
|
|
|
+{
|
|
|
+ public function indexAction()
|
|
|
+ {
|
|
|
+ $guestbook = new Application_Model_GuestbookMapper();
|
|
|
+ $this->view->entries = $guestbook->fetchAll();
|
|
|
+ }
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Et bien sûr un script de vue sera nécessaire. Editez
|
|
|
+ <filename>application/views/scripts/guestbook/index.phtml</filename> pour y
|
|
|
+ inclure ceci:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+<!-- application/views/scripts/guestbook/index.phtml -->
|
|
|
+
|
|
|
+<p><a href="<?php echo $this->url(
|
|
|
+ array(
|
|
|
+ 'controller' => 'guestbook',
|
|
|
+ 'action' => 'sign'
|
|
|
+ ),
|
|
|
+ 'default',
|
|
|
+ true) ?>">Sign Our Guestbook</a></p>
|
|
|
+
|
|
|
+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>
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <note>
|
|
|
+ <title>Checkpoint</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Naviguez maintenant vers "http://localhost/guestbook". Vous devriez voir ceci
|
|
|
+ apparaitre dans votre navigateur:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ <inlinegraphic width="525" scale="100" align="center" valign="middle"
|
|
|
+ fileref="figures/learning.quickstart.create-model.png" format="PNG" />
|
|
|
+ </para>
|
|
|
+ </note>
|
|
|
+
|
|
|
+ <note>
|
|
|
+ <title>Utiliser le script de chargement des données</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Le script de chargement des données montré dans la section en question
|
|
|
+ (<filename>scripts/load.sqlite.php</filename>) peut être utilisé pour créer une base
|
|
|
+ de données pour chaque environnement défini et la remplir de données d'exemple. En
|
|
|
+ interne, il utilise <classname>Zend_Console_Getopt</classname>, qui permet de préciser
|
|
|
+ des options à la commande. Si vous passez "-h" ou "--help", toutes les options
|
|
|
+ disponibles seront affichées:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting language="php"><![CDATA[
|
|
|
+Usage: load.sqlite.php [ options ]
|
|
|
+--withdata|-w Load database with sample data
|
|
|
+--env|-e [ ] Application environment for which to create database
|
|
|
+ (defaults to development)
|
|
|
+--help|-h Help -- usage message)]]
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ L'option "-e" permet de préciser la valeur de la constante
|
|
|
+ <constant>APPLICATION_ENV</constant> -- ce qui en effet permet de créer une base de
|
|
|
+ données SQLite pour chaque environnement défini. N'oubliez pas l'envrionnement
|
|
|
+ lorsque vous utilisez ce script.
|
|
|
+ </para>
|
|
|
+ </note>
|
|
|
+</sect1>
|