1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- EN-Revision: 20766 -->
4 <sect1 id="zend.db.table.row">
5 <title>Zend_Db_Table_Row</title>
7 <sect2 id="zend.db.table.row.introduction">
8 <title>Introduction</title>
11 <classname>Zend_Db_Table_Row</classname> est la classe qui donne accès à chacun
12 des résultats issus d'un objet <classname>Zend_Db_Table</classname>. Lorsque vous
13 exécutez une requête via une classe de Table, alors les résultats sont des objets
14 <classname>Zend_Db_Table_Row</classname>. Vous pouvez aussi utiliser ces objets comme
15 résultats vides : pour créer des nouveaux résultats à ajouter à la base de
20 <classname>Zend_Db_Table_Row</classname> est une implémentation du design pattern
21 <ulink url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data
26 <sect2 id="zend.db.table.row.read">
27 <title>Récupérer un résultat (un "Row")</title>
30 <classname>Zend_Db_Table_Abstract</classname> possède des méthodes
31 <methodname>find()</methodname> et <methodname>fetchAll()</methodname>, qui retournent un objet de type
32 <classname>Zend_Db_Table_Rowset</classname>, et une méthode <methodname>fetchRow()</methodname>, qui
33 retourne un objet de type <classname>Zend_Db_Table_Row</classname>.
36 <example id="zend.db.table.row.read.example">
37 <title>Exemple de récupération d'un Row</title>
39 <programlisting language="php"><![CDATA[
41 $row = $bugs->fetchRow($bugs->select()
42 ->where('bug_id = ?', 1));
47 Un objet <classname>Zend_Db_Table_Rowset</classname> contient une collection
48 d'objets <classname>Zend_Db_Table_Row</classname>. Voyez <xref
49 linkend="zend.db.table.rowset" />.
52 <example id="zend.db.table.row.read.example-rowset">
53 <title>Exemple de lecture d'un Row dans un Rowset</title>
55 <programlisting language="php"><![CDATA[
57 $rowset = $bugs->fetchAll($bugs->select()
58 ->where('bug_status = ?', 1));
59 $row = $rowset->current();
63 <sect3 id="zend.db.table.row.read.get">
64 <title>Lecture des valeurs des colonnes, dans un Row</title>
67 <classname>Zend_Db_Table_Row_Abstract</classname> possède des accesseurs. Les
68 colonnes <acronym>SQL</acronym> du résultat sont disponibles en lecture et écriture, via des propriétés
72 <example id="zend.db.table.row.read.get.example">
73 <title>Lecture d'une colonne dans un Row</title>
75 <programlisting language="php"><![CDATA[
77 $row = $bugs->fetchRow($bugs->select()
78 ->where('bug_id = ?', 1));
80 // Affiche la valeur de la colonne bug_description
81 echo $row->bug_description;
87 Les versions antérieures de <classname>Zend_Db_Table_Row</classname>
88 utilisaient un processus de transformation nommé <emphasis>inflexion</emphasis>
89 pour récupérer les valeurs des colonnes dans un résultat.
93 Actuellement, <classname>Zend_Db_Table_Row</classname> n'utilise pas
94 d'inflexion. Les noms des propriétés de l'objet doivent correspondre à
95 l'orthographe des noms des colonnes dans la base de données sous-jacente
100 <sect3 id="zend.db.table.row.read.to-array">
101 <title>Récupérer les valeurs des colonnes comme un tableau</title>
104 Vous pouvez accéder aux données d'un row sous forme de tableau grâce à la
105 méthode <methodname>toArray()</methodname>. Celle-ci retourne un tableau associatif.
108 <example id="zend.db.table.row.read.to-array.example">
109 <title>Exemple avec toArray()</title>
111 <programlisting language="php"><![CDATA[
113 $row = $bugs->fetchRow($bugs->select()
114 ->where('bug_id = ?', 1));
116 // Récupère un tableau associatif column/value
117 $rowArray = $row->toArray();
119 // Utilisation comme un tableau normal
120 foreach ($rowArray as $column => $value) {
121 echo "Column: $column\n";
122 echo "Value: $value\n";
128 Le tableau retourné par <methodname>toArray()</methodname> n'est pas une référence. Vous
129 pouvez modifier ses valeurs, cela n'aura aucune répercussion dans la base de
134 <sect3 id="zend.db.table.row.read.relationships">
135 <title>Récupérer des données des tables liées</title>
138 <classname>Zend_Db_Table_Row_Abstract</classname> possède des méthodes
139 permettant de récupérer des données des tables liées à la table interrogée. Voyez
140 <xref linkend="zend.db.table.relationships" /> pour plus d'informations sur les
141 relations entre les tables.
146 <sect2 id="zend.db.table.row.write">
147 <title>Sauvegarde un Row en base de données</title>
149 <sect3 id="zend.db.table.row.write.set">
150 <title>Changement des valeurs des colonnes d'un Row</title>
153 Vous pouvez changer les valeurs de chaque colonne du résultat Row, simplement
154 avec les accesseurs, comme en lecture. Effectuez une banale affectation.
158 Utiliser l'accesseur pour spécifier une valeur à une colonne d'un résultat Row
159 ne répercute pas le comportement immédiatement en base de données. Vous devez
160 utiliser explicitement la méthode <methodname>save()</methodname> pour ceci.
163 <example id="zend.db.table.row.write.set.example">
164 <title>Exemple de changement de la valeur d'une colonne dans un Row</title>
166 <programlisting language="php"><![CDATA[
168 $row = $bugs->fetchRow($bugs->select()
169 ->where('bug_id = ?', 1));
171 // Change la valeur d'une ou plusieurs colonnes
172 $row->bug_status = 'FIXED';
174 // MET A JOUR l'enregistrement dans la base de données
180 <sect3 id="zend.db.table.row.write.insert">
181 <title>Créer un Row vierge</title>
184 Vous pouvez créer un nouvel enregistrement vierge (Row) pour une table avec la
185 méthode <methodname>createRow()</methodname> issue de la classe de cette Table. Vous pouvez
186 alors affecter des valeurs à ses colonnes grâce aux accesseurs, comme déjà vu, puis
187 enregistrer le Row en base de données avec sa méthode <methodname>save()</methodname>.
190 <example id="zend.db.table.row.write.insert.example">
191 <title>Exemple de création d'un Row vierge pour une table</title>
193 <programlisting language="php"><![CDATA[
195 $newRow = $bugs->createRow();
197 // affecte des valeurs aux colonnes
198 $newRow->bug_description = '...description...';
199 $newRow->bug_status = 'NEW';
201 // INSERT le nouvel enregistrement dans la base de données
207 L'argument optionnel de <methodname>createRow()</methodname> est un tableau associatif qui
208 sert à peupler tout de suite l'objet de valeurs.
211 <example id="zend.db.table.row.write.insert.example2">
212 <title>Exemple de remplissage des valeurs d'un nouveau Row vierge</title>
214 <programlisting language="php"><![CDATA[
216 'bug_description' => '...description...',
217 'bug_status' => 'NEW'
221 $newRow = $bugs->createRow($data);
223 // INSERT l'enregistrement en base de données
230 La méthode <methodname>createRow()</methodname> était nommée <methodname>fetchNew()</methodname>
231 dans les anciennes version de <classname>Zend_Db_Table</classname>. Il est
232 recommandé de ne plus utiliser cette ancienne appellation, même si celle-ci
233 fonctionne toujours actuellement.
238 <sect3 id="zend.db.table.row.write.set-from-array">
239 <title>Changement en masse des valeurs dans un Row</title>
242 <classname>Zend_Db_Table_Row_Abstract</classname> possède une méthode
243 <methodname>setFromArray()</methodname> qui permet de lui peupler ses valeurs avec celles issues
244 d'un tableau associatif nom de la colonne / valeur.
247 <example id="zend.db.table.row.write.set-from-array.example">
249 Exemple d'utilisation de setFromArray() avec un enregistrement (Row) vierge
252 <programlisting language="php"><![CDATA[
254 $newRow = $bugs->createRow();
256 // Les données sont dans un tableau associatif
258 'bug_description' => '...description...',
259 'bug_status' => 'NEW'
262 // Affecte toutes les valeurs des colonnes en une seule fois
263 $newRow->setFromArray($data);
265 // INSERT l'enregistrement en base de données
271 <sect3 id="zend.db.table.row.write.delete">
272 <title>Supprimer un Row</title>
275 Vous pouvez appeler la méthode <methodname>delete()</methodname> d'un objet Row. Ceci
276 supprime les lignes dans la base de données qui correspondent à la clé primaire de
280 <example id="zend.db.table.row.write.delete.example">
281 <title>Effacer un Row</title>
283 <programlisting language="php"><![CDATA[
285 $row = $bugs->fetchRow('bug_id = 1');
287 // EFFACE cet enregistrement de la base de données
293 Notez qu'il n'est pas nécessaire d'appeler <methodname>save()</methodname> pour un
294 effacement. Celui-ci est à effet immédiat.
299 <sect2 id="zend.db.table.row.serialize">
300 <title>Sérialisation et désérialisation d'un Row</title>
303 Il peut être utile de sauvegarder le contenu d'un enregistrement (Row) sur un
304 support quelconque, pour une utilisation ultérieure. La
305 <emphasis>sérialisation</emphasis> est le nom de l'opération qui consiste à transformer
306 un objet en une forme facilement stockable (dans un fichier par exemple). Les objets du
307 type <classname>Zend_Db_Table_Row_Abstract</classname> sont sérialisables.
310 <sect3 id="zend.db.table.row.serialize.serializing">
311 <title>Sérialiser un Row</title>
314 Utilisez simplement la fonction <acronym>PHP</acronym> <methodname>serialize()</methodname> pour créer une
315 chaîne de caractères représentant votre objet Row.
318 <example id="zend.db.table.row.serialize.serializing.example">
319 <title>Exemple de sérialisation d'un Row</title>
321 <programlisting language="php"><![CDATA[
323 $row = $bugs->fetchRow('bug_id = 1');
325 // Convertit l'objet en une forme sérialisée
326 $serializedRow = serialize($row);
328 // Maintenant vous pouvez utiliser $serializedRow
329 // pour l'écrire dans un fichier, etc.
334 <sect3 id="zend.db.table.row.serialize.unserializing">
335 <title>Désérialiser les données d'un Row</title>
338 Utilisez simplement la fonction <acronym>PHP</acronym> <methodname>unserialize()</methodname>. L'objet Row
339 originel est alors recréé.
343 Notez que l'objet retourné fonctionne alors en mode
344 <emphasis>déconnecté</emphasis>. Vous pouvez lire les valeurs des colonnes, mais pas
345 les modifier ni enregistrer l'objet en base de données
346 (<methodname>save()</methodname>).
349 <example id="zend.db.table.row.serialize.unserializing.example">
350 <title>Exemple de désérialisation d'un objet Row sérialisé</title>
352 <programlisting language="php"><![CDATA[
353 $rowClone = unserialize($serializedRow);
355 // Vous ne pouvez faire qu'une utilisation en lecture seule
356 echo $rowClone->bug_description;
361 <title>Pourquoi ce mode déconnecté imposé ?</title>
364 Un objet sérialisé est une chaîne de caractère, humainement visible. Il
365 est donc peu sécurisé d'y laisser un mot de passe vers un serveur de base de
366 données. Le lecteur d'un objet Row sérialisé ne devrait pas pouvoir accéder à la
367 base de données. De plus, une connexion à une base de données est un type non
368 sérialisable par <acronym>PHP</acronym> (ressource).
373 <sect3 id="zend.db.table.row.serialize.set-table">
374 <title>Reconnecter l'objet Row à la Table</title>
377 Il est bien entendu possible de reconnecter l'objet Row à la base de données,
378 et plus précisément à la Table dont il fut issu. Utilisez la méthode
379 <methodname>setTable()</methodname> et passez lui une instance héritant de
380 <classname>Zend_Db_Table_Abstract</classname>. Une fois reconnecté, l'objet Row
381 possède de nouveau un accès à la base de données, et n'est donc plus en mode lecture
385 <example id="zend.db.table.row.serialize.set-table.example">
386 <title>Exemple de réactivation d'un Row</title>
388 <programlisting language="php"><![CDATA[
389 $rowClone = unserialize($serializedRow);
393 // Reconnecte le Row à la table et donc, à la base de données
394 $rowClone->setTable($bugs);
396 // Maintenant il est possible de l'utiliser en mode écriture
397 $rowClone->bug_status = 'FIXED';
404 <sect2 id="zend.db.table.row.extending">
405 <title>Étendre la classe Row</title>
408 Vous pouvez utilisez votre propre classe étendant
409 <classname>Zend_Db_Table_Row_Abstract</classname>. Spécifiez votre classe dans la
410 propriété protégée <varname>$_rowClass</varname> de la classe de votre Table, ou dans le
411 tableau du constructeur de l'objet Table.
414 <example id="zend.db.table.row.extending.example">
415 <title>Spécification d'une classe Row personnalisée</title>
417 <programlisting language="php"><![CDATA[
418 class MyRow extends Zend_Db_Table_Row_Abstract
420 // ...personnalisations
423 // Spécifie la classe de Row utilisée pour toutes les
424 // instance de la classe de Table
425 class Products extends Zend_Db_Table_Abstract
427 protected $_name = 'products';
428 protected $_rowClass = 'MyRow';
431 // Ou pour une classe de table spécifique, via son constructeur
432 $bugs = new Bugs(array('rowClass' => 'MyRow'));
436 <sect3 id="zend.db.table.row.extending.overriding">
437 <title>Initialisation et pré-traitements d'un Row</title>
440 Si vous avez un besoin spécifique d'implémenter une logique spéciale après la
441 création d'une instance de Row, vous pouvez utiliser sa méthode <methodname>init()</methodname>,
442 qui est appelée dans son constructeur, mais après que les méta données aient été
443 calculées. <example id="zend.db.table.row.init.usage.example">
444 <title>Exemple d'utilisation de la méthode init()</title>
446 <programlisting language="php"><![CDATA[
447 class MyApplicationRow extends Zend_Db_Table_Row_Abstract
451 public function init()
453 $this->_role = new MyRoleClass();
461 <sect3 id="zend.db.table.row.extending.insert-update">
463 Définir sa propre logique pour Insert, Update, et Delete dans Zend_Db_Table_Row
467 La classe des Rows appelle les méthodes protégées <methodname>_insert()</methodname>,
468 <methodname>_update()</methodname>, et <methodname>_delete()</methodname> avant d'effectuer chacune des
469 opérations respectives <constant>INSERT</constant>, <constant>UPDATE</constant>, et
470 <constant>DELETE</constant>. Il est donc possible de définir sa propre logique dans votre
475 Ci-dessous vous trouverez des exemples d'utilisation d'une logique
476 personnalisée dans les classes de Row :
479 <example id="zend.db.table.row.extending.overriding-example1">
480 <title>Exemple de logique personnalisée dans une classe de Row</title>
483 La logique personnelle peut donc être déportée dans une classe de Row qui
484 ne s'appliquera qu'à certaines tables, et pas à d'autres. Sinon, la classe de
485 Table utilise le Row par défaut.
489 Par exemple, vous souhaitez historiser toutes les insertions sur une Table
490 spécifique, mais uniquement si la configuration du site le permet :
493 <programlisting language="php"><![CDATA[
494 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
496 protected function _insert()
498 $log = Zend_Registry::get('database_log');
499 $log->info(Zend_Debug::dump($this->_data,
500 "INSERT: $this->_tableClass",
505 // $loggingEnabled est une variable d'exemple qui définit si
506 // l'historisation est activée ou pas
507 if ($loggingEnabled) {
508 $bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
515 <example id="zend.db.table.row.extending.overriding-example2">
516 <title>Exemple d'une classe de Row qui historise les insertions de plusieurs
520 En passant l'objet Row personnalisé à chacune des Tables concernées, alors
521 vous n'aurez pas besoin de définir cette logique dans chacune des classes des
526 Dans cet exemple, le code qui effectue l'historisation est identique à
527 celui de l'exemple précédent.
530 <programlisting language="php"><![CDATA[
531 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
533 protected function _insert()
535 $log = Zend_Registry::get('database_log');
536 $log->info(Zend_Debug::dump($this->_data,
537 "INSERT: $this->_tableClass",
542 class Bugs extends Zend_Db_Table_Abstract
544 protected $_name = 'bugs';
545 protected $_rowClass = 'MyLoggingRow';
548 class Products extends Zend_Db_Table_Abstract
550 protected $_name = 'products';
551 protected $_rowClass = 'MyLoggingRow';
557 <sect3 id="zend.db.table.row.extending.inflection">
558 <title>Définir l'inflexion dans Zend_Db_Table_Row</title>
561 Il peut être intéressant de personnaliser l'accès aux colonnes de la table
562 représentée par un résultat Row, plutôt que d'utiliser le nom des colonnes telles
563 que définies dans le SGBDR sous-jacent. La transformation de l'un vers l'autre est
564 appelée <emphasis>inflexion</emphasis>.
568 Les classes Zend_Db n'utilisent pas l'inflexion par défaut. Voyez <xref
569 linkend="zend.db.table.extending.inflection" /> pour plus de détails sur ce
574 Ainsi si vous voulez utiliser l'inflexion, vous devez implémenter vous-même la
575 transformation à effectuer en redéfinissant la méthode
576 <methodname>_transformColumn()</methodname> dans votre classe de Row, et bien entendu utiliser
577 cette classe de Row pour votre Table.
580 <example id="zend.db.table.row.extending.inflection.example">
581 <title>Exemple d'utilisation de l'inflexion</title>
584 Ceci vous permet d'utiliser les accesseurs de votre Row de manière
585 transformée. La classe de votre Row utilisera <methodname>_transformColumn()</methodname>
586 pour changer le nom de la colonne appelée, avant de le faire correspondre à un
587 nom dans la table réelle de la base de données.
590 <programlisting language="php"><![CDATA[
591 class MyInflectedRow extends Zend_Db_Table_Row_Abstract
593 protected function _transformColumn($columnName)
595 $nativeColumnName = myCustomInflector($columnName);
596 return $nativeColumnName;
600 class Bugs extends Zend_Db_Table_Abstract
602 protected $_name = 'bugs';
603 protected $_rowClass = 'MyInflectedRow';
607 $row = $bugs->fetchNew();
609 // Utilisez des nom de colonnes CamelCase, l'inflecteur les
610 // transformera alors pour vous afin d'établir la correspondance
611 // avec les noms natifs des colonnes.
612 $row->bugDescription = 'New description';
616 <para>En revanche, c'est à vous d'écrire votre mécanisme d'inflexion.</para>