| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- <!-- EN-Revision: 13846 -->
- <sect1 id="zend.db.table.row">
- <title>Zend_Db_Table_Row</title>
- <sect2 id="zend.db.table.row.introduction">
- <title>Introduction</title>
- <para><classname>Zend_Db_Table_Row</classname> est la classe qui donne accès à chacun des résultats issus d'un objet
- <classname>Zend_Db_Table</classname>. Lorsque vous exécutez une requête via une classe de Table, alors les résultats sont
- des objets <classname>Zend_Db_Table_Row</classname>. Vous pouvez aussi utiliser ces objets comme résultats vides : pour
- créer des nouveaux résultats à ajouter à la base de données.</para>
- <para><classname>Zend_Db_Table_Row</classname> est une implémentation du design pattern <ulink
- url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data Gateway</ulink></para>
- </sect2>
- <sect2 id="zend.db.table.row.read">
- <title>Récupérer un résultat (un "Row")</title>
- <para><classname>Zend_Db_Table_Abstract</classname> possède des méthodes <code>find()</code> et <code>fetchAll()</code>,
- qui retournent un objet de type <classname>Zend_Db_Table_Rowset</classname>, et une méthode <code>fetchRow()</code>, qui
- retourne un objet de type <classname>Zend_Db_Table_Row</classname>.</para>
- <example id="zend.db.table.row.read.example">
- <title>Exemple de récupération d'un Row</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()
- ->where('bug_id = ?', 1));
- ]]></programlisting>
- </example>
- <para>Un objet <classname>Zend_Db_Table_Rowset</classname> contient une collection d'objets
- <classname>Zend_Db_Table_Row</classname>. Voyez <xref linkend="zend.db.table.rowset" />.</para>
- <example id="zend.db.table.row.read.example-rowset">
- <title>Exemple de lecture d'un Row dans un Rowset</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $rowset = $bugs->fetchAll($bugs->select()
- ->where('bug_status = ?', 1));
- $row = $rowset->current();
- ]]></programlisting>
- </example>
- <sect3 id="zend.db.table.row.read.get">
- <title>Lecture des valeurs des colonnes, dans un Row</title>
- <para><classname>Zend_Db_Table_Row_Abstract</classname> possède des accesseurs. Les colonnes SQL du résultat sont
- disponibles en lecture et écriture, via des propriétés de classe.</para>
- <example id="zend.db.table.row.read.get.example">
- <title>Lecture d'une colonne dans un Row</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()
- ->where('bug_id = ?', 1));
- // Affiche la valeur de la colonne bug_description
- echo $row->bug_description;
- ]]></programlisting>
- </example>
- <note>
- <para>Les versions antérieures de <classname>Zend_Db_Table_Row</classname> utilisaient un processus de
- transformation nommé <emphasis>inflexion</emphasis> pour récupérer les valeurs des colonnes dans un
- résultat.</para>
- <para>Actuellement, <classname>Zend_Db_Table_Row</classname> n'utilise pas d'inflexion. Les noms des propriétés de
- l'objet doivent correspondre à l'orthographe des noms des colonnes dans la base de données
- sous-jacente</para>
- </note>
- </sect3>
- <sect3 id="zend.db.table.row.read.to-array">
- <title>Récupérer les valeurs des colonnes comme un tableau</title>
- <para>Vous pouvez accéder aux données d'un row sous forme de tableau grâce à la méthode
- <code>toArray()</code>. Celle-ci retourne un tableau associatif.</para>
- <example id="zend.db.table.row.read.to-array.example">
- <title>Exemple avec <code>toArray()</code></title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()
- ->where('bug_id = ?', 1));
- // Récupère un tableau associatif column/value
- $rowArray = $row->toArray();
- // Utilisation comme un tableau normal
- foreach ($rowArray as $column => $value) {
- echo "Column: $column\n";
- echo "Value: $value\n";
- }
- ]]></programlisting>
- </example>
- <para>Le tableau retourné par <code>toArray()</code> n'est pas une référence. Vous pouvez modifier ses
- valeurs, cela n'aura aucune répercussion dans la base de données.</para>
- </sect3>
- <sect3 id="zend.db.table.row.read.relationships">
- <title>Récupérer des données des tables liées</title>
- <para><classname>Zend_Db_Table_Row_Abstract</classname> possède des méthodes permettant de récupérer des données des
- tables liées à la table interrogée. Voyez <xref linkend="zend.db.table.relationships" /> pour plus
- d'informations sur les relations entre les tables.</para>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.row.write">
- <title>Sauvegarde un Row en base de données</title>
- <sect3 id="zend.db.table.row.write.set">
- <title>Changement des valeurs des colonnes d'un Row</title>
- <para>Vous pouvez changer les valeurs de chaque colonne du résultat Row, simplement avec les accesseurs,
- comme en lecture. Effectuez une banale affectation.</para>
- <para>Utiliser l'accesseur pour spécifier une valeur à une colonne d'un résultat Row ne répercute pas le
- comportement immédiatement en base de données. Vous devez utiliser explicitement la méthode
- <code>save()</code> pour ceci.</para>
- <example id="zend.db.table.row.write.set.example">
- <title>Exemple de changement de la valeur d'une colonne dans un Row</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()
- ->where('bug_id = ?', 1));
- // Change la valeur d'une ou plusieurs colonnes
- $row->bug_status = 'FIXED';
- // MET A JOUR l'enregistrement dans la base de données
- $row->save();
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.write.insert">
- <title>Créer un Row vierge</title>
- <para>Vous pouvez créer un nouvel enregistrement vierge (Row) pour une table avec la méthode
- <code>createRow()</code> issue de la classe de cette Table. Vous pouvez alors affecter des valeurs à ses
- colonnes grâce aux accesseurs, comme déjà vu, puis enregistrer le Row en base de données avec sa méthode
- <code>save()</code>.</para>
- <example id="zend.db.table.row.write.insert.example">
- <title>Exemple de création d'un Row vierge pour une table</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $newRow = $bugs->createRow();
- // affecte des valeurs aux colonnes
- $newRow->bug_description = '...description...';
- $newRow->bug_status = 'NEW';
- // INSERT le nouvel enregistrement dans la base de données
- $newRow->save();
- ]]></programlisting>
- </example>
- <para>L'argument optionnel de <code>createRow()</code> est un tableau associatif qui sert à peupler tout de
- suite l'objet de valeurs.</para>
- <example id="zend.db.table.row.write.insert.example2">
- <title>Exemple de remplissage des valeurs d'un nouveau Row vierge</title>
- <programlisting role="php"><![CDATA[
- $data = array(
- 'bug_description' => '...description...',
- 'bug_status' => 'NEW'
- );
- $bugs = new Bugs();
- $newRow = $bugs->createRow($data);
- // INSERT l'enregistrement en base de données
- $newRow->save();
- ]]></programlisting>
- </example>
- <note>
- <para>La méthode <code>createRow()</code> était nommée <code>fetchNew()</code> dans les anciennes
- version de <classname>Zend_Db_Table</classname>. Il est recommandé de ne plus utiliser cette ancienne appellation,
- même si celle-ci fonctionne toujours actuellement.</para>
- </note>
- </sect3>
- <sect3 id="zend.db.table.row.write.set-from-array">
- <title>Changement en masse des valeurs dans un Row</title>
- <para><classname>Zend_Db_Table_Row_Abstract</classname> possède une méthode <code>setFromArray()</code> qui permet de
- lui peupler ses valeurs avec celles issues d'un tableau associatif nom de la colonne / valeur..</para>
- <example id="zend.db.table.row.write.set-from-array.example">
- <title>Exemple d'utilisation de <code>setFromArray()</code> avec un enregistrement (Row) vierge</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $newRow = $bugs->createRow();
- // Les données sont dans un tableau associatif
- $data = array(
- 'bug_description' => '...description...',
- 'bug_status' => 'NEW'
- );
- // Affecte toutes les valeurs des colonnes en une seule fois
- $newRow->setFromArray($data);
- // INSERT l'enregistrement en base de données
- $newRow->save();
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.write.delete">
- <title>Supprimer un Row</title>
- <para>Vous pouvez appeler la méthode <code>delete()</code> d'un objet Row. Ceci supprime les lignes dans la
- base de données qui correspondent à la clé primaire de l'objet Row.</para>
- <example id="zend.db.table.row.write.delete.example">
- <title>Effacer un Row</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow('bug_id = 1');
- // EFFACE cet enregistrement de la base de données
- $row->delete();
- ]]></programlisting>
- </example>
- <para>Notez qu'il n'est pas nécessaire d'appeler <code>save()</code> pour un effacement. Celui-ci est à
- effet immédiat.</para>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.row.serialize">
- <title>Sérialisation et désérialisation d'un Row</title>
- <para>Il peut être utile de sauvegarder le contenu d'un enregistrement (Row) sur un support quelconque, pour une
- utilisation ultérieure. La <emphasis>sérialisation</emphasis> est le nom de l'opération qui consiste à
- transformer un objet en une forme facilement stockable (dans un fichier par exemple). Les objets du type
- <classname>Zend_Db_Table_Row_Abstract</classname> sont sérialisables.</para>
- <sect3 id="zend.db.table.row.serialize.serializing">
- <title>Sérialiser un Row</title>
- <para>Utilisez simplement la fonction PHP <code>serialize()</code> pour créer une chaîne de caractères
- représentant votre objet Row.</para>
- <example id="zend.db.table.row.serialize.serializing.example">
- <title>Exemple de sérialisation d'un Row</title>
- <programlisting role="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow('bug_id = 1');
- // Convertit l'objet en une forme sérialisée
- $serializedRow = serialize($row);
- // Maintenant vous pouvez utiliser $serializedRow
- // pour l'écrire dans un fichier, etc.
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.serialize.unserializing">
- <title>Désérialiser les données d'un Row</title>
- <para>Utilisez simplement la fonction PHP <code>unserialize()</code>. L'objet Row originel est alors
- recréé.</para>
- <para>Notez que l'objet retourné fonctionne alors en mode <emphasis>déconnecté</emphasis>. Vous pouvez lire
- les valeurs des colonnes, mais pas les modifier ni enregistrer l'objet en base de données
- (<classname>save()</classname>).</para>
- <example id="zend.db.table.row.serialize.unserializing.example">
- <title>Exemple de désérialisation d'un objet Row sérialisé.</title>
- <programlisting role="php"><![CDATA[
- $rowClone = unserialize($serializedRow);
- // Vous ne pouvez faire qu'une utilisation en lecture seule
- echo $rowClone->bug_description;
- ]]></programlisting>
- </example>
- <note>
- <title>Pourquoi ce mode déconnecté imposé ?</title>
- <para>Un objet sérialisé est une chaîne de caractère, humainement visible. Il est donc peu sécurisé d'y
- laisser un mot de passe vers un serveur de base de données. Le lecteur d'un objet Row sérialisé ne
- devrait pas pouvoir accéder à la base de données. De plus, une connexion à une base de données est un
- type non sérialisable par PHP (ressource).</para>
- </note>
- </sect3>
- <sect3 id="zend.db.table.row.serialize.set-table">
- <title>Reconnecter l'objet Row à la Table</title>
- <para>Il est bien entendu possible de reconnecter l'objet Row à la base de données, et plus précisément à la
- Table dont il fut issu. Utilisez la méthode <code>setTable()</code> et passez lui une instance héritant de
- <classname>Zend_Db_Table_Abstract</classname>. Une fois reconnecté, l'objet Row possède de nouveau un accès à la base
- de données, et n'est donc plus en mode lecture seule.</para>
- <example id="zend.db.table.row.serialize.set-table.example">
- <title>Exemple de réactivation d'un Row</title>
- <programlisting role="php"><![CDATA[
- $rowClone = unserialize($serializedRow);
- $bugs = new Bugs();
- // Reconnecte le Row à la table et donc, à la base de données
- $rowClone->setTable($bugs);
- // Maintenant il est possible de l'utiliser en mode écriture
- $rowClone->bug_status = 'FIXED';
- $rowClone->save();
- ]]></programlisting>
- </example>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.row.extending">
- <title>Étendre la classe Row</title>
- <para>Vous pouvez utilisez votre propre classe étendant <classname>Zend_Db_Table_Row_Abstract</classname>. Spécifiez votre
- classe dans la propriété protégée <code>$_rowClass</code> de la classe de votre Table, ou dans le tableau du
- constructeur de l'objet Table.</para>
- <example id="zend.db.table.row.extending.example">
- <title>Spécification d'une classe Row personnalisée</title>
- <programlisting role="php"><![CDATA[
- class MyRow extends Zend_Db_Table_Row_Abstract
- {
- // ...personnalisations
- }
- // Spécifie la classe de Row utilisée pour toutes les
- // instance de la classe de Table
- class Products extends Zend_Db_Table_Abstract
- {
- protected $_name = 'products';
- protected $_rowClass = 'MyRow';
- }
- // Ou pour une classe de table spécifique, via son constructeur
- $bugs = new Bugs(array('rowClass' => 'MyRow'));
- ]]></programlisting>
- </example>
- <sect3 id="zend.db.table.row.extending.overriding">
- <title>Initialisation et pré-traitements d'un Row</title>
- <para>Si vous avez un besoin spécifique d'implémenter une logique spéciale après la création d'une instance
- de Row, vous pouvez utiliser sa méthode <code>init()</code>, qui est appelée dans son constructeur, mais
- après que les méta données aient été calculées. <example id="zend.db.table.row.init.usage.example">
- <title>Exemple d'utilisation de la méthode init()</title>
- <programlisting role="php"><![CDATA[
- class MyApplicationRow extends Zend_Db_Table_Row_Abstract
- {
- protected $_role;
- public function init()
- {
- $this->_role = new MyRoleClass();
- }
- }
- ]]></programlisting>
- </example></para>
- </sect3>
- <sect3 id="zend.db.table.row.extending.insert-update">
- <title>Définir sa propre logique pour Insert, Update, et Delete dans Zend_Db_Table_Row</title>
- <para>La classe des Rows appelle les méthodes protégées <code>_insert()</code>, <code>_update()</code>, et
- <code>_delete()</code> avant d'effectuer chacune des opérations respectives <code>INSERT</code>,
- <code>UPDATE</code>, et <code>DELETE</code>. Il est donc possible de définir sa propre logique dans votre
- sous-classe de Row.</para>
- <para>Ci-dessous vous trouverez des exemples d'utilisation d'une logique personnalisée dans les classes de
- Row :</para>
- <example id="zend.db.table.row.extending.overriding-example1">
- <title>Exemple de logique personnalisée dans une classe de Row</title>
- <para>La logique personnelle peut donc être déportée dans une classe de Row qui ne s'appliquera qu'à
- certaines tables, et pas à d'autres. Sinon, la classe de Table utilise le Row par défaut.</para>
- <para>Par exemple, vous souhaitez historiser toutes les insertions sur une Table spécifique, mais
- uniquement si la configuration du site le permet :</para>
- <programlisting role="php"><![CDATA[
- class MyLoggingRow extends Zend_Db_Table_Row_Abstract
- {
- protected function _insert()
- {
- $log = Zend_Registry::get('database_log');
- $log->info(Zend_Debug::dump($this->_data,
- "INSERT: $this->_tableClass",
- false));
- }
- }
- // $loggingEnabled est une variable d'exemple qui définit si
- // l'historisation est activée ou pas
- if ($loggingEnabled) {
- $bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
- } else {
- $bugs = new Bugs();
- }
- ]]></programlisting>
- </example>
- <example id="zend.db.table.row.extending.overriding-example2">
- <title>Exemple d'une classe de Row qui historise les insertions de plusieurs tables</title>
- <para>En passant l'objet Row personnalisé à chacune des Tables concernées, alors vous n'aurez pas besoin
- de définir cette logique dans chacune des classes des Tables.</para>
- <para>Dans cet exemple, le code qui effectue l'historisation est identique à celui de l'exemple
- précédent.</para>
- <programlisting role="php"><![CDATA[
- class MyLoggingRow extends Zend_Db_Table_Row_Abstract
- {
- protected function _insert()
- {
- $log = Zend_Registry::get('database_log');
- $log->info(Zend_Debug::dump($this->_data,
- "INSERT: $this->_tableClass",
- false));
- }
- }
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_rowClass = 'MyLoggingRow';
- }
- class Products extends Zend_Db_Table_Abstract
- {
- protected $_name = 'products';
- protected $_rowClass = 'MyLoggingRow';
- }
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.extending.inflection">
- <title>Définir l'inflexion dans Zend_Db_Table_Row</title>
- <para>Il peut être intéressant de personnaliser l'accès aux colonnes de la table représentée par un résultat
- Row, plutôt que d'utiliser le nom des colonnes telles que définies dans le SGBDR sous-jacent. La
- transformation de l'un vers l'autre est appelée <emphasis>inflexion</emphasis>.</para>
- <para>Les classes Zend_Db n'utilisent pas l'inflexion par défaut. Voyez <xref
- linkend="zend.db.table.extending.inflection" /> pour plus de détails sur ce procédé.</para>
- <para>Ainsi si vous voulez utiliser l'inflexion, vous devez implémenter vous-même la transformation à
- effectuer en redéfinissant la méthode <code>_transformColumn()</code> dans votre classe de Row, et bien
- entendu utiliser cette classe de Row pour votre Table.</para>
- <example id="zend.db.table.row.extending.inflection.example">
- <title>Exemple d'utilisation de l'inflexion</title>
- <para>Ceci vous permet d'utiliser les accesseurs de votre Row de manière transformée. La classe de votre
- Row utilisera <code>_transformColumn()</code> pour changer le nom de la colonne appelée, avant de le
- faire correspondre à un nom dans la table réelle de la base de données.</para>
- <programlisting role="php"><![CDATA[
- class MyInflectedRow extends Zend_Db_Table_Row_Abstract
- {
- protected function _transformColumn($columnName)
- {
- $nativeColumnName = myCustomInflector($columnName);
- return $nativeColumnName;
- }
- }
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_rowClass = 'MyInflectedRow';
- }
- $bugs = new Bugs();
- $row = $bugs->fetchNew();
- // Utilisez des nom de colonnes CamelCase, l'inflecteur les
- // transformera alors pour vous afin d'établir la correspondance
- // avec les noms natifs des colonnes.
- $row->bugDescription = 'New description';
- ]]></programlisting>
- </example>
- <para>En revanche, c'est à vous d'écrire votre mécanisme d'inflexion.</para>
- </sect3>
- </sect2>
- </sect1>
|