1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- EN-Revision: 21829 -->
4 <sect1 id="zend.db.table">
5 <title>Zend_Db_Table</title>
7 <sect2 id="zend.db.table.introduction">
8 <title>Introduction</title>
11 La classe <classname>Zend_Db_Table</classname> est une interface orientée objet
12 vers les tables d'une base de données. Elle fournit des méthodes pour la gestion de la
13 plupart des opérations concernant une table. Bien entendu, vous pouvez étendre la classe
14 de base pour ajouter une logique personnalisée.
18 La solution que représente <classname>Zend_Db_Table</classname> est basée sur le
19 motif de conception <ulink
20 url="http://www.martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data
21 Gateway</ulink>. Cette solution inclut aussi une classe implémentant le motif <ulink
22 url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data
27 <sect2 id="zend.db.table.defining">
28 <title>Définir une classe de Table</title>
31 Pour chaque table de la base de données envers laquelle vous souhaitez un accès,
32 définissez une classe étendant <classname>Zend_Db_Table_Abstract</classname>.
35 <sect3 id="zend.db.table.defining.table-schema">
36 <title>Définir le nom de la table, et de la base de données</title>
39 Déclarez le nom de la table pour laquelle la classe va agir, en utilisant la
40 propriété protégée <varname>$_name</varname>. C'est une chaîne, elle doit contenir le nom
41 de la table tel qu'il apparaît dans la base de données.
44 <example id="zend.db.table.defining.table-schema.example1">
45 <title>Déclarer une classe de Table avec un nom de table spécifique</title>
47 <programlisting language="php"><![CDATA[
48 class Bugs extends Zend_Db_Table_Abstract
50 protected $_name = 'bugs';
56 Si vous ne spécifiez pas le nom de la table, le nom de la classe sera alors
57 utilisé comme nom de table par défaut.
60 <example id="zend.db.table.defining.table-schema.example">
61 <title>Déclarer une classe de Table sans nom de table spécifique</title>
63 <programlisting language="php"><![CDATA[
64 class bugs extends Zend_Db_Table_Abstract
66 // le nom de la table est ici supposé être le nom de la classe
72 Vous pouvez aussi déclarer le nom de la base de données contenant la table,
73 toujours au moyen d'une propriété protégée de la classe :
74 <varname>$_schema</varname>, ou avec le nom de la base précédant le nom de la table dans
75 la propriété <varname>$_name</varname>. Si vous choisissez de définir le nom de la base de
76 données dans la propriété <varname>$_name</varname>, alors ce choix sera prioritaire sur
77 celui utilisant <varname>$_schema</varname>.
80 <example id="zend.db.table.defining.table-schema.example3">
81 <title>Déclarer une classe de Table avec un nom de base de données</title>
83 <programlisting language="php"><![CDATA[
84 // Première alternative :
85 class Bugs extends Zend_Db_Table_Abstract
87 protected $_schema = 'bug_db';
88 protected $_name = 'bugs';
91 // Seconde alternative :
92 class Bugs extends Zend_Db_Table_Abstract
94 protected $_name = 'bug_db.bugs';
97 // Si le nom de la base est spécifiée dans $_name ET $_schema,
98 // alors c'est celui spécifié dans $_name qui prime :
100 class Bugs extends Zend_Db_Table_Abstract
102 protected $_name = 'bug_db.bugs';
103 protected $_schema = 'ignored';
109 Les noms de la base de données et de la table peuvent aussi être définis via
110 le constructeur de la classe de Table. Ils écrasent alors ceux éventuellement
111 définis dans les propriétés de la classe (avec <varname>$_name</varname> et
112 <varname>$_schema</varname>).
115 <example id="zend.db.table.defining.table-schema.example.constructor">
116 <title>Déclarer les noms de table et base de donnée à l'instanciation</title>
118 <programlisting language="php"><![CDATA[
119 class Bugs extends Zend_Db_Table_Abstract
123 // Première alternative :
125 $tableBugs = new Bugs(array('name' => 'bugs', 'schema' => 'bug_db'));
127 // Seconde alternative :
129 $tableBugs = new Bugs(array('name' => 'bug_db.bugs'));
131 // Si le nom de la base est spécifié dans name ET schema, alors c'est
132 // celui spécifié dans name qui prime :
134 $tableBugs = new Bugs(array('name' => 'bug_db.bugs',
135 'schema' => 'ignored'));
140 Si vous n'indiquez pas de base de données, c'est celle utilisée par
141 l'adaptateur qui sera utilisée.
145 <sect3 id="zend.db.table.defining.primary-key">
146 <title>Définir la clé primaire d'une table</title>
149 Toute table doit posséder une clé primaire.
150 <classname>Zend_Db_Table</classname> ne fonctionne pas avec les tables sans clé
151 primaire. Vous pouvez les déclarer la(les) colonne servant de clé primaire grâce à
152 la propriété protégée de la classe <varname>$_primary</varname>. Celle-ci peut être soit
153 une chaîne, dans le cas d'une clé sur une colonne, ou un tableau de chaînes pour une
154 clé sur plusieurs colonnes (clé primaire composée).
157 <example id="zend.db.table.defining.primary-key.example">
158 <title>Exemple de spécification de la clé primaire</title>
160 <programlisting language="php"><![CDATA[
161 class Bugs extends Zend_Db_Table_Abstract
163 protected $_name = 'bugs';
164 protected $_primary = 'bug_id';
170 Si vous ne spécifiez pas explicitement de clé primaire, alors
171 <classname>Zend_Db_Table_Abstract</classname> va essayer de la trouver lui-même en
172 utilisant les informations renvoyées par <methodname>describeTable()</methodname>.
177 Toute classe de table doit, par un moyen ou un autre, connaître la clé
178 primaire de la table ciblée. Si la clé primaire ne peut être trouvée ( spécifiée
179 dans la classe, ou découverte par <methodname>describeTable()</methodname>), alors la table
180 ne va pas pouvoir être utilisée avec
181 <classname>Zend_Db_Table</classname>.
186 <sect3 id="zend.db.table.defining.setup">
187 <title>Redéfinir les méthodes de configuration de la classe de Table</title>
190 Lorsque vous créez votre instance de classe
191 <classname>Zend_Db_Table</classname>, le constructeur décompose le processus via
192 plusieurs méthodes permettant l'initialisation des métadonnées de la table. Chacune
193 de ces étapes est matérialisée par une méthode de la classe, surchargeable.
194 N'oubliez cependant pas d'appeler la méthode parente respective à la fin de votre
198 <example id="zend.db.table.defining.setup.example">
199 <title>Exemple de redéfinition de la méthode _setupTableName()</title>
201 <programlisting language="php"><![CDATA[
202 class Bugs extends Zend_Db_Table_Abstract
204 protected function _setupTableName()
206 $this->_name = 'bugs';
207 parent::_setupTableName();
213 <para>Les méthodes de configuration que vous pouvez redéfinir sont :</para>
218 <methodname>_setupDatabaseAdapter()</methodname> vérifie si un adaptateur a été
219 passé à la classe, éventuellement en récupère un depuis le registre. En
220 redéfinissant cette méthode, vous pouvez ajouter une source de recherche
227 <methodname>_setupTableName()</methodname> donne le nom de la table par défaut
228 comme étant le nom de la classe. En redéfinissant cette méthode, vous pouvez
229 spécifier le nom de la table avant son intervention.
235 <methodname>_setupMetadata()</methodname> définit le nom de la base de données si
236 le nom de la table est de la forme "base.table"; appelle
237 <methodname>describeTable()</methodname> pour récupérer les méta-données; remplir le
238 tableau <varname>$_cols</varname> avec les noms des colonnes reçus via
239 <methodname>describeTable()</methodname>. La redéfinition de cette méthode permet de
240 spécifier soi-même les noms des colonnes de la table.
246 <methodname>_setupPrimaryKey()</methodname> donne le nom de la clé primaire par
247 défaut en cherchant dans <methodname>describeTable()</methodname>; vérifie que la clé
248 primaire fait bien partie du tableau <varname>$_cols</varname>. En redéfinissant
249 cette méthode, vous pouvez spécifier une clé primaire manuellement.
255 <sect3 id="zend.db.table.initialization">
256 <title>Initialisation de la Table</title>
259 Si lors de la construction de l'objet représentant votre Table, vous avez
260 besoin d'implémenter une logique spécifique, vous devriez utiliser la méthode
261 <methodname>init()</methodname>, qui est appelée juste après le constructeur, donc une fois la
262 table correctement créée.
265 <example id="zend.db.table.defining.init.usage.example">
266 <title>Exemple d'utilisation de la méthode init()</title>
268 <programlisting language="php"><![CDATA[
269 class Bugs extends Zend_Db_Table_Abstract
271 protected $_observer;
273 public function init()
275 $this->_observer = new MyObserverClass();
283 <sect2 id="zend.db.table.constructing">
284 <title>Créer une instance de la classe de Table</title>
287 Avant d'utiliser votre classe de Table, il faut en créer une instance, via son
288 constructeur. Celui-ci accepte un tableau d'options. La plus importante d'entre elles
289 est l'adaptateur de base de données, qui représente la connexion au SGBD. Il y a trois
290 façon de le spécifier :
293 <sect3 id="zend.db.table.constructing.adapter">
294 <title>Spécifier l'adaptateur de base de données</title>
297 La première manière de spécifier l'objet d'adaptateur à la classe de Table,
298 est de le passer dans le tableau d'options, à l'index <code>"db"</code>.
301 <example id="zend.db.table.constructing.adapter.example">
302 <title>Exemple de construction d'un objet Table avec l'objet adaptateur</title>
304 <programlisting language="php"><![CDATA[
305 $db = Zend_Db::factory('PDO_MYSQL', $options);
307 $table = new Bugs(array('db' => $db));
312 <sect3 id="zend.db.table.constructing.default-adapter">
313 <title>Spécifier un adaptateur par défaut</title>
316 La deuxième manière de donner un objet adaptateur à la classe de Table est de
317 le déclarer comme étant l'objet adaptateur par défaut pour toutes les classes de
318 Table. Vous pouvez faire ceci en utilisant la méthode statique
319 <methodname>Zend_Db_Table_Abstract::setDefaultAdapter()</methodname>. Son argument est
320 un objet de type <classname>Zend_Db_Adapter_Abstract</classname>.
323 <example id="zend.db.table.constructing.default-adapter.example">
325 Exemple de construction d'un objet Table en utilisant l'adaptateur par défaut
328 <programlisting language="php"><![CDATA[
329 $db = Zend_Db::factory('PDO_MYSQL', $options);
330 Zend_Db_Table_Abstract::setDefaultAdapter($db);
339 Il peut être intéressant de créer son objet adaptateur de base de données en
340 un lieu approprié, comme le fichier d'amorçage ("bootstrap"), et ensuite de le
341 spécifier comme adaptateur par défaut pour toutes les tables, à travers toute
342 l'application. Attention toutefois, ce procédé fixe un et un seul adaptateur, pour
343 toutes les classes de table (héritant de
344 <classname>Zend_Db_Table_Abstract</classname>).
348 <sect3 id="zend.db.table.constructing.registry">
349 <title>Stocker l'objet adaptateur dans le registre</title>
352 La troisième manière de passer l'objet adaptateur de base de données à votre
353 classe de Table, est de passer une chaîne de caractères dans la clé
354 <code>"db"</code> du tableau de configuration accepté par le constructeur. Cette
355 chaîne représente alors l'index auquel est stocké l'adaptateur, dans le registre
359 <example id="zend.db.table.constructing.registry.example">
360 <title>Exemple de construction de l'objet Table avec le registre</title>
362 <programlisting language="php"><![CDATA[
363 $db = Zend_Db::factory('PDO_MYSQL', $options);
364 Zend_Registry::set('my_db', $db);
368 $table = new Bugs(array('db' => 'my_db'));
373 Cette option est très semblable à celle qui consiste à définir un adaptateur
374 par défaut à toutes les classes. Le registre est en revanche plus flexible, car vous
375 pouvez y stocker plusieurs adaptateurs, correspondants à plusieurs SGBD différents.
376 Changer de SGBD pour ses classes de Table est alors aussi simple que de changer de
382 <sect2 id="zend.db.table.insert">
383 <title>Insérer des enregistrement dans une table</title>
386 Vous pouvez utiliser votre objet de Table pour insérer des données dans la table
387 sur laquelle l'objet se base. Utilisez sa méthode <methodname>insert()</methodname> qui accepte un
388 seul paramètre : c'est un tableau dont les clés sont les noms des colonnes de la
389 table, et les valeurs les valeurs souhaitées pour insertions.
392 <example id="zend.db.table.insert.example">
393 <title>Exemple d'insertion de données dans la table</title>
395 <programlisting language="php"><![CDATA[
399 'created_on' => '2007-03-22',
400 'bug_description' => 'Something wrong',
401 'bug_status' => 'NEW'
404 $table->insert($data);
409 Par défaut les paramètres sont traités comme des valeurs littérales. Si vous
410 souhaitez utiliser une expression <acronym>SQL</acronym> à la place, manipulez un objet
411 <classname>Zend_Db_Expr</classname> plutôt.
414 <example id="zend.db.table.insert.example-expr">
415 <title>Exemple d'insertion d'expressions dans une table</title>
417 <programlisting language="php"><![CDATA[
421 'created_on' => new Zend_Db_Expr('CURDATE()'),
422 'bug_description' => 'Something wrong',
423 'bug_status' => 'NEW'
429 Dans les exemples ci-dessus, il est supposé que la table possède une clé primaire
430 auto-incrémentée. C'est le comportement par défaut que gère
431 <classname>Zend_Db_Table_Abstract</classname>, mais il y a d'autres comportements
432 valides, qui sont détaillés ci-dessous.
435 <sect3 id="zend.db.table.insert.key-auto">
436 <title>Utiliser une table avec une clé primaire auto-incrémentée</title>
439 Une clé primaire auto-incrémentée génère une valeur entière unique si vous
440 omettez la colonne de la clé primaire dans une requête <acronym>SQL</acronym> de type
441 <constant>INSERT</constant>.
445 Dans <classname>Zend_Db_Table_Abstract</classname>, si vous définissez la
446 variable protégée <varname>$_sequence</varname> à un booléen <constant>TRUE</constant> (défaut),
447 alors la classe va supposer que la table qu'elle représente possède une clé primaire
451 <example id="zend.db.table.insert.key-auto.example">
452 <title>Exemple de déclaration d'une clé primaire auto-incrémentée</title>
454 <programlisting language="php"><![CDATA[
455 class Bugs extends Zend_Db_Table_Abstract
457 protected $_name = 'bugs';
459 // Ce comportement est celui par défaut, il est noté ici
460 // uniquement pour l'exemple, mais non necéssaire
461 protected $_sequence = true;
467 MySQL, MSSQL, et SQLite sont des exemples de SGBD supportant les clé primaires
472 PostgreSQL a une propriété <constant>SERIAL</constant> qui définit une séquence
473 automatiquement, basée sur le nom de la table et d'une colonne, et utilise cette
474 séquence pour générer des valeurs de clés pour les nouveaux enregistrements. IBM DB2
475 a une propriété <constant>IDENTITY</constant> qui fonctionne de la même manière. Si vous
476 utilisez ces propriétés d'automatisme, considérez votre classe de Table
477 (<classname>Zend_Db_Table</classname>) comme si elle avait une clé primaire
478 auto-incrémentée. Déclarez ainsi <varname>$_sequence</varname> à <constant>TRUE</constant>.
482 <sect3 id="zend.db.table.insert.key-sequence">
483 <title>Utiliser une Table avec une séquence</title>
486 Une séquence est un objet de base de données qui génère des valeurs uniques
487 pouvant être utilisées comme clés primaires dans une ou plusieurs tables de la base
492 Si vous définissez <varname>$_sequence</varname> avec une chaîne de caractères,
493 <classname>Zend_Db_Table_Abstract</classname> va alors supposer que cette chaîne
494 représente le nom de l'objet de séquence. Elle sera donc utilisée pour générer une
495 valeur lors de requêtes <constant>INSERT</constant> le nécessitant.
498 <example id="zend.db.table.insert.key-sequence.example">
499 <title>Exemple de déclaration d'une séquence dans une classe de Table</title>
501 <programlisting language="php"><![CDATA[
502 class Bugs extends Zend_Db_Table_Abstract
504 protected $_name = 'bugs';
506 protected $_sequence = 'bug_sequence';
512 Oracle, PostgreSQL, et IBM DB2 sont des SGBDs qui supportent les séquences.
516 PostgreSQL et IBM DB2 ont aussi des mécanismes définissant implicitement la
517 séquence et les colonnes associées. Si vous utilisez un de ces procédés, considérez
518 votre classe de table comme ayant une clé primaire auto-incrémentée. N'utilisez la
519 chaîne de la séquence dans $_sequence que si vous voulez explicitement utiliser
520 cette séquence pour générer la valeur suivante de clé.
524 <sect3 id="zend.db.table.insert.key-natural">
525 <title>Utiliser une classe de Table avec une clé naturelle</title>
528 Certaines tables ont des clé naturelles, c'est à dire que vous devez fournir
529 vous même, manuellement, la valeur de la clé concernée. Aucun mécanisme automatique
530 (auto-incrémentation ou séquence) ne le fait pour vous.
534 Si vous utilisez <varname>$_sequence</varname> avec la valeur booléenne
535 <constant>FALSE</constant>, alors <classname>Zend_Db_Table_Abstract</classname> se
536 comportera comme si une clé naturelle est utilisée. Ainsi, lors de l'appel de la
537 méthode <methodname>insert()</methodname>, vous devrez spécifier la valeur de la clé primaire
538 vous même, autrement une <classname>Zend_Db_Table_Exception</classname> sera
542 <example id="zend.db.table.insert.key-natural.example">
543 <title>Exemple de déclaration d'une clé naturelle</title>
545 <programlisting language="php"><![CDATA[
546 class BugStatus extends Zend_Db_Table_Abstract
548 protected $_name = 'bug_status';
550 protected $_sequence = false;
557 Tous les SGBDs gère ce cas. Les tables d'intersection dans les relations
558 de type "plusieurs à plusieurs" sont de bons exemples de clés naturelles,
559 souvent composées d'autres clés étrangères.
565 <sect2 id="zend.db.table.update">
566 <title>Mettre à jour des enregistrements dans une table</title>
569 Vous pouvez mettre à jour des enregistrements de votre table en utilisant la
570 méthode <code>update</code> de votre classe de Table. Elle accepte deux paramètres. Le
571 premier est un tableau associatifs des colonnes concernées, et de leurs valeurs
572 respectives. Le deuxième est une expression <acronym>SQL</acronym> qui sera utiliser comme clause
573 <constant>WHERE</constant> dans la requête <constant>UPDATE</constant>.
576 <example id="zend.db.table.update.example">
577 <title>Exemple de mise à jour d'enregistrements dans une table</title>
579 <programlisting language="php"><![CDATA[
583 'updated_on' => '2007-03-23',
584 'bug_status' => 'FIXED'
587 $where = $table->getAdapter()->quoteInto('bug_id = ?', 1234);
589 $table->update($data, $where);
594 La méthode de la classe de Table <methodname>update()</methodname> est proxiées vers la
595 méthode <link linkend="zend.db.adapter.write.update"><methodname>update()</methodname></link> de
596 l'adaptateur. Le deuxième paramètre peut donc être un tableau d'arguments pour la clause
597 WHERE. Chaque élément du tableau sera joint au suivant avec une opération
598 <constant>AND</constant>.
603 Les valeurs et les identifiants <acronym>SQL</acronym> ne sont pas échappés automatiquement. Si
604 vous voulez échapper des valeurs, vous devrez utiliser <methodname>quote()</methodname>,
605 <methodname>quoteInto()</methodname>, et <methodname>quoteIdentifier()</methodname> de l'adaptateur.
610 <sect2 id="zend.db.table.delete">
611 <title>Supprimer des enregistrements d'une Table</title>
614 Pour effacer des enregistrements de votre table en utilisant sa classe de Table,
615 utilisez sa méthode <methodname>delete()</methodname>. Son seul paramètre est une chaîne ou un
616 tableau définissant la clause <constant>WHERE</constant> à utiliser lors de la requête
617 <constant>DELETE</constant>.
620 <example id="zend.db.table.delete.example">
621 <title>Exemple de suppression d'enregistrements</title>
623 <programlisting language="php"><![CDATA[
626 $where = $table->getAdapter()->quoteInto('bug_id = ?', 1235);
628 $table->delete($where);
633 Cette méthode est proxiée vers <link
634 linkend="zend.db.adapter.write.delete"><methodname>delete()</methodname></link> de l'adaptateur. Si
635 le paramètre est un tableau, chacun des éléments du tableau sera joint au suivant avec
636 l'opération <constant>AND</constant> pour former la clause WHERE.
641 Les valeurs et les identifiants <acronym>SQL</acronym> ne sont pas échappés automatiquement. Si
642 vous voulez échapper des valeurs, vous devrez utiliser <methodname>quote()</methodname>,
643 <methodname>quoteInto()</methodname>, et <methodname>quoteIdentifier()</methodname> de l'adaptateur.
648 <sect2 id="zend.db.table.find">
649 <title>Récupérer des enregistrements par clé primaire</title>
652 Vous pouvez interroger votre table afin de récupérer des enregistrements en
653 spécifiant une ou plusieurs valeurs de clé primaire. La méthode <methodname>find()</methodname>
654 permet ceci, elle prend comme premier paramètre une valeur ou un tableau de valeurs de
658 <example id="zend.db.table.find.example">
659 <title>Exemple de récupération d'enregistrements par clé primaire</title>
661 <programlisting language="php"><![CDATA[
664 // Récupère un enregistrement, mais
665 // retourne un Rowset
666 $rows = $table->find(1234);
668 // Récupère plusieurs enregistrement
669 // retourne un Rowset
670 $rows = $table->find(array(1234, 5678));
675 Si une seule clé est passée en paramètre, la méthode retournera au plus un
676 résultat (car par définition, une clé primaire assure l'unicité d'un enregistrement). Si
677 vous passez plusieurs valeurs de clés, alors la méthode pourra retourner plusieurs
678 enregistrements. Cette méthode pourra aussi retourner zéro enregistrement. Quoiqu'il en
679 soit, l'objet de retour est bien un
680 <classname>Zend_Db_Table_Rowset_Abstract</classname>.
684 Si votre clé primaire est une clé composée de plusieurs colonnes, passez alors les
685 autres valeurs de colonne comme paramètres à la méthode <methodname>find()</methodname>. Il doit y
686 avoir autant de paramètres passés à la méthode, que de colonnes composant la clé.
690 Ainsi, pour trouver plusieurs enregistrements en passant plusieurs valeurs de clés
691 primaires composées, passez autant de tableaux composés, que de colonnes représentant
692 les clés. Les tableaux doivent donc, comporter le même nombre de valeurs. Celles-ci vont
693 ainsi fonctionner par tuples : tous les premiers éléments des tableaux seront
694 évalués pour la première recherche, et chacun représentera une colonne composant la clé
695 primaire. Puis ainsi de suite, jusqu'à la fin des tableaux.
698 <example id="zend.db.table.find.example-compound">
699 <title>Exemple de recherche avec une clé primaire composée</title>
702 L'exemple suivant appelle <methodname>find()</methodname> pour récupérer deux enregistrements en
703 se basant sur une clé à deux colonnes. Le premier enregistrement aura une clé
704 primaire (1234, 'ABC'), et le second une valeur de clé primaire (5678, 'DEF').
707 <programlisting language="php"><![CDATA[
708 class BugsProducts extends Zend_Db_Table_Abstract
710 protected $_name = 'bugs_products';
711 protected $_primary = array('bug_id', 'product_id');
714 $table = new BugsProducts();
716 // Retourne un enregistrement unique, basé sur une clé
717 // primaire à deux colonnes
718 $rows = $table->find(1234, 'ABC');
720 // Retourne deux enregistrements, basés sur une clé
721 // primaire à deux colonnes
722 $rows = $table->find(array(1234, 5678), array('ABC', 'DEF'));
727 <sect2 id="zend.db.table.fetch-all">
728 <title>Requêter pour plusieurs enregistrements</title>
730 <sect3 id="zend.db.table.fetch-all.select">
731 <title>API de l'objet Select</title>
736 L'API pour les opérations de récupération d'enregistrements a été
737 améliorée afin d'autoriser un objet
738 <classname>Zend_Db_Table_Select</classname> à modifier la requête. Les
739 anciens comportements de <methodname>fetchRow()</methodname> et <methodname>fetchAll()</methodname>
740 sont désormais dépréciés, mais toujours fonctionnels à ce jour.
744 Les requêtes suivantes sont sémantiquement identiques et fonctionnent.
745 Il est conseillé cependant d'utiliser l'implémentation avec l'objet
750 <programlisting language="php"><![CDATA[
751 // Récupérer un rowset
752 $rows = $table->fetchAll('bug_status = "NEW"', 'bug_id ASC', 10, 0);
753 $rows = $table->fetchAll($table->select()->where('bug_status = ?', 'NEW')
754 ->order('bug_id ASC')
757 $rows = $table->fetchAll(
759 ->where('bug_status = :status')
760 ->bind(array(':status'=>'NEW')
761 ->order('bug_id ASC')
766 $row = $table->fetchRow('bug_status = "NEW"', 'bug_id ASC');
767 $row = $table->fetchRow($table->select()->where('bug_status = ?', 'NEW')
768 ->order('bug_id ASC'));
770 $row = $table->fetchRow(
772 ->where('bug_status = :status')
773 ->bind(array(':status'=>'NEW')
774 ->order('bug_id ASC')
776 ]]></programlisting></para>
781 L'objet <classname>Zend_Db_Table_Select</classname> est une extension de
782 <classname>Zend_Db_Select</classname> mais qui applique des restrictions
783 particulières à la requête. Les restrictions sont :
789 Vous <emphasis>pouvez</emphasis> utiliser l'objet pour ne sélectionner
790 que certaines colonnes de l'enregistrement à retourner. Ceci est pratique
791 dans le cas où vous n'avez pas besoin spécifiquement de toutes les colonnes
798 Vous <emphasis>pouvez</emphasis> spécifier des colonnes avec des
799 évaluations envers des expressions <acronym>SQL</acronym>. Cependant, l'enregistrement
800 résultant sera alors en mode lecture seule (<property>readOnly</property>)
801 et ne pourra pas être propagé en base de données (<methodname>save()</methodname>). Un
802 appel à <methodname>save()</methodname> lèvera une exception.
808 Vous <emphasis>pouvez</emphasis> utiliser des jointures JOIN vers
809 d'autres tables, mais uniquement pour des critères de jointure, et non
810 sélectionner des colonnes jointes.
816 Vous <emphasis>ne pouvez pas</emphasis> spécifier de colonnes JOINtes
817 comme faisant partie du résultat de la requête. L'objet row/rowset serait
818 alors corrompu, et contiendrait des données d'une table étrangère à sa table
819 originale. Une erreur sera renvoyée dans un tel cas.
825 <example id="zend.db.table.qry.rows.set.simple.usage.example">
826 <title>Utilisation simple</title>
828 <programlisting language="php"><![CDATA[
831 $select = $table->select();
832 $select->where('bug_status = ?', 'NEW');
834 $rows = $table->fetchAll($select);
840 L'objet <code>Select</code> utilise une interface fluide (fluent interface),
841 permettant le chaînage des méthodes.
845 <example id="zend.db.table.qry.rows.set.fluent.interface.example">
846 <title>Exemple d'interface fluide</title>
848 <programlisting language="php"><![CDATA[
851 $rows = $table->fetchAll($table->select()
852 ->where('bug_status = ?', 'NEW'));
858 <sect3 id="zend.db.table.fetch-all.usage">
859 <title>Récupérer un jeu d'enregistrements :</title>
862 Vous pouvez demander une requête qui retourne plusieurs enregistrements. La
863 méthode <methodname>fetchAll()</methodname> de votre classe de Table permet ceci. Elle retourne
864 un objet de type <classname>Zend_Db_Table_Rowset_Abstract</classname>, même si aucun
865 enregistrement ne correspond à la requête.
868 <example id="zend.db.table.qry.rows.set.finding.row.example">
869 <title>Exemple de récupération d'enregistrements</title>
871 <programlisting language="php"><![CDATA[
874 $select = $table->select()->where('bug_status = ?', 'NEW');
876 $rows = $table->fetchAll($select);
881 Vous pouvez aussi définir les clauses <acronym>SQL</acronym> <code>ORDER BY</code> ou encore
882 <constant>LIMIT</constant> (ou autre équivalent comme OFFSET).
885 <example id="zend.db.table.fetch-all.example2">
886 <title>Exemple de récupération d'enregistrements avec des clauses SQL</title>
888 <programlisting language="php"><![CDATA[
893 // Retourne les enregistrements du 21ème au 30ème
897 $select = $table->select()->where('bug_status = ?', 'NEW')
899 ->limit($count, $offset);
901 $rows = $table->fetchAll($select);
906 Tous les arguments de requêtes sont optionnels. Vous pouvez écrire une requête
907 sans clause WHERE ni LIMIT ou encore ORDER.
911 <sect3 id="zend.db.table.advanced.usage">
912 <title>Utilisation avancée</title>
915 Pour une utilisation plus avancée, vous pourriez vouloir spécifier une à une
916 les colonnes que les enregistrements trouvés doivent comporter. Ceci se fait au
917 moyen de la clause FROM de l'objet select. Le premier paramètre dans la clause FROM
918 est le même que celui d'un objet Zend_Db_Select, cependant l'objet
919 Zend_Db_Table_Select admet une instance de Zend_Db_Table_Abstract pour définir le
924 <example id="zend.db.table.qry.rows.set.retrieving.a.example">
925 <title>Récupérer des colonnes spécifiques sur les enregistrements</title>
927 <programlisting language="php"><![CDATA[
930 $select = $table->select();
931 $select->from($table, array('bug_id', 'bug_description'))
932 ->where('bug_status = ?', 'NEW');
934 $rows = $table->fetchAll($select);
942 Le jeu de résultats retourné est tout de même valide. Il ne possède en
943 revanche que certaines colonnes de la table. La méthode <methodname>save()</methodname>
944 est appelable, mais elle ne mettre à jour que ces colonnes.
946 </important> Il est aussi possible de spécifier des expressions dans une clause
947 FROM, et donc récupérer un objet row/rowset en lecture seule. Dans l'exemple
948 ci-après, nous retournons un enregistrement de la table "bugs" qui représente un
949 agrégat du nombre de nouveaux bugs reportés. Regardez la clause GROUP. L'alias SQL
950 "count" sera accessible dans le row/rowset résultant, comme si il faisait parti de
951 la table en tant que colonne.
955 <example id="zend.db.table.qry.rows.set.retrieving.b.example">
956 <title>Récupérer des enregistrements avec des requêtes incluant des
959 <programlisting language="php"><![CDATA[
962 $select = $table->select();
963 $select->from($table,
964 array('COUNT(reported_by) as `count`', 'reported_by'))
965 ->where('bug_status = ?', 'NEW')
966 ->group('reported_by');
968 $rows = $table->fetchAll($select);
970 </example> Vous pouvez aussi utiliser une table de jointure comme partie de
971 votre requête. Dans l'exemple ci-dessous, nous utilisons la table "accounts" comme
972 partie de la recherche, pour tous les bugs reportés par "Bob".
976 <example id="zend.db.table.qry.rows.set.refine.example">
977 <title>Utiliser une table intermédiaire par jointure avec
978 <methodname>fetchAll()</methodname></title>
980 <programlisting language="php"><![CDATA[
983 // Récupération avec la partie from déjà spécifié, important lors des jointures
984 $select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
985 $select->setIntegrityCheck(false)
986 ->where('bug_status = ?', 'NEW')
987 ->join('accounts', 'accounts.account_name = bugs.reported_by')
988 ->where('accounts.account_name = ?', 'Bob');
990 $rows = $table->fetchAll($select);
996 L'objet <classname>Zend_Db_Table_Select</classname> est destiné à sélectionner
997 des données sur une table précise. Des jointures peuvent être faites, mais il n'est
998 pas possible de sélectionner des colonnes ne faisant pas partie de la table
999 sous-jacente. Cependant, ceci aurait pu être utile dans certains cas, et l'objet
1000 <classname>Zend_Db_Table_Select</classname> possède une clause spéciale
1001 déverrouillant cette limitation. Passez la valeur <constant>FALSE</constant> à sa méthode
1002 <code>setIntegrityCheck</code>. Il est alors possible de sélectionner des colonnes
1003 hors table. Attention toutefois, l'objet row/rowset résultant sera verrouillé.
1004 Impossible d'y appeler <methodname>save()</methodname>, <methodname>delete()</methodname> ou même d'affecter
1005 une valeur à certains de ses champs. Une exception sera systématiquement
1009 <example id="zend.db.table.qry.rows.set.integrity.example">
1011 Déverrouiller un objet Zend_Db_Table_Select pour récupérer des colonnes JOINtes
1014 <programlisting><![CDATA[
1015 $table = new Bugs();
1017 $select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
1018 ->setIntegrityCheck(false);
1019 $select->where('bug_status = ?', 'NEW')
1021 'accounts.account_name = bugs.reported_by',
1023 ->where('accounts.account_name = ?', 'Bob');
1025 $rows = $table->fetchAll($select);
1026 ]]></programlisting>
1031 <sect2 id="zend.db.table.fetch-row">
1032 <title>Récupérer un seul enregistrement</title>
1035 Vous pouvez demander à ne récupérer qu'un seul résultat, en requêtant de manière
1036 similaire à la méthode <methodname>fetchAll()</methodname>.
1039 <example id="zend.db.table.fetch-row.example1">
1040 <title>Exemple de récupération d'un seul enregistrement</title>
1042 <programlisting language="php"><![CDATA[
1043 $table = new Bugs();
1045 $select = $table->select()->where('bug_status = ?', 'NEW')
1048 $row = $table->fetchRow($select);
1049 ]]></programlisting>
1053 Cette méthode retourne un objet de type Zend_Db_Table_Row_Abstract. Si la requête
1054 ne trouve aucun enregistrement, alors <methodname>fetchRow()</methodname> retournera
1055 <constant>NULL</constant>.
1059 <sect2 id="zend.db.table.info">
1060 <title>Récupérer les méta données d'une Table</title>
1063 La classe Zend_Db_Table_Abstract propose des informations concernant ses méta
1064 données.La méthode <methodname>info()</methodname> retourne un tableau d'informations sur les
1065 colonnes, la clé primaire, etc. de la table.
1068 <example id="zend.db.table.info.example">
1069 <title>Exemple de récupération du nom de la table</title>
1071 <programlisting language="php"><![CDATA[
1072 $table = new Bugs();
1074 $info = $table->info();
1076 echo "The table name is " . $info['name'] . "\n";
1077 ]]></programlisting>
1080 <para>Les clés du tableau retourné par <methodname>info()</methodname> sont les suivantes :</para>
1084 <para><emphasis>name</emphasis> => nom de la table.</para>
1089 <emphasis>cols</emphasis> => un tableau contenant les colonnes de la
1096 <emphasis>primary</emphasis> => un tableau contenant la(les) colonnes
1097 utilisée(s) pour définir la clé primaire de la table.
1103 <emphasis>metadata</emphasis> => un tableau associatif, associant les
1104 noms des colonnes de la tables, à leurs informations intrinsèques. Les données
1105 sont les mêmes que celles retournée par <methodname>describeTable()</methodname>.
1111 <emphasis>rowClass</emphasis> => le nom de la classe concrète servant
1112 les objets représentants les enregistrements de la table. Par défaut :
1119 <emphasis>rowsetClass</emphasis> => le nom de la classe concrète
1120 servant de conteneur d'objets représentants les enregistrements de la table. Par
1121 défaut : Zend_Db_Table_Rowset.
1127 <emphasis>referenceMap</emphasis> => un tableau associatif. Il
1128 représente les références de cette table vers ses parents éventuelles. Voyez
1129 <xref linkend="zend.db.table.relationships.defining" />.
1135 <emphasis>dependentTables</emphasis> => un tableau de noms de classes
1136 de tables qui référencent cette table. Voyez <xref
1137 linkend="zend.db.table.relationships.defining" />.
1143 <emphasis>schema</emphasis> => Le nom de la base de données comportant
1150 <sect2 id="zend.db.table.metadata.caching">
1151 <title>Cacher les méta données de la table</title>
1154 Par défaut, <classname>Zend_Db_Table_Abstract</classname> demande à la base de
1155 données les <link linkend="zend.db.table.info">méta données de table</link>, à chaque
1156 instanciation d'objet de table. L'objet de table analyse les métadonnées de la table
1157 dans le SGDB en utilisant la méthode <methodname>describeTable()</methodname> de l'adaptateur. Les
1158 opérations nécessitant cette introspection incluent :
1163 <para><methodname>insert()</methodname></para>
1167 <para><methodname>find()</methodname></para>
1171 <para><methodname>info()</methodname></para>
1176 Cependant, il peut être dégradant pour les performances du SGBD de lui demander
1177 ces informations à chaque instanciation de chaque objet de chaque table. Ainsi, un
1178 système de cache pour les méta données a été mis en place.
1182 La mise en cache des méta données des tables peut être contrôlée de deux manières :
1186 <emphasis>Un appel à la méthode statique
1187 Zend_Db_Table_Abstract::setDefaultMetadataCache()</emphasis> - Ceci permet
1188 d'enregistrer une fois pour toutes l'objet de cache que toutes les tables
1195 <emphasis>L'appel au constructeur
1196 Zend_Db_Table_Abstract::__construct()</emphasis> - Il va permettre de
1197 spécifier l'objet de cache pour une table en particulier.
1201 Dans tous les cas, vous devrez passer soit <constant>NULL</constant> (et
1202 ainsi désactiver le cache des méta données des tables), soit une instance de <link
1203 linkend="zend.cache.frontends.core"><classname>Zend_Cache_Core</classname></link>. Il
1204 est possible d'utiliser à la fois <code>setDefaultMetadataCache</code> et le
1205 constructeur afin d'avoir un objet de cache par défaut, puis un spécifique pour
1209 <example id="zend.db.table.metadata.caching-default">
1210 <title>Utiliser un objet de cache de méta données pour toutes les classes</title>
1213 L'exemple qui suit illustre la manière de passer un objet de cache de méta
1214 données général, pour toutes les classes de table :
1217 <programlisting language="php"><![CDATA[
1218 // D'abord, configurons le cache
1219 $frontendOptions = array(
1220 'automatic_serialization' => true
1223 $backendOptions = array(
1224 'cache_dir' => 'cacheDir'
1227 $cache = Zend_Cache::factory('Core',
1232 // Puis passons le comme objet de cache par défaut
1233 Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
1235 // Testons avec une classe
1236 class Bugs extends Zend_Db_Table_Abstract
1241 // Chaque instance utilise l'objet par défaut
1243 ]]></programlisting>
1246 <example id="zend.db.table.metadata.caching-instance">
1247 <title>Utiliser un objet de cache de métadonnées pour une instance précise</title>
1250 L'exemple qui suit illustre la manière de passer un objet de cache de méta
1251 données spécifique, pour une instance précise :
1254 <programlisting language="php"><![CDATA[
1255 // D'abord, configurons le cache
1256 $frontendOptions = array(
1257 'automatic_serialization' => true
1260 $backendOptions = array(
1261 'cache_dir' => 'cacheDir'
1264 $cache = Zend_Cache::factory('Core',
1269 // Testons avec une classe
1270 class Bugs extends Zend_Db_Table_Abstract
1275 // Lors de son instanciation, il est possible
1276 // de lui passer l'objet de cache
1277 $bugs = new Bugs(array('metadataCache' => $cache));
1278 ]]></programlisting>
1282 <title>Sérialisation automatique avec Cache Frontend</title>
1285 Étant donné que les informations retournées par
1286 <methodname>describeTable()</methodname> le sont sous forme de tableau, assurez vous
1287 que le paramètre <code>automatic_serialization</code> est à <constant>TRUE</constant> pour
1288 l'objet de la classe <classname>Zend_Cache_Core</classname>.
1293 Dans nos exemples, nous utilisons <classname>Zend_Cache_Backend_File</classname>,
1294 mais vous pouvez utiliser le backend que vous souhaitez, voyez <link
1295 linkend="zend.cache">Zend_Cache</link> pour plus d'informations.
1298 <sect3 id="zend.db.table.metadata.caching.hardcoding">
1299 <title>Coder en dur les métadonnées de tables</title>
1302 Pour cacher les métadonnées une étape plus avant, vous pouvez aussi choisir de
1303 coder en dur ces métadonnées. Dans ce cas particulier, cependant, tout changement au
1304 schéma de la table requerra un changement dans votre code. Ainsi, il est seulement
1305 recommandé pour ceux qui sont dans la phase d'optimisation pour un usage en
1309 <para>La structure des métadonnées est comme ceci :</para>
1311 <programlisting language="php"><![CDATA[
1312 protected $_metadata = array(
1313 '<column_name>' => array(
1314 'SCHEMA_NAME' => <string>,
1315 'TABLE_NAME' => <string>,
1316 'COLUMN_NAME' => <string>,
1317 'COLUMN_POSITION' => <int>,
1318 'DATA_TYPE' => <string>,
1319 'DEFAULT' => NULL|<value>,
1320 'NULLABLE' => <bool>,
1321 'LENGTH' => <string - length>,
1322 'SCALE' => NULL|<value>,
1323 'PRECISION' => NULL|<value>,
1324 'UNSIGNED' => NULL|<bool>,
1325 'PRIMARY' => <bool>,
1326 'PRIMARY_POSITION' => <int>,
1327 'IDENTITY' => <bool>,
1329 // additional columns...
1331 ]]></programlisting>
1334 Une manière simple de récupérer les valeurs appropriées est d'activer le cache
1335 des métadonnées et d'utiliser celles présentes dans votre cache.
1339 Vous pouvez désactiver cette optimisation en mettant à <constant>FALSE</constant> le
1340 paramètre <code>metadataCacheInClass</code> :
1343 <programlisting language="php"><![CDATA[
1344 // Lors de l'instanciation :
1345 $bugs = new Bugs(array('metadataCacheInClass' => false));
1348 $bugs->setMetadataCacheInClass(false);
1349 ]]></programlisting>
1352 Ce paramètre est activé par défaut, ce qui assure que le tableau
1353 <varname>$_metadata</varname> n'est chargé qu'une seule fois par instance
1358 <sect2 id="zend.db.table.extending">
1359 <title>Personnaliser et étendre une classe de Table</title>
1361 <sect3 id="zend.db.table.extending.row-rowset">
1362 <title>Utiliser des objets Row ou Rowset personnalisés</title>
1365 Par défaut, les méthodes de la classe de Table retourne des jeux
1366 d'enregistrements comme étant des instances de la classe
1367 <classname>Zend_Db_Table_Rowset</classname>, ces "Rowsets" contiennent des
1368 enregistrements de la table, représentés par des objets instances de
1369 <classname>Zend_Db_Table_Row</classname>. Vous pouvez spécifier vos propres classes
1370 pour row/rowset, mais elles doivent étendre
1371 <classname>Zend_Db_Table_Rowset_Abstract</classname> ou
1372 <classname>Zend_Db_Table_Row_Abstract</classname>, respectivement.
1376 Vous pouvez spécifier vos classes row/rowset en utilisant le constructeur de
1377 la classe de Table, via le tableau d'options, aux clés <code>"rowClass"</code> et
1378 <code>"rowsetClass"</code>. Indiquez les noms des classes sous forme de chaînes de
1382 <example id="zend.db.table.extending.row-rowset.example">
1383 <title>Exemple de spécification de ses propres classes Row et Rowset</title>
1385 <programlisting language="php"><![CDATA[
1386 class My_Row extends Zend_Db_Table_Row_Abstract
1391 class My_Rowset extends Zend_Db_Table_Rowset_Abstract
1398 'rowClass' => 'My_Row',
1399 'rowsetClass' => 'My_Rowset'
1403 $where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')
1405 // Retourne un objet de type My_Rowset,
1406 // contenant des objets de type My_Row.
1407 $rows = $table->fetchAll($where);
1408 ]]></programlisting>
1412 Vous pouvez aussi utiliser les méthodes <methodname>setRowClass()</methodname> et
1413 <methodname>setRowsetClass()</methodname>. Ceci s'applique alors de manière ponctuelle, et non
1414 plus globale pour toute la classe de Table en tout point.
1417 <example id="zend.db.table.extending.row-rowset.example2">
1418 <title>Exemple de changement ponctuel des classes de Row et Rowset</title>
1420 <programlisting language="php"><![CDATA[
1421 $table = new Bugs();
1423 $where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')
1425 // Retourne un objet de type Zend_Db_Table_Rowset
1426 // contenant des objets de type Zend_Db_Table_Row.
1427 $rowsStandard = $table->fetchAll($where);
1429 $table->setRowClass('My_Row');
1430 $table->setRowsetClass('My_Rowset');
1432 // Retourne un objet de type My_Rowset,
1433 // contenant des objets de type My_Row.
1434 $rowsCustom = $table->fetchAll($where);
1436 // L'objet $rowsStandard existe toujours et n'a pas changé d'état.
1437 ]]></programlisting>
1441 Pour des informations détaillées concernant les classes Row et Rowset, voyez
1442 <xref linkend="zend.db.table.row" /> et <xref
1443 linkend="zend.db.table.rowset" />.
1447 <sect3 id="zend.db.table.extending.insert-update">
1448 <title>Personnaliser les logiques Insert, Update, et Delete</title>
1451 Vous pouvez redéfinir les méthodes <methodname>insert()</methodname> et
1452 <methodname>update()</methodname> afin d'y ajouter votre propre logique. Assurez vous d'appeler
1453 les méthodes parentes une fois votre code écrit.
1456 <example id="zend.db.table.extending.insert-update.example">
1458 Exemple d'implémentation d'une logique personnalisée gérant des timestamps
1461 <programlisting language="php"><![CDATA[
1462 class Bugs extends Zend_Db_Table_Abstract
1464 protected $_name = 'bugs';
1466 public function insert(array $data)
1468 // Ajout d'un timestamp
1469 if (empty($data['created_on'])) {
1470 $data['created_on'] = time();
1472 return parent::insert($data);
1475 public function update(array $data, $where)
1477 // Ajout d'un timestamp
1478 if (empty($data['updated_on'])) {
1479 $data['updated_on'] = time();
1481 return parent::update($data, $where);
1484 ]]></programlisting>
1487 <para>Il est aussi possible de redéfinir la méthode <methodname>delete()</methodname>.</para>
1490 <sect3 id="zend.db.table.extending.finders">
1491 <title>Définir des méthodes de recherches personnalisées dans Zend_Db_Table</title>
1494 Bien que <methodname>fetchAll()</methodname> fonctionne très bien, si vous avez plusieurs
1495 appels similaires à cette méthode (ou une autre), il peut être intéressant de
1496 factoriser du code en créant votre propre méthode de récupération d'enregistrements,
1497 utilisant <methodname>fetchAll()</methodname> ou une autre méthode.
1500 <example id="zend.db.table.extending.finders.example">
1501 <title>Méthode personnalisée de récupération d'enregistrements "bugs" par
1502 critère "status"</title>
1504 <programlisting language="php"><![CDATA[
1505 class Bugs extends Zend_Db_Table_Abstract
1507 protected $_name = 'bugs';
1509 public function findByStatus($status)
1511 $where = $this->getAdapter()->quoteInto('bug_status = ?',
1513 return $this->fetchAll($where, 'bug_id');
1516 ]]></programlisting>
1520 <sect3 id="zend.db.table.extending.inflection">
1521 <title>Utiliser l'inflexion dans Zend_Db_Table</title>
1524 L'<emphasis>inflexion</emphasis> est un processus de transformations de
1525 caractères. Par défaut, si vous ne définissez pas de nom à votre table via la
1526 propriété protégée <varname>$_name</varname>,
1527 <classname>Zend_Db_Table_Abstract</classname> va utiliser le nom de la classe comme
1528 nom de table, sans effectuer aucune transformation.
1532 Certaines personnes peuvent vouloir utiliser un mécanisme d'inflexion pour
1533 transformer le nom de la classe d'une manière bien spécifique, afin de retrouver le
1538 Par exemple, une classe nommée "<code>BugsProducts</code>", peut vouloir
1539 refléter une table s'appelant "<code>bugs_products</code>," sans utiliser la
1540 propriété de classe <varname>$_name</varname>. Dans cette règle d'inflexion, les mots
1541 composant le nom de la classe sont écrits en "CamelCase", et seraient transformés en
1542 mots en minuscules, et séparés par des tirets bas.
1546 Vous pouvez aussi spécifier le nom de la table indépendamment du nom de la
1547 classe. Utilisez pour cela la propriété <varname>$_name</varname> de la classe de
1552 Si vous voulez utiliser l'inflexion, vous devrez créer une classe (abstraite)
1553 étendant <classname>Zend_Db_Table_Abstract</classname>, et redéfinissant sa méthode
1554 protégée <methodname>_setupTableName()</methodname>. Toutes les classes de Table devront alors
1555 hériter de cette nouvelle classe abstraite.
1558 <example id="zend.db.table.extending.inflection.example">
1559 <title>Exemple d'une classe abstraite utilisant l'inflexion</title>
1561 <programlisting language="php"><![CDATA[
1562 abstract class MyAbstractTable extends Zend_Db_Table_Abstract
1564 protected function _setupTableName()
1566 if (!$this->_name) {
1567 $this->_name = myCustomInflector(get_class($this));
1569 parent::_setupTableName();
1573 class BugsProducts extends MyAbstractTable
1576 ]]></programlisting>
1580 C'est à vous d'écrire les fonctions qui vont établir le mécanisme