Глава 9. Zend_Db
Пред. |  | След.

## Глава 9. Zend_Db

## 9.1. Zend_Db_Adapter

### 9.1.1. Введение

`Zend_Db_Adapter` является абстрактным слоем доступа к интерфейсу БД для Zend Framework. Вы можете использовать основанный на PDO `Zend_Db_Adapter` для подключения и работы с любой СУБД, поддерживающей SQL, используя один и тот же интерфейс. В число таких СУБД входят Microsoft SQL Server, MySQL, PostgreSQL, SQLite и другие.

Для того, чтобы создать экземпляр `Zend_Db_Adapter` для вашей конкретной СУБД, вам нужно вызвать метод `Zend_Db::factory()` с именем адаптера и массивом параметров, описывающих соединение. Например, подключение к базе данных MySQL с именем "camelot" на локальном хосте под именем пользователя "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);

    ?>

Подключение к базе данных SQLite с именем "camelot" производится аналогичным образом:

    <?php

    require_once 'Zend/Db.php';

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

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

    ?>

И в том, и в другом случае вы можете использовать один и тот же API для того, чтобы делать запросы к базе данных.

### 9.1.2. Добавление кавычек для предотвращения SQL-инъекций

Вы должны всегда окружать кавычками значения, которые подставляются в оператор SQL — это поможет предотвратить атаки посредством SQL-инъекций. `Zend_Db_Adapter` предоставляет два метода (посредством включенного объекта PDO) для того, чтобы облегчить самостоятельное добавление кавычек к значениям.

Первый из них — метод `quote()`. Он должным образом добавит кавычки в скалярное значение в соответствии с вашим адаптером БД. Если вы пытаетесь добавить кавычки в массив, то метод вернет строку из разделенных запятыми значений массива с добавленными кавычками (это полезно для функций, которые принимают список параметров).

    <?php

    // создается объект $db, предполагается, что адаптером является Mysql

    // добавление кавычек в строку
    $value = $db->quote('St John"s Wort');
    // значением $value сейчас является строка '"St John\"s Wort"'
    // (обратите внимание на окружающие кавычки)

    // добавление кавычек в массив
    $value = $db->quote(array('a', 'b', 'c');
    // значением $value сейчас является '"a", "b", "c"'
    // (разделенная запятыми строка)

    ?>

Вторым является метод `quoteInto()`. Вы передаете в него строку-основу с указанием меток заполнения в виде вопросительных знаков и после одно скалярное значение или массив для подстановки с добавлением кавычек. Это полезно для построения запросов и условий в порядке следования. Скалярные значения и массивы обрабатываются точно так же, как в методе `quote()`.

    <?php

    // создается объект $db, предполагается, что адаптером является Mysql

    // подстановка скалярного значения в условие WHERE
    $where = $db->quoteInto('id = ?', 1);
    // значением $where сейчас является 'id = "1"'
    // (обратите внимание на добавленные кавычки)

    // подстановка массива в условие WHERE
    $where = $db->quoteInto('id IN(?)', array(1, 2, 3));
    // значением $where сейчас является 'id IN("1", "2", "3")'
    // (разделенная запятыми строка)

    ?>

### 9.1.3. Прямые запросы

Имея экземпляр `Zend_Db_Adapter`, вы можете выполнять запросы непосредственно в SQL. `Zend_Db_Adapter` переадресует эти запросы базовому объекту PDO, который подготавливает и выполняет их, затем возвращает объект `PDOStatement` для ваших манипуляций с результатами (если они есть).

    <?php

    // создается объект $db и затем делается запрос к БД
    // с оператором SQL, в который подставлено значение с добавлением кавычек
    $sql = $db->quoteInto(
        'SELECT * FROM example WHERE date > ?',
        '2006-01-01'
    );
    $result = $db->query($sql);

    // используется PDOStatement $result, чтобы извлечь все строки результата в массив
    $rows = $result->fetchAll();

    ?>

Вы можете автоматически связывать все данные в вашем запросе. Это означает, что вы можете устанавливать в запросе именованные метки заполнения и затем передавать массив данных, замещающих эти метки. В замещающие данные автоматически добавляются кавычки, обеспечивая большую защиту от атак с применением SQL-инъекций.

    <?php

    // создается объект $db и затем делается запрос к БД
    // на этот раз используется связывание меток заполнения
    $result = $db->query(
        'SELECT * FROM example WHERE date > :placeholder',
        array('placeholder' => '2006-01-01')
    );

    // используется PDOStatement $result, чтобы извлечь все строки результата в массив
    $rows = $result->fetchAll();

    ?>

Возможно, вы захотите подготавливать и связывать данные в операторах SQL вручную. Для этого используйте метод `prepare()` для получения подготовленного `PDOStatement`, с которым вы можете работать непосредственно.

    <?php

    // создается объект $db и затем делается запрос к БД
    // на этот раз подготавливается PDOStatement для связки значений вручную
    $stmt = $db->prepare('SELECT * FROM example WHERE date > :placeholder');
    $stmt->bindValue('placeholder', '2006-01-01');
    $stmt->execute();

    // используется PDOStatement $result,
    // чтобы извлечь все строки результата в массив
    $rows = $stmt->fetchAll();

    ?>

### 9.1.4. Транзакции

По умолчанию PDO (и, соответственно, `Zend_Db_Adapter`) находится в режиме автоматического завершения транзакции (auto-commit). Это означает, что все изменения сохраняются, как только они выполнены. Если вы хотите выполнять операторы внутри транзакций, просто вызывайте метод `beginTransaction()`, затем либо `commit()` для сохранения изменений, либо `rollBack()`, чтобы отменить изменения.

    <?php

    // создается объект $db и затем устанавливается начало транзакции
    $db->beginTransaction();

    // попытка сделать запрос
    // если запрос успешный, то фиксация изменений
    // если неудача, то откат
    try {
        $db->query(...);
        $db->commit();
    } catch (Exception $e) {
        $db->rollBack();
        echo $e->getMessage();
    }

    ?>

### 9.1.5. Вставка строк

В качестве дополнительного удобства вы можете использовать метод `insert()` для создания оператора INSERT и связки данных для вставки. В данные для связывания автоматически подставляются кавычки для предотвращения атак с использованием SQL-инъекций.

Возвращаемое значение не является последним сгенерированным идентификатором, поскольку таблица может не иметь столбцы с автоинкрементом. Вместо этого возвращается количество затронутых строк (обычно 1). Если вы хотите получать идентификатор последней добавленной записи, вызывайте после вставки метод `lastInsertId()`.

    <?php

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

    // создается объект $db

    // массив данных для подстановки в формате 'имя столбца' => 'значение'
    $row = array (
        'noble_title'    => 'King',
        'first_name'     => 'Arthur',
        'favorite_color' => 'blue',
    );

    // таблица, в которую должна быть вставлена строка
    $table = 'round_table';

    // вставка строки и получение ID строки
    $rows_affected = $db->insert($table, $row);
    $last_insert_id = $db->lastInsertId();

    ?>

### 9.1.6. Обновление строк

В качестве дополнительного удобства вы можете использовать метод `update()` для создания оператора UPDATE и присвоения данных для обновления. В данные для связывания автоматически подставляются кавычки для предотвращения атак с использованием SQL-инъекций.

Вы можете передавать необязательное условие WHERE для того, чтобы указать, какие строки обновить. (Заметьте, что условие WHERE не является параметром для связывания, поэтому вам нужно самостоятельно добавить кавычки для значений в этом условии).

    <?php

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

    // создается объект $db

    // новые значения для установки в update, в формате 'имя столбца' => 'значение'.
    $set = array (
        'favorite_color' => 'yellow',
    );

    // таблица для обновления
    $table = 'round_table';

    // условие WHERE
    $where = $db->quoteInto('first_name = ?', 'Robin');

    // обновление таблицы и получение количества затронутых строк
    $rows_affected = $db->update($table, $set, $where);

    ?>

### 9.1.7. Удаление строк

В качестве дополнительного удобства вы можете использовать метод `delete()` для создания оператора DELETE. Вы можете предоставлять необязательное условие WHERE для указания, какие строки удалить. (Заметьте, что условие WHERE не является параметром для связывания, поэтому вам нужно самостоятельно добавить кавычки для значений в этом условии).

    <?php

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

    // создается объект $db

    // таблица для удаления
    $table = 'round_table';

    // условие WHERE
    $where = $db->quoteInto('first_name = ?', 'Patsy');

    // удаление из таблицы и получение количества затронутых строк
    $rows_affected = $db->delete($table, $where);

    ?>

### 9.1.8. Извлечение строк

Несмотря на то, что вы можете делать запросы непосредственно в БД с помощью метода `query()`, зачастую все, что вам нужно сделать, — это выполнение оператора SELECT и получение результатов. Набор методов `fetch*()` сделает это за вас. Для каждого из этих методов вы передаете SQL-оператор SELECT. Если вы используете именованные метки замещения, то можете передавать еще массив значений связывания для замещения в данном операторе с добавлением кавычек. Методами `fetch*()` являются:

- `fetchAll()`

- `fetchAssoc()`

- `fetchCol()`

- `fetchOne()`

- `fetchPairs()`

- `fetchRow()`

    <?php

    // создается объект $db

    // извлечение всех столбцов и всех строк в виде индексного массива
    $result = $db->fetchAll(
        "SELECT * FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // извлечение всех столбцов и всех строк в виде ассоциативного массива
    // первый столбец используется как ключ массива
    $result = $db->fetchAssoc(
        "SELECT * FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // извлечение одного столбца для всех строк
    $result = $db->fetchCol(
        "SELECT first_name FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // извлечение одного значения
    $result = $db->fetchOne(
        "SELECT COUNT(*) FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // извлечение последовательности пар ключ-значение;
    // первый столбец является ключом массива,
    // второй - значением массива
    $result = $db->fetchPairs(
        "SELECT first_name, favorite_color FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // извлечение только одной строки
    $result = $db->fetchRow(
        "SELECT * FROM round_table WHERE first_name = :name",
        array('name' => 'Lancelot')
    );

    ?>

Пред. |  | След.
8.5. Constants for General Date Functions | Начало | 9.2. Zend_Db_Profiler