Chapitre 3. Zend_Db
Précédent |  | Suivant

## Chapitre 3. Zend_Db

## 3.1. Zend_Db_Adapter

### 3.1.1. Introduction

`Zend_Db_Adapter` est l'API d'abstraction pour le Framework Zend. Basé sur PDO, vous pouvez utiliser `Zend_Db_Adapter` pour vous connecter sur tout les SGBD supportés, en utilisant la même API. Les SGB supportés sont entre autres : Microsoft SQL Server, MySQL, PostgreSQL, SQLite.

Pour créer une instance de `Zend_Db_Adapter` pour vous connecter à votre base de données, vous devez appeler `Zend_Db::factory()` avec le nom de l'adapteur et un tableau de paramètres décrivant la connexion. Par exemple, pour vous connecter à une base de données MySQL appelée "camelot" sur votre machine locale et avec le nom d'utilisateur "malory" :

    <?php

    require_once 'Zend/Db.php';

    $params = array ('host'     => '127.0.0.1',
                     'username' => 'malory',
                     'password' => '******',
                     'dbname'   => 'camelot');

    $db = Zend_Db::factory('PDO_MYSQL', $params);

    ?>

De la même manière, pour vous connecter à une base de données SQLite appelée "camelot" :

    <?php

    require_once 'Zend/Db.php';

    $params = array ('dbname' => 'camelot');

    $db = Zend_Db::factory('PDO_SQLITE', $params);

    ?>

Quelque soit le SGBD, vous aurez la possibilité d'utiliser exactement la même API pour interroger la base de données.

### 3.1.2. Se protéger des injections SQL

Vous devriez toujours échapper les valeurs destinées à être utilisées dans une requête SQL; cela permet de se prémunir des injections SQL. `Zend_Db_Adapter` fournies deux méthodes (via l'objet PDO) pour vous aider à échapper les valeurs.

La première est la méthode `quote()`. Elle va échapper une valeur scalaire conformément aux spécificités de la base de données. Si vous essayer d'échapper un tableau, la méthode va retourner une chaîne contenant chaque valeur du tableau, séparée par des virgules, chacune correctement protégée (c'est pratique dans le cas de fonctions qui prennent un paramètre de type liste).

    <?php

    // créé un objet $db, on suppose l'utilisation de MySQL

    // échappement d'un scalaire
    $value = $db->quote('St John"s Wort');
    // $value is now '"St John\"s Wort"' (note the surrounding quotes)

    // échappement d'un tableau
    $value = $db->quote(array('a', 'b', 'c');
    // $value vaut maintenant '"a", "b", "c"' (une chaîne séparée par des virgules)

    ?>

La seconde est la méthode `quoteInto()`. Vous fournissez une requête de base, avec des points d'interrogations comme caractère à remplacer, et un scalaire ou un tableau à protéger. C'est pratique pour construire rapidemant des requête et des clauses. Les scalaires et les tableaux sont traitées de la même façon que dans la méthode `quote()`.

    <?php

    // créé un objet $db, on suppose l'utilisation de MySQL

    // protection d'un scalaire dans une clause WHERE
    $where = $db->quoteInto('id = ?', 1);
    // $where vaut maintenant 'id = "1"' (notez bien les guillemets supplémentaires)

    // protection d'un tableau dans la clause WHERE
    $where = $db->quoteInto('id IN(?)', array(1, 2, 3));
    // $where vaut maintenant 'id IN("1", "2", "3")' (une chaîne séparée par des virgules)

    ?>

### 3.1.3. Requêtes Directes

Une fois que vous avez une instance de `Zend_Db_Adapter`, vous pouvez exécuter directement des requêtes SQL. `Zend_Db_Adapter` passe cette requête dans l'objet PDO sous-jacent, qui les prépare et les exécute, et vous retourne ensuite une objet `PDOStatement` pour que vous puissez manipuler les résultats, s'il y en a.

    <?php

    // créé un objet $db et exécute ensuite la requête
    // avec une requête SQL correctement protégée
    $sql = $db->quoteInto(
        'SELECT * FROM example WHERE date > ?',
        '2006-01-01'
    );
    $result = $db->query($sql);

    // utilisez l'objet de type PDOStatement $result pour récupérer toutes les lignes de résultat dans un tableau
    $rows = $result->fetchAll();
    ?>

Vous pouvez associer automatiquement vos données à la requête. Cela signifie que vous pouvez définir de multiples marqueurs de remplacement réservés et nommés dans la requête, et ensuite passer un tableau de données qui vont se substituer à ces marqueurs. Les valeurs de remplacement sont automatiquement protégées, pour prévenir les attaques par injection SQL.

    <?php

    // créé un objet $db, et interroge la base de données.
    // cette fois, utilisez un marqueur de remplacement.
    $result = $db->query(
        'SELECT * FROM example WHERE date > :placeholder',
        array('placeholder' => '2006-01-01')
    );

    // utiliser le PDOStatement $result pour récupérer toutes les lignes de résultat dans un tableau
    $rows = $result->fetchAll();

    ?>

Optionellement, vous pouvez préparer et lier manuellement une instruction SQL. Pour ce faire, utilisez la méthode `prepare()` pour obtenir un objet de type `PDOStatement`, que vous pouvez manipuler directement.

    <?php

    // créé un objet $db, et interroge la base de données.
    // cette fois-ci, utilisez un objet PDOStatement pour une liaison manuelle.
    $stmt = $db->prepare('SELECT * FROM example WHERE date > :placeholder');
    $stmt->bindValue('placeholder', '2006-01-01');
    $stmt->execute();

    // utiliser le PDOStatement $result pour récupérer toutes les lignes de résultat dans un tableau
    $rows = $stmt->fetchAll();

    ?>

### 3.1.4. Transactions

Par défaut, PDO (and ainsi `Zend_Db_Adapter`) sont en mode "auto-commit". Cela signifie que chaque requête est validée à chaque exécution. Si vous souhaitez les exécuter à l'intérieur d'une transaction, appelez simplement la méthode `beginTransaction()` vous pourrez alors valider (`commit()`) ou annuler (`rollBack()`) vos changements. `Zend_Db_Adapter` retourne en mode "auto-commit" jusqu'à ce que vous appeliez de nouveau `beginTransaction()`.

    <?php

    // créé une objet $db, puis débute une transaction.
    $db->beginTransaction();

    // tente une requête
    // si elle réussie, validez les changements avec commit()
    // si elle échoue, annuler les changements avec rollback()
    try {
        $db->query(...);
        $db->commit();
    } catch (Exception $e) {
        $db->rollBack();
        echo $e->getMessage();
    }

    ?>

### 3.1.5. Insertion de Lignes

Vous avez la possibilité d'utiliser la méthode `insert()` pour créer une instruction INSERT, et lui lier les données pour l'insertion. (Les données liées sont automatiquement protégées pour prévenir tout risque d'injection SQL).

La valeur retournée n'est pas le dernier identifiant d'insertion, la table ne contenant peut-être pas de colonne auto-incrémentée; à la place, la valeur retournée est le nombre de lignes affectées (habituellement 1). Si vous souhaitez l'ID du dernier identifiant généré, appelez la méthode `lastInsertId()` après l'insertion.

    <?php

    //
    // INSERT INTO round_table
    //     (noble_title, first_name, favorite_color)
    //     VALUES ("King", "Arthur", "blue");
    //

    // créé un objet $db et ensuite...
    // les données des colonnes à insérer en utilisant la syntaxe nom_colonne => valeur_colonne
    $row = array (
        'noble_title'    => 'King',
        'first_name'     => 'Arthur',
        'favorite_color' => 'blue',
    );

    // la table dans laquelle la ligne doit être insérée
    $table = 'round_table';

    // insérez la ligne, et récupérez son identifiant
    $rows_affected = $db->insert($table, $row);
    $last_insert_id = $db->lastInsertId();

    ?>

### 3.1.6. Mise à jour de lignes

Vous avez la possibilité d'utiliser la méthode `update()` pour créer une instruction UPDATE et lier vos données pour la mise à jour. (Les données liées sont automatiquement protégées pour prévenir tout risque d'injection SQL).

Vous pouvez fournir une clause WHERE facultative pour spécifier quelle ligne mettre à jour. (Notez que la clause WHERE n'est pas un paramètre échappé, vous devez donc protéger vous-même sa valeur).

    <?php

    //
    // UPDATE round_table
    //     SET favorite_color = "yellow"
    //     WHERE first_name = "Robin";
    //

    // crée un objet $db, en ensuite...
    // les nouvelles valeurs à mettre à jour, en utilisant la syntaxe nom_colonne => valeur_colonne
    $set = array (
        'favorite_color' => 'yellow',
    );

    // la table à mettre à jour
    $table = 'round_table';

    // la clause WHERE
    $where = $db->quoteInto('first_name = ?', 'Robin');

    // mise à jour de la table, et récupération du nombre de lignes affectées
    $rows_affected = $db->update($table, $set, $where);

    ?>

### 3.1.7. Suppression de Lignes

Vous avez la possibilité d'utiliser la méthode `delete()` pour créer une instruction DELETE. Vous pouvez fournir optionellement une clause WHERE. (Notez que la clause WHERE n'est pas un paramètre échappé, vous devez donc protéger vous-même sa valeur).

    <?php

    //
    // DELETE FROM round_table
    //     WHERE first_name = "Patsy";
    //

    // crée un objet $db, en ensuite...
    // la table dont on veut supprimer des données
    $table = 'round_table';

    // la clause WHERE
    $where = $db->quoteInto('first_name = ?', 'Patsy');

    // mise à jour de la table, et récupération du nombre de lignes affectées
    $rows_affected = $db->delete($table, $where);

    ?>

### 3.1.8. Récupération de lignes

Bien que vous puissiez interroger la base de données directement avec la méthode `query()` tout ce que vous avez besoin de faire et des sélectionner des lignes et obtenir le résultat. La série de méthodes `fetch*()` vous permet de le faire. Pour chaque méthode `fetch*()`, vous passez une instruction SQL; si vous utilisez des marqueurs de remplacement dans cette instruction, vous devrez aussi passer un tableau contenant la valeur à échapper, pour qu'elle soient protégées et remplacées dans la requête. Les méthodes `fetch*()` sont :

- `fetchAll()`

- `fetchAssoc()`

- `fetchCol()`

- `fetchOne()`

- `fetchPairs()`

- `fetchRow()`

    <?php

    // crée un objet $db, en ensuite...

    // ?? retrouve les colonnes de chaque ligne comme un tableau séquentiel ??
    $result = $db->fetchAll(
        "SELECT * FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // ?? retrouve les colonnes de chaque ligne comme un tableau associatif ??
    // la première colonne est utilisée comme la clé du tableau
    $result = $db->fetchAssoc(
        "SELECT * FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // retrouve la première colonne de résultat
    $result = $db->fetchCol(
        "SELECT first_name FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // retrouve uniquement la première valeur
    $result = $db->fetchOne(
        "SELECT COUNT(*) FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // retrouve la série de paries clé/valeurs; la première colonne et le tableau de clé
    // la seconde le tableau de valeurs
    $result = $db->fetchPairs(
        "SELECT first_name, favorite_color FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // retrouve uniquement la première ligne retournée
    $result = $db->fetchRow(
        "SELECT * FROM round_table WHERE first_name = :name",
        array('name' => 'Lancelot')
    );

    ?>

Précédent |  | Suivant
2.4. Plugins | Sommaire | 3.2. Zend_Db_Profiler