Raccourcis : Contenu - rubriques - sous rubriques
EN FR

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.

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é dans 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. À noter que jDbResultSet renvoie toujours un enregistrement sous forme d'objet.

Sa méthode fetchAll() permet de récupérer tous les résultats en même temps dans un tableau PHP.

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";
  } 

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();
    }