Глава 9. Zend_Db

Содержание

9.1. Zend_Db_Adapter
9.1.1. Введение
9.1.2. Заключение в кавычки для предотвращения SQL-инъекций
9.1.3. Прямые запросы
9.1.4. Транзакции
9.1.5. Вставка строк
9.1.6. Обновление строк
9.1.7. Удаление строк
9.1.8. Извлечение строк
9.2. Zend_Db_Profiler
9.2.1. Введение
9.2.2. Использование профайлера
9.2.3. Расширенное использование профайлера
9.3. Zend_Db_Select
9.3.1. Обзор
9.3.2. Создание объекта Select
9.3.3. Построение запросов Select
9.3.4. Выполнение запросов Select
9.3.5. Другие методы
9.4. Zend_Db_Table
9.4.1. Класс таблицы - введение
9.4.2. Определение класса таблицы
9.4.3. Создание экземпляра класса таблицы
9.4.4. Добавление строк в таблицу
9.4.5. Обновление строк в таблице
9.4.6. Удаление строк из таблицы
9.4.7. Извлечение строк по первичному ключу
9.4.8. Получение набора строк
9.4.9. Запрос единственной строки
9.4.10. Получение метаданных таблицы
9.4.11. Кэширование метаданных таблицы
9.4.12. Расширение класса таблицы
9.5. Zend_Db_Table_Row
9.5.1. Введение
9.5.2. Извлечение строки
9.5.3. Редактирование строк в БД
9.5.4. Сериализация и десериализация строк
9.5.5. Расширение класса строки
9.6. Zend_Db_Table_Rowset
9.6.1. Введение
9.6.2. Получение набора строк
9.6.3. Получение строк из набора
9.6.4. Получение набора строк в виде массива
9.6.5. Сериализация и десериализация наборов строк
9.6.6. Расширение класса набора строк
9.7. Связи между таблицами Zend_Db_Table
9.7.1. Введение
9.7.2. Определение связей
9.7.3. Извлечение зависимых строк
9.7.4. Извлечение родителькой строки
9.7.5. Извлечение строк через связи "многие-ко многим"
9.7.6. Каскадные операции записи

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() для отмены изменений. Zend_Db_Adapter вернется в режим автоматического завершения транзакций до тех пор, пока вы снова не вызовете beginTransaction().

<?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 для определения того, какие строки следует обновить.

<?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);

?>

Если у вас есть несколько предложений WHERE, которые нужно применить к запросу UPDATE, то вы можете передавать массив таких предложений методу update(). Эти предложения объединяются через оператор AND. Объединение предложений через оператор OR должно производиться вручную:

<?php
$set = array('favorite_color' => 'yellow');

// несколько условий, объединяемых через AND
$where   = array(
    $db->quoteInto('first_name = ?', $firstName),
    $db->quoteInto('noble_title = ?', $nobleTitle)
    );
$count   = $db->update('round_table', $set, $where);

// несколько условий, объединяемых через OR
$firstNameOne = $db->quote($firstNameOne);
$firstNameTwo = $db->quote($firstNameTwo);
$where        = "first_name = $firstNameOne OR first_name = $firstNameTwo";
$count        = $db->update('round_table', $set, $where);

?>
[Замечание] Замечание

Значения и идентификаторы предложений WHERE не заключаются в кавычки автоматически. Если у вас есть значения или идентификаторы, требующие заключения в кавычки, то вы должны произвести его самостоятельно. Используйте методы quote(), quoteInto() и quoteIdentifier() адаптера БД.

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

Вы можете использовать метод delete() для создания оператора DELETE. Методу можно передавать необязательное предложение 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);

?>

Как и в случае метода update(), вы можете использовать массив предложений WHERE для аргумента $where метода delete().

[Замечание] Замечание

Значения и идентификаторы предложений WHERE не заключаются в кавычки автоматически. Если у вас есть значения или идентификаторы, требующие заключения в кавычки, то вы должны произвести его самостоятельно. Используйте методы quote(), quoteInto() и quoteIdentifier() адаптера БД.

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

?>