Глава 5. Zend_Db

Содержание

5.1. Zend_Db_Adapter
5.1.1. Введение
5.1.2. Добавление кавычек против SQL-инъекций
5.1.3. Прямые запросы
5.1.4. Транзакции
5.1.5. Вставка строк
5.1.6. Обновление строк
5.1.7. Удаление строк
5.1.8. Извлечение строк
5.2. Zend_Db_Profiler
5.2.1. Введение
5.2.2. Использование профайлера
5.2.3. Расширенное использование профайлера
5.3. Zend_Db_Select
5.3.1. Введение
5.3.2. Извлечение столбцов
5.3.3. Объединение таблиц
5.3.4. Условия WHERE
5.3.5. Группировка
5.3.6. Условия HAVING
5.3.7. Сортировка
5.3.8. Ограничение по количеству строк и смещению
5.3.9. Ограничение по странице и количеству строк
5.4. Zend_Db_Table
5.4.1. Введение
5.4.2. Начало работы
5.4.3. Имя таблицы и первичные ключи
5.4.4. Вставка строк
5.4.5. Обновление строк
5.4.6. Удаление строк
5.4.7. Поиск строк по первичному ключу
5.4.8. Извлечение одной строки
5.4.9. Извлечение множества строк
5.4.10. Добавление логики предметной области
5.5. Zend_Db_Table_Row
5.5.1. Введение
5.5.2. Извлечение строки
5.5.3. Изменение значений
5.6. Zend_Db_Table_Rowset
5.6.1. Введение
5.6.2. Извлечение набора строк
5.6.3. Итерация набора строк

5.1. Zend_Db_Adapter

5.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 для того, чтобы делать запросы к базе данных.

5.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")'
// (разделенная запятыми строка)

?>

5.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();

?>

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

?>

5.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();

?>

5.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);

?>

5.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);

?>

5.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')
);

?>