12.Zend Framework 2 et 3

12.7.Les bases de données

12.7.3.Construire la requête SQL

12.7.3.1.Introduction

Dans le chapitre précédent nous avons vu comment configurer et instancier un objet Zend\Db\Adapter\Adapter nécessaire à l'interfaçage avec une base de données via Zend Framework. Nous avons vu qu'il est possible d'exécuter des requêtes SQL de façon "basique" en écrivant la requête sous la forme d'une chaîne de caractères. Si cette méthode à l'avantage de fonctionner en toutes circonstances, elle a l'inconvient de devoir éventuellement construire une requête SQL différente selon la base de données utilisée. Zend Framework propose donc une solution pour décrire la requête de façon différente, via appel à des methodes et classes dédiées. C'est la bibliothèque ZF qui a ensuite la charge de reconstruire la requête SQL en l'adaptant au serveur de base de données utilisé.
Pour cela, le module zendframework/zend-db contient la classe Zend\Db\Sql\Sql qui prend pour paramètre un objet Adapter (le même que vu précédemment) et qui propose les méthodes insert(), update(), delete() et select().

12.7.3.2.insert()

Le code PHP de construction de la requête d'insertion aura la forme suivante:
<?php
use Zend\Db\Adapter\Adapter;
use Zend\Db\Sql\Sql;

$db = new Adapter($config); // $config à définir
$sql = new Sql($db);

$nomTable = 'matable';
$valeurs = array('monchamp1' => 'maValeur');

$requete = $sql->insert()
               ->into($nomTable)
               ->values($valeurs);
// Reste à exécuter la requête
La requête se construit en appelant la méthode insert() puis s'enrichit en précisant le nom de la table concernée via into() et la description des champs de la ligne à ajouter via un tableau associatif (nom du champ => valeur) passé en paramètre de values().
Ces valeurs peuvent être prédéfinies (des variables, des constantes ou des chaînes écrites en dur comme dans l'exemple) ou bien le résultat d'appels de fonctions SQL. Dans ce dernier cas, il faut faire appel à l'objet Zend\Db\Sql\Expression[comment?].
La méthode proposée est celle qui se rapproche le plus de la forme SQL mais elle peut être compactée en omettant la partie into() et en passant le nom de la table dans la méthode insert() de la façon suivante
<?php
$requete = $sql->insert($nomTable)
               ->values($valeurs);

12.7.3.3.update()

Le code PHP de construction de la requête de mise à jour aura la forme suivante:
<?php
use Zend\Db\Adapter\Adapter;
use Zend\Db\Sql\Sql;

$db = new Adapter($config); // $config à définir
$sql = new Sql($db);

$nomTable = 'matable';
$valeurs = array('monchamp1' => 'maNouvelleValeur');

$requete = $sql->update()
               ->table($nomTable)
               ->set($valeurs);
// REM: On ajoutera probablement une clause where
// Reste à exécuter la requête
La requête se construit en appelant la méthode update() puis s'enrichit en précisant le nom de la table concernée via table() et les nouvelles valeurs des champs des lignes à modifier via un tableau associatif (nom du champ => valeur) passé en paramètre de set().
Tout comme pour select(), il est possible d'insérer des valeurs qui sont le résultat d'appels de fonctions SQL. Pour cela il faut faire appel à l'objet Zend\Db\Sql\Expression[comment?].
Comme décrit plus loin, il est bien évidemment possible de restreindre la liste des lignes modifiées via une méthode where()[comment?].
Là, aussi, l'écriture peut être compactée, en omettant cette fois-ci la partie table() et en passant le nom de la table dans la méthode update() de la façon suivante
<?php
$requete = $sql->update($nomTable)
               ->set($valeurs);

12.7.3.4.delete()

Le code PHP de construction de la requête de suppression aura la forme suivante:
<?php
use Zend\Db\Adapter\Adapter;
use Zend\Db\Sql\Sql;

$db = new Adapter($config); // $config à définir
$sql = new Sql($db);

$nomTable = 'matable';

$requete = $sql->delete()
               ->from($nomTable);
// REM: On ajoutera probablement une clause where
// Reste à exécuter la requête
La requête se construit en appelant la méthode delete() puis s'enrichit en précisant le nom de la table concernée via from().
Comme décrit plus loin, il est bien évidemment possible de restreindre la liste des lignes supprimées via une méthode where()[comment?].
L'écriture compacte est cette fois
<?php
$requete = $sql->delete($nomTable);

12.7.3.5.select()

12.7.3.5.1.from()

Pour une requête de sélection on pourra s'appuyer sur le bout de code suivant:
<?php
use Zend\Db\Adapter\Adapter;
use Zend\Db\Sql\Sql;

$db = new Adapter($config); // $config à définir
$sql = new Sql($db);

$nomTable = 'matable';

$requete = $sql->select()
               ->from($nomTable);
// REM: On ajoutera probablement une clause where
// Reste à exécuter la requête et parcourir les résultats
Si, encore une fois, nous vous présentons la façon de faire qui se rapproche le plus de la forme SQL sachez qu'elle peut être simplifiée de la façon suivante
<?php
$requete = $sql->select($nomTable);

12.7.3.5.2.columns()

Pour définir la liste des champs à retourner nous nous appuierons sur la méthode columns() en passant en paramètre au choix, soit:
  • Un tableau indexé des données attendus
  • Un tableau associatif où les clés seront les noms sous lesquels les champs doivent être retournés et les valeurs les données attendues
<?php
$requete = $sql->select()
               ->columns(array('champ1', 'champ2'))
               ->from($nomTable);
// Equivalent de SELECT champ1, champ2 FROM ...

$requete = $sql->select()
               ->columns(array('alias1' => 'champ1',
                               'alias2' => 'champ2'))
               ->from($nomTable);
// Equivalent de SELECT champ1 AS alias1, champ2 as alias2 FROM ...
Dans ce cas, les données peuvent être soit directement les champs (comme dans l'exemple), soit le résultat de fonctions SQL à la condition de faire appel à l'objet Zend\Db\Sql\Expression[comment?].

12.7.3.5.3.where()

Quasi inévitablement, nous aurons besoin de compléter la requête pour filtrer les lignes de résultat à remonter via la méthode where()[comment?].

12.7.3.5.4.order()

Pour trier les lignes retournées nous ferons appel à la méthode order() en passant en paramètre la chaîne SQL "classique" pour les tris ex: 'champ1, champ2' ou 'champ1 ASC, champ2 DESC'.
<?php
$requete = $sql->select()
               ->from($nomTable)
               ->order('champ1, champ2 DESC');

12.7.3.5.5.limit() et offset()

Pour limiter le nombre de résultats retournés et l'index du premier résultat retourné les équivalents des instructions LIMIT et OFFSET existent sous la forme de méthodes limit() offset()en passant en paramètre la chaîne SQL "classique" pour les tris ex: 'champ1, champ2' ou 'champ1 ASC, champ2 DESC'.
<?php
$requete = $sql->select()
               ->from($nomTable)
               ->limit(20)
               ->offset(10);
// Retourne 20 résultats maximum en commençant au 11ème (10+1)

12.7.3.5.6.quantifier() et DISTINCT

Si vous souhaitez faire une requête de type DISTINCT (afin de ne pas remonter plusieurs lignes identiques) vous devez faire appel à la méthode quatifier() en passant pour paramètre Where::QUANTIFIER_DISTINCT
<?php
$requete = $sql->select()
               ->quantifier(Where::QUANTIFIER_DISTINCT)
               ->from($nomTable);

12.7.3.5.7.group()

L'équivalent de GROUP BY se fait via la méthode group() à laquelle on passe en paramètre un tableau des champs (ou alias) tels que (éventuellement) précisés via columns() sur lesquels le regroupement doit se faire.
<?php
$requete = $sql->select()
               //-> Cf. columns() et Expression pour des COUNT, MAX, SUM ...
               ->from($nomTable)
               ->group(array('champ1', 'champ2'));

12.7.3.5.8.join() et LEFT JOIN, INNER JOIN, etc.

Les classes ZF permettent également de réaliser des jointures entre les tables pour cela, il y a la méthode join(). Cette méthode attend les paramètres suivants:
  • Le nom de la table avec laquelle la jointure doit se faire
  • Les conditions de la jointure sous forme d'une chaîne de caractère (ex: 'table1.champ1 = table2.champ2') ou sous forme d'un objet Expression pour les cas plus complexes
  • Optionnel: Un tableau des champs (de la seconde table) à retourner. Par défaut Where::SQL_START, autrement dit '*' soit l'ensemble des champs de la seconde table sont retournés
  • Optionnel: Le type de jointure (par défaut Where::JOIN_INNER):
    • Where::JOIN_INNER ('inner')
    • Where::JOIN_OUTER ('outer')
    • Where::JOIN_LEFT ('left')
    • Where::JOIN_RIGHT ('right')
    • Where::JOIN_RIGHT_OUTER ('right outer')
    • Where::JOIN_LEFT_OUTER ('left outer')
<?php
$requete = $sql->select()
               ->from('table1')
               ->join('table2', 'table1.champ1=table2.champ2', array('champ2'), Where::JOIN_LEFT);
// SELECT table1.*, table2.champ2 FROM table1 LEFT JOIN table2 ON table1.champ1=table2.champ2