<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 17175 -->
<!-- Reviewed: no -->
<sect1 id="zend.db.table.rowset">
    <title>Zend_Db_Table_Rowset</title>

    <sect2 id="zend.db.table.rowset.introduction">
        <title>Introduction</title>

        <para>
            Lorsque vous effectuez une requête avec une classe de Table en utilisant
            <methodname>find()</methodname> ou <methodname>fetchAll()</methodname> , le résultat retourné est alors un objet
            de type <classname>Zend_Db_Table_Rowset_Abstract</classname>. Un Rowset est un conteneur
            d'objets descendants de <classname>Zend_Db_Table_Row_Abstract</classname>. Vous pouvez
            itérer à travers ce conteneur et accéder aux objet Row individuellement, en lecture ou
            écriture bien entendu.
        </para>
    </sect2>

    <sect2 id="zend.db.table.rowset.fetch">
        <title>Récupérer un Rowset</title>

        <para>
            <classname>Zend_Db_Table_Abstract</classname> possède des méthodes
            <methodname>find()</methodname> et <methodname>fetchAll()</methodname>, chacune retourne un objet de type
            <classname>Zend_Db_Table_Rowset_Abstract</classname>.
        </para>

        <example id="zend.db.table.rowset.fetch.example">
            <title>Exemple de récupération d'un rowset</title>

            <programlisting language="php"><![CDATA[
$bugs   = new Bugs();
$rowset = $bugs->fetchAll("bug_status = 'NEW'");
]]></programlisting>
        </example>
    </sect2>

    <sect2 id="zend.db.table.rowset.rows">
        <title>Atteindre les Rows depuis un Rowset</title>

        <para>
            L'objet Rowset en lui-même n'est pas très intéressant au regard des objets Rows
            qu'il contient, qui eux, le sont bien plus.
        </para>

        <para>
            Un requête légitime peut retourner zéro enregistrement, donc zéro Rows. De ce
            fait, un objet Rowset peut contenir zéro objet Row. Comme
            <classname>Zend_Db_Table_Rowset_Abstract</classname> implémente l'interface
            <code>Countable</code>, vous pouvez utiliser la fonction <acronym>PHP</acronym> <methodname>count()</methodname>
            dessus, pour compter les Rows qu'il contient.
        </para>

        <example id="zend.db.table.rowset.rows.counting.example">
            <title>Compter les Rows dans un Rowset</title>

            <programlisting language="php"><![CDATA[
$rowset   = $bugs->fetchAll("bug_status = 'FIXED'");

$rowCount = count($rowset);

if ($rowCount > 0) {
    echo "$rowCount rows trouvés";
} else {
    echo 'Pas de rows pour cette requête';
}
]]></programlisting>
        </example>

        <example id="zend.db.table.rowset.rows.current.example">
            <title>Lecture d'un simple Row depuis un Rowset</title>

            <para>
                La façon la plus simple d'accéder à un Row depuis l'objet Rowset est
                d'utiliser la méthode <methodname>current()</methodname>. C'est tout à fait adapté lorsque le
                Rowset ne contient qu'un résultat (Row).
            </para>

            <programlisting language="php"><![CDATA[
$bugs   = new Bugs();
$rowset = $bugs->fetchAll("bug_id = 1");
$row    = $rowset->current();
]]></programlisting>
        </example>

        <para>
            Si le Rowset ne contient aucun Row, <methodname>current()</methodname> retourne
            <constant>NULL</constant>.
        </para>

        <example id="zend.db.table.rowset.rows.iterate.example">
            <title>Itération à travers un Rowset</title>

            <para>
                Les objets descendants de <classname>Zend_Db_Table_Rowset_Abstract</classname>
                implémentent l'interface <code>Iterator</code>, ce qui veut dire qu'ils peuvent être
                utilisés dans la structure <acronym>PHP</acronym> <code>foreach</code>. Chaque valeur récupérée
                représente alors un objet de <classname>Zend_Db_Table_Row_Abstract</classname> qui
                correspond à un enregistrement dans la table.
            </para>

            <programlisting language="php"><![CDATA[
$bugs = new Bugs();

// récupère tous les enregistrements de la table
$rowset = $bugs->fetchAll();

foreach ($rowset as $row) {

    // affiche 'Zend_Db_Table_Row' par défaut
    echo get_class($row) . "\n";

    // lit une colonne dans le résultat Row
    $status = $row->bug_status;

    // modifie une colonne dans le résultat courant
    $row->assigned_to = 'mmouse';

    // Enregistre en base de données
    $row->save();
}
]]></programlisting>
        </example>

        <example id="zend.db.table.rowset.rows.seek.example">
            <title>Déplacement vers une position précise dans le Rowset</title>

            <para>
                <code>SeekableIterator</code> vous permet de vus déplacer à une position
                précise dans l'itérateur. Utilisez pour ceci la méthode <methodname>seek()</methodname>. Elle
                prend en paramètre un entier représentant le numéro de la position désirée.
                N'oubliez pas que le premier enregistrement est stocké à la position zéro. Si vous
                spécifiez une position qui n'existe pas, une exception sera levée. Vous devriez
                utiliser <methodname>count()</methodname> pour vérifier le nombre d'enregistrements Rows
                présents.
            </para>

            <programlisting language="php"><![CDATA[
$bugs = new Bugs();

// récupère tous les enregistrements de la table
$rowset = $bugs->fetchAll();

// Déplace l'itérateur à l'enregistrement 8 (le neuvième donc) :
$rowset->seek(8);

// récupèration de cet enregistrement
$row9 = $rowset->current();

// et utilisation
$row9->assigned_to = 'mmouse';
$row9->save();
]]></programlisting>
        </example>

        <para>
            <methodname>getRow()</methodname> permet de retourner directement un enregistrement en
            fonction de sa position dans l'itérateur Rowset. Le premier paramètre est un entier
            représentant cette position. Le second paramètre est optionnel, et indique si oui ou non
            l'itérateur doit rester sur cette position, après avoir retourné le Row correspondant.
            Par défaut, il est à <constant>FALSE</constant>. Cette méthode retourne donc un objet
            <classname>Zend_Db_Table_Row</classname>. Si la position demandée n'existe pas, une
            exception est levée :
        </para>

        <programlisting language="php"><![CDATA[
$bugs = new Bugs();

// récupère tous les enregistrements de la table
$rowset = $bugs->fetchAll();

// récupère le neuvième enregistrement immédiatement
$row9->getRow(8);

// utilisation de l'enregistrement récupéré :
$row9->assigned_to = 'mmouse';
$row9->save();
]]></programlisting>

        <para>
            Dès que vous avez accès à un objet individuel Row, vous pouvez le piloter comme
            présenté dans la section <xref linkend="zend.db.table.row" />.
        </para>
    </sect2>

    <sect2 id="zend.db.table.rowset.to-array">
        <title>Récupérer un Rowset en tant que tableau (Array)</title>

        <para>
            Vous pouvez accéder à toutes les données d'un Rowset au moyen d'un tableau <acronym>PHP</acronym>
            avec la méthode <methodname>toArray()</methodname>. Ce tableau possède deux dimensions. Chaque
            entrée du tableau représente un tableau de l'objet Row. Les clés sont les noms des
            champs, et les valeurs leurs valeurs.
        </para>

        <example id="zend.db.table.rowset.to-array.example">
            <title>Utiliser toArray()</title>

            <programlisting language="php"><![CDATA[
$bugs   = new Bugs();
$rowset = $bugs->fetchAll();

$rowsetArray = $rowset->toArray();

$rowCount = 1;
foreach ($rowsetArray as $rowArray) {
    echo "row #$rowCount:\n";
    foreach ($rowArray as $column => $value) {
        echo "\t$column => $value\n";
    }
    ++$rowCount;
    echo "\n";
}
]]></programlisting>
        </example>

        <para>
            Le tableau retourné par <methodname>toArray()</methodname> n'est pas une référence. Le
            modifier ne modifiera en aucun cas les données réelles dans la base de données.
        </para>
    </sect2>

    <sect2 id="zend.db.table.rowset.serialize">
        <title>Sérialisation et Désérialisation d'un Rowset</title>

        <para>
            Les objets de type <classname>Zend_Db_Table_Rowset_Abstract</classname> sont
            sérialisables. De la même manière que vous sérialisez un objet Row individuel, le Rowset
            est sérialisable et désérialisable.
        </para>

        <example id="zend.db.table.rowset.serialize.example.serialize">
            <title>Sérialiser d'un Rowset</title>

            <para>
                Utilisez simplement la fonction <acronym>PHP</acronym> <methodname>serialize()</methodname> pour créer une
                chaîne de caractères représentant votre objet Rowset.
            </para>

            <programlisting language="php"><![CDATA[
$bugs   = new Bugs();
$rowset = $bugs->fetchAll();

// Convertit l'objet en sa forme sérialisée
$serializedRowset = serialize($rowset);

// Maintenant vous pouvez écrire $serializedRowset
// dans un fichier, etc.
]]></programlisting>
        </example>

        <example id="zend.db.table.rowset.serialize.example.unserialize">
            <title>Désérialisation d'un objet Rowset sérialisé</title>

            <para>Utilisez simplement la fonction <acronym>PHP</acronym> <methodname>unserialize()</methodname>.</para>

            <para>
                Notez que l'objet retourné fonctionne alors en mode
                <emphasis>déconnecté</emphasis>. Vous pouvez itérer à travers, et lire les objets
                Row qu'il contient, mais vous ne pouvez plus faire intervenir la base de données, ni
                changer de valeurs dans les Rows.
            </para>

            <programlisting language="php"><![CDATA[
$rowsetDisconnected = unserialize($serializedRowset);

// Maintenant vous pouvez utiliser l'objet, mais en lecture seule
$row = $rowsetDisconnected->current();
echo $row->bug_description;
]]></programlisting>
        </example>

        <note>
            <title>Pourquoi ce mode déconnecté imposé&#160;?</title>

            <para>
                Un objet sérialisé est une chaîne de caractère, humainement visible. Il est
                donc peut sécurisé d'y laisser un mot de passe vers un serveur de base de données.
                Le lecteur d'un objet Rowset 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 <acronym>PHP</acronym> (ressource).
            </para>
        </note>

        <para>
            Il est bien entendu possible de reconnecter l'objet Rowset à la base de données,
            et plus précisément à la Table dont il fut issu. Utilisez la méthode
            <methodname>setTable()</methodname> et passez lui une instance héritant de
            <classname>Zend_Db_Table_Abstract</classname>. Une fois reconnecté, l'objet Rowset
            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.rowset.serialize.example.set-table">
            <title>Réactivation d'un Rowset</title>

            <programlisting language="php"><![CDATA[
$rowset = unserialize($serializedRowset);

$bugs = new Bugs();

// Reconnecte le rowset à une table, et par
// conséquent, à la connexion vers la base de données active
$rowset->setTable($bugs);

$row = $rowset->current();

// Maintenant vous pouvez modifier les objets Row et les sauvegarder
$row->bug_status = 'FIXED';
$row->save();
]]></programlisting>
        </example>

        <para>
            Réactiver un Rowset avec <methodname>setTable()</methodname> réactive tous les Rows le
            composant.
        </para>
    </sect2>

    <sect2 id="zend.db.table.rowset.extending">
        <title>Étendre la classe Rowset</title>

        <para>
            Vous pouvez utilisez votre propre classe étendant
            <classname>Zend_Db_Table_Rowset_Abstract</classname>. Spécifiez votre classe dans la
            propriété protégée <varname>$_rowsetClass</varname> de la classe de votre Table, ou dans le
            tableau du constructeur de l'objet Table.
        </para>

        <example id="zend.db.table.rowset.extending.example">
            <title>Spécifier sa propre classe de Rowset</title>

            <programlisting language="php"><![CDATA[
class MyRowset extends Zend_Db_Table_Rowset_Abstract
{
    // ...personnalisations
}

// Spécifie la classe de Rowset utilisée pour toutes les
// instance de la classe de Table
class Products extends Zend_Db_Table_Abstract
{
    protected $_name = 'products';
    protected $_rowsetClass = 'MyRowset';
}

// Ou pour une classe de table spécifique, via son constructeur
$bugs = new Bugs(array('rowsetClass' => 'MyRowset'));
]]></programlisting>
        </example>

        <para>
            En temps normal, la classe standard Zend_Db_Rowset est suffisante. Cependant, il
            peut être judicieux de rajouter de la logique dans son Rowset, pour une table précise.
            Par exemple, une nouvelle méthode pourrait effectuer des calculs.
        </para>

        <example id="zend.db.table.rowset.extending.example-aggregate">
            <title>Exemple d'une classe Rowset personnalisée avec une nouvelle méthode</title>

            <programlisting language="php"><![CDATA[
class MyBugsRowset extends Zend_Db_Table_Rowset_Abstract
{
    /**
     * Trouve les Rows dans le Rowset courant avec la plus grande
     * valeur pour la colonne 'updated_at'.
     */
    public function getLatestUpdatedRow()
    {
        $max_updated_at = 0;
        $latestRow = null;
        foreach ($this as $row) {
            if ($row->updated_at > $max_updated_at) {
                $latestRow = $row;
            }
        }
        return $latestRow;
    }
}

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';
    protected $_rowsetClass = 'MyBugsRowset';
}
]]></programlisting>
        </example>
    </sect2>
</sect1>