Section: Exécuter des requêtes
« Profils et configuration | ^ jDb : accéder à une base de données SQL | Schémas et autres outils » |
− Table des matières
L'objet jDbConnection ¶
Une fois le fichier de configuration écrit, vous pouvez accéder aux bases de données.
La première chose à faire est de récupérer un objet jDbConnection :
$cnx = jDb::getConnection();
La méthode getConnection()
permet de récupérer un objet de type jDbConnection
(ou jDbPDOConnection
héritant de PDO, si vous utilisez PDO, ils ont toutefois la
même API). Cette méthode accepte un paramètre facultatif : le nom du profil à
utiliser. S'il n'est pas indiqué, celui déclaré par défaut sera utilisé.
Pour construire les requêtes, vous avez une méthode importante à connaître si vous
n'utilisez pas les requêtes préparées : quote()
, qui permet d'échapper
certains caractères dans les valeurs que vous voulez insérer dans vos requêtes.
Elle évite dans une certaine mesure les problèmes comme l'injection SQL.
Un autre ami de quote()
est quote2()
utilisé sur les colonnes binaires
et s'utilise de la même façon que quote()
.
$sql = "INSERT INTO users (nom,prenom) VALUES";
$sql .=" (". $cnx->quote("de l'ombre") .",".$cnx->quote('robert').")";
Notez que la méthode quote()
encadre la valeur avec des quotes.
Si vous avez besoin de construire votre requête en utilisant des noms de champs ou de tables
qu'il faut encadrer avec le caractère adéquate selon le type de base de données,
vous pouvez utiliser la méthode encloseName()
:
$table = 'users';
$sql = "INSERT INTO ".$cnx->encloseName($table)." (nom, prenom) VALUES";
$sql .=" (". $cnx->quote("de l'ombre") .",".$cnx->quote('robert').")";
Pour exécuter des requêtes, il y a principalement deux méthodes, exec()
et query()
.
exec ¶
exec
doit être utilisé pour les requêtes qui ne renvoient pas de résultat
(UPDATE, INSERT, DELETE...)
. cette méthode renvoie juste le nombre de lignes
concernées par la requête. Exemple :
$cnx = jDb::getConnection();
$cnx->exec("INSERT INTO users (nom,prenom) VALUES('dupont','toto')");
query ¶
query
est fait pour les requêtes qui renvoient des résultats, vides ou pas
(SELECT ou procédures stockées). La méthode renvoie alors un objet
jDbResultSet
.
Voici un exemple rapide :
$cnx = jDb::getConnection();
$rs = $cnx->query('SELECT nom, prenom FROM users');
$result = '';
while ($record = $rs->fetch()) {
$result .= 'nom = '.$record->nom.' prenom = '.$record->prenom."\n";
}
limitQuery ¶
Vous pouvez faire des requêtes qui récupèrent un nombre limité
d'enregistrements. Vous utiliserez alors la méthode limitQuery
:
$cnx = jDb::getConnection();
$rs = $cnx->limitQuery('SELECT nom, prenom FROM users', 5, 10);
$result = '';
while ($record = $rs->fetch()) {
$result .= 'nom = '.$record->nom.' prenom = '.$record->prenom."\n";
}
Le premier paramètre est la requête. Le deuxième est le numéro, dans la liste des résultats, du premier enregistrement à récupérer. Le troisième paramètre est le nombre d'enregistrements à récupérer.
requêtes préparées ¶
Vous pouvez utiliser des requêtes préparées. C'est d'ailleurs plus sécurisé quand il faut injecter des paramètres dans la requete SQL. Tous les drivers fournis avec Jelix supportent les requêtes préparées, excepté "mssql".
L'API est similaire à PDO : une méthode prepare
permet d'indiquer
la requête. Celle-ci peut avoir des paramètres nommés, commençant par ":".
La méthode renvoi un objet de type jDbResultSet
.
$stmt = $cnx->prepare('INSERT INTO `labels_test` (`key`,`lang` ,`label`) VALUES (:k, :lg, :lb)');
Sur cet objet jDbResultSet, on peut indiquer la valeur de chaque paramètre
avec la méthode bindParam()
ou bindValue()
. bindParam()
permet de
donner une valeur de variable, tandis que bindValue()
permet d'indiquer
directement une valeur PHP. Vous devez indiquer à ces deux methodes, le type
de la valeur ou de la variable, avec l'une des constantes PDO::PARAM_*
.
Par défaut, c'est PDO::PARAM_STR
, donc la valeur doit être une chaîne.
$bind = $stmt->bindParam('lg', $lang);
$bind = $stmt->bindParam('k', $key, PDO::PARAM_INT);
$bind = $stmt->bindValue('lb', 'hello', PDO::PARAM_STR);
Et ensuite, on lance l'execution de la requête :
$stmt->execute();
Si la requête est un select, on peut se servir de $stmt
comme un
ResultSet classique, voir la section suivante.
Il est possible de relancer l'execution avec d'autres valeurs pour les
paramètres, autant de fois que l'on veut, sans avoir à rééxecuter prepare()
.
$stmt = $cnx->prepare('INSERT INTO `labels_test` (`key`,`lang` ,`label`) VALUES (:k, :lg, :lb)');
// on insère un premier enregistrement
$bind = $stmt->bindParam('lg', $lang);
$bind = $stmt->bindParam('k', $key, PDO::PARAM_INT);
$bind = $stmt->bindValue('lb', 'hello', PDO::PARAM_STR);
$stmt->execute();
// on insère un deuxième enregistrement, en modifiant juste les paramètres
// qui changent
$bind = $stmt->bindValue('k', 'good.bye', PDO::PARAM_INT);
$bind = $stmt->bindValue('lb', 'Good Bye', PDO::PARAM_STR);
$stmt->execute();
Une alternative à l'utilisation de bindParam()
et bindValue()
, est de
donner les valeurs directement à la méthode execute()
.
$stmt = $cnx->prepare('INSERT INTO `labels_test` (`key`,`lang` ,`label`) VALUES (:k, :lg, :lb)');
$stmt->execute(array(
'lg' => $lang,
'k' => $key,
'lb' => 'hello'
));
Notez que le driver oci ne prend pas en charge les paramètres donnés à execute()
.
ResultSet ¶
jDbResultSet
est l'objet que vous récupérez après avoir fait un SELECT
(via query()
, limitQuery()
ou prepare()
).
Sa méthode fetch()
vous permet de récupérer un à un les enregistrements.
Sa méthode fetchAll()
permet de récupérer tous les résultats en même temps
dans un tableau PHP.
À noter qu'avec ces deux méthodes, et dans son utilisation comme iterateur, jDbResultSet
renvoie les enregistrements sous forme d'objets.
Si vous préférez des tableaux associatifs, utilisez fetchAssociative()
et fetchAllAssociative()
.
jDbResultSet implémente l'interface Iterator
. De ce fait, vous pouvez utiliser
cet objet dans certaines boucles, comme les foreach
:
$cnx = jDb::getConnection();
$rs = $cnx->query('SELECT nom, prenom FROM users');
$result = '';
foreach ($rs as $record) {
$result .= 'nom = '.$record->nom.' prenom = '.$record->prenom."\n";
}
Les objets contenant les enregistrements sont des objets "anonymes" (ils n'ont
pas de classe précise). Si vous voulez que ce soient des objets d'une certaine
classe, vous devez l'indiquer via setFetchMode()
:
class User {
...
}
$cnx = jDb::getConnection();
$rs = $cnx->query('SELECT nom, prenom FROM users');
$rs->setFetchMode(jDbConnection::FETCH_CLASS, 'User');
$result = '';
foreach ($rs as $record) {
// $record est ici un objet de type User
$result .= 'nom = '.$record->nom.' prenom = '.$record->prenom."\n";
}
Quand un objet jDbResultSet
est détruit, la ressource base de donnée associée est libérée
automatiquement. Mais vous pouvez le faire explicitement avec la méthode free()
.
Pour le reste des méthodes, voyez la documentation de référence.
Utilisation des résultats dans un template ¶
Il est possible de passer un objet jDbResultSet dans un template.
Dans le contrôleur :
$cnx = jDb::getConnection();
$rs = $cnx->query('SELECT nom, prenom FROM users');
$template->assign('resultats', $rs);
Dans le template :
<table>
<tr> <th>nom</th> <th>prenom</th></tr>
{foreach $resultats as $user}
<tr>
<td>{$user->nom|eschtml}</td>
<td>{$user->prenom|eschtml}</td>
</tr>
{/foreach}
</table>
Transactions ¶
jDb permet de faire des transactions. Bien sûr, il faut que le driver utilisé supporte les transactions.
Pour marquer le début d'une transaction, vous appellerez la méthode
beginTransaction()
. Ensuite vous lancerez les requêtes, Puis après avoir
fait vos requêtes, vous pourrez valider la transaction en appelant la méthode
commit()
. Pour annuler une transaction, il suffit d'appeler rollback()
.
$cnx = jDb::getConnection();
$cnx->beginTransaction();
try {
$cnx->exec(...);
$cnx->query(...);
//....
$cnx->commit();
}
catch (Exception $e) {
$cnx->rollback();
}