13.Zend Framework 2 et 3
13.7.Les bases de données
13.7.3.Construire la requête SQL
13.7.3.7.Expression
13.7.3.7.1.Introduction
L'objet Zend\Db\Sql\Expression est un recours indispensable lorsqu'il s'agit d'insérer, récupérer, joindre des champs ou des tables de base de données non pas via une valeur "pré-définie" comme dans les exemples simplifiés des paragraphes précédents mais via des structures plus complexes ou des appels à des fonctions SQL.
Le principe de fonctionnement est plutôt simple. Il suffit de se dire que lorsque Zend Framework construit une requête SQL, s'il rencontre une chaîne de caractère alors il l'englobe entre des délimiteurs de chaînes adaptés à la base de données (apostrophes ou guillemets). Ainsi, si l'on précise que l'on veut faire un insert() en passant dans values() un tableau array('monchamp' => 'mavaleur'), ZF construira une requête comme suit INSERT INTO ... (monchamp) VALUES ('mavaleur') en prenant soit de bien mettre 'mavaleur' entre apostrophes. Si c'est bien ce que l'on souhaite dans cette situation, il peut en être différent si l'on souhaite faire appel à une fonction ou instruction SQL. Ainsi, si l'on souhaire insérer la date courante via CURRENT_DATE et que l'on passe dans values() le tableau suivant array('monchamp' => 'CURRENT_DATE'), la requête construite par Zend Framework sera INSERT INTO ... (monchamp) VALUES ('CURRENT_DATE') qui aura pour effet de stocker non pas la date courante mais la chaîne de caractères 'CURRENT_DATE'. En fait, la requête que nous souhaitons créer devra plutôt ressembler à INSERT INTO ... (monchamp) VALUES (CURRENT_DATE) (donc sans les apostrophes de part et d'autre de l'instruction SQL CURRENT_DATE). Il faut donc préciser à ZF que la valeur passée est en fait une expression comme suit: array('monchamp' => new Expression('CURRENT_DATE')). Grâce à cela, la chaîne ne sera pas entourée de délimiteur de chaîne de caractère et la requête aura bien la forme attendue.
13.7.3.7.2.Application sur le valeurs insérées ou mises à jour via insert() et update()
<?php
use Zend\Db\Adapter\Adapter;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Expression;
$db = new Adapter($config); // $config à définir
$sql = new Sql($db);
$nomTable = 'matable';
$valeurs = array('madate' => new Expression('CURRENT_DATE'),
'monchamp' => 'mavaleur');
$requete = $sql->insert()
->into($nomTable)
->values($valeurs);
// Equivalent à INSERT INTO ... (madate, monchamp) VALUES (CURRENT_DATE, 'mavaleur')
// Reste à exécuter la requête
Cela peut également être utilisé dans une requête update() pour modifier la valeur d'un champ sur la base d'un ou plusieurs autres champs
<?php
// use Zend\Db\Sql\Expression;
$valeurs = array('monchamp1' => new Expression('UPPER(monchamp1)'),
'monchamp2' => 'mavaleur');
$requete = $sql->update()
->table($nomTable)
->set($valeurs);
// Equivalent à UPDATE ... SET monchamp1=UPPER(monchamp1), monchamp2='mavaleur'
// Reste à exécuter la requête
13.7.3.7.3.Application sur les valeurs retournées via select()
<?php
// use Zend\Db\Sql\Expression;
$requete = $sql->select()
->columns(array('champ',
'champ_maj' => new Expression('UPPER(champ)')))
->from($nomTable);
// Equivalent à SELECT champ, UPPER(champ) AS champ_maj FROM ...
// Reste à exécuter la requête et parcourir les résultats
13.7.3.7.4.Application sur les filtres where()
Il en va de même avec la critères de recherche définis via la methode where() lors des appels à update() et select().
Dans l'exemple suivant nous recherchons les enregistrements pour lesquels le champ 'champ' vaut 'valeur' et le champ annee est égal à l'année courante, celle-ci étant déterminée par l'appel aux fonctions SQL SUBSTR et CURRENT_DATE.
<?php
// use Zend\Db\Sql\Expression;
$where = array('annee' => new Expression('SUBSTR(CURRENT_DATE, 1, 4)'),
'champ' => 'valeur');
$requete = $sql->select()
->from($nomTable)
->where($where);
// Equivalent à SELECT ... WHERE annee=SUBSTR(CURRENT_DATE, 1, 4) AND champ='valeur'
// Reste à exécuter la requête et parcourir les résultats
13.7.3.7.5.Application sur les jointures join()
Pour des jointures avec des critères simples du type 'table1.champ1=table2.champ2' pas besoin d'avoir recours à Expression mais pour le coup, lorsqu'il s'agit de comparer à une chaîne de caractères la requête construite ne pourra pas être valide sans Expression.
<?php
// use Zend\Db\Sql\Expression;
$requete = $sql->select()
->from('table1')
->join('table2',
new Expression('table1.champ1 = table2.champ2 AND table2.champ3=\'toto\''),
'*',
'left');
// Equivalent à
// SELECT ... FROM table1 LEFT JOIN table2 ON table1.champ1 = table2.champ2 AND table2.champ3='toto'
// Reste à exécuter la requête et parcourir les résultats