13.Zend Framework 2 et 3

13.7.Les bases de données

13.7.5.Parcourir les résultats de la requête SQL

13.7.5.1.Introduction

Nous avons vu dans les chapitres précédents comment construire une requête SQL avec Zend Framework[comment?], nous avons vu comment l'exécuter[comment?]. Reste, dans le cas d'une requête SELECT, à voir comment parcourir les résultats de la requête. C'est l'objet de ce chapitre.
Que la requête ait été exécutée via la méthode query() de la classe Zend\Db\Adapter\Adapter ou execute() d'un classe implémentant Zend\Db\Apdater\Driver\StatementInterface le principe est le même, l'objet retourné est un itérateur (i.e. implémente l'interface Iterator). Il est par conséquent possible, entre autres, de:
  • Parcourir l'ensemble des éléments avec une boucle foreach
  • Faire appel à la méthode current() pour récupérer l'élément sur lequel le pointeur est actuellement positionné
  • Faire appel à la méthode next() pour passer à l'élément suivant (et le récupérer)
En revanche, c'est dans les détails que nous trouverons quelques différences puisque query() retourne un objet Zend\Db\ResultSet\ResultSet tandis que execute() retourne un objet Zend\Db\Adapter\Driver\ResultInterface.

13.7.5.2.Parcours avec foreach

Comme on peut le voir dans les exemples ci-dessous: Que ce soit avec query()
<?php
// On supposera les variables $sql, $db, $nomTable, etc. définies précédemment
$requete = $sql->select($nomTable);
// La requête (objet Sql) sera convertie en chaîne de caractères
$sqlStr = $sql->buildSqlString($requete);
$lignes = $db->query($sqlStr, Adapter::QUERY_MODE_EXECUTE);

// Boucle sur l'ensemble des enregistrements
foreach ($lignes as $ligne) {
    // $ligne contient les valeurs des différents champs d'un enregistrement retourné par la requête.
    // Ainsi la valeur du champ 'monchamp' est disponible dans $ligne['monchamp'].
    echo $ligne['monchamp']."\n";
}
ou avec execute()
<?php
// On supposera les variables $sql, $db, $nomTable, etc. définies précédemment
$requete = $sql->select($nomTable);
// La requête (objet Sql) sera convertie en "requête préparée"
$stmt = $sql->prepareStatementForSqlObject($requete);
$lignes = $stmt->execute();

// Boucle sur l'ensemble des enregistrements
foreach ($lignes as $ligne) {
    // $ligne contient les valeurs des différents champs d'un enregistrement retourné par la requête.
    // Ainsi la valeur du champ 'monchamp' est disponible dans $ligne['monchamp'].
    echo $ligne['monchamp']."\n";
}
la façon de parcourir l'ensemble des enregistrements avec foreach() est véritablement identique.
warning Attention toutefois, la nature des éléments parcourus diffère entre les 2 cas de figure. Dans le cas query() chaque élément rétourné par l'itérateur est un objet ArrayObject. Dans le cas execute() l'élément retourné est un simple tableau (type array).
Dans les 2 cas, il est possible de récupérer la valeur d'un champ en utilisant l'élément retourné comme un simple tableau indexé (c'est à dire en précisant entre crochet le nom du champ pour lequel on souhaite connaitre la valeur associée) en revanche vous pourriez avoir des surprises en tentant d'appliquer, sur les résultats de query() des fonctions habituellements utilisées sur des tableaux. Si des fonctions comme array_key_exists() peuvent s'appliquer à des objets ArrayObject cela n'est pas (encore?) le cas, par exemple, de la fonction array_keys()

13.7.5.3.Parcours avec current() et next()

Pour parcourir tout ou partie des enregistrements retourné par la requête il est également possible de faire appel à la fonction current() pour récupérer le premier resultat puis faire des appels successifs à next() pour les résultats suivants.
Comme expliqué dans le chapitre précédent (foreach) la nature des éléments retournés par l'itérateur diffère d'un cas à l'autre. Dans le cas query() c'est un ArrayObject qui est retourné, dans le cas execute() c'est un simple tableau (type array) qui est retourné. Les mêmes remarques s'appliquent donc.
L'autre différence majeure entre les 2 cas de figure concerne la valeur retour lorsque le dernier enregistrement a été atteint (ou plutôt dépassé). En effet, dans le cas query() l'itérateur retourne null alors que dans le cas execute() il retournera false.
Ce qui donne une boucle de parcours comme suit pour query()
<?php
$requete = $sql->select($nomTable);
// La requête (objet Sql) sera convertie en chaîne de caractères
$sqlStr = $sql->buildSqlString($requete);
$lignes = $db->query($sqlStr, Adapter::QUERY_MODE_EXECUTE);

// Lecture du premier enregistrement
$ligne = $lignes->current();
while (null !== $ligne) {
    // Tant qu'il y a effectivement un enregistrement (i.e !== null) on continue de parcourir
    // les enregistrements.
    // $ligne contient les valeurs des différents champs d'un enregistrement retourné par la requête.
    // Ainsi la valeur du champ 'monchamp' est disponible dans $ligne['monchamp'].
    echo $ligne['monchamp']."\n";
    // on passe à l'enregistrement suivant
    $ligne = $lignes->next();
}
et comme suit pour execute()
<?php
$requete = $sql->select($nomTable);
// La requête (objet Sql) sera convertie en "requête préparée"
$stmt = $sql->prepareStatementForSqlObject($requete);
$lignes = $stmt->execute();

// Lecture du premier enregistrement
$ligne = $lignes->current();
while (false !== $ligne) {
    // Tant qu'il y a effectivement un enregistrement (i.e !== false) on continue de parcourir
    // les enregistrements.
    // $ligne contient les valeurs des différents champs d'un enregistrement retourné par la requête.
    // Ainsi la valeur du champ 'monchamp' est disponible dans $ligne['monchamp'].
    echo $ligne['monchamp']."\n";
    // on passe à l'enregistrement suivant
    $ligne = $lignes->next();
}