DBAL Driver - базовые классы для работы с базами данных, на основе которых построена остальнаях часть пакета DBAL.
Условно driver можно разделить на 2 составляющие:
Здесь мы рассмотрим архитектуру DBAL более подробно.
Если вы прочитали "Введение в пакет DBAL", то уже знаете, что основными понятиями здесь являются
Рассмотрим, как выглядит статическая диаграмма классов, связанных с выполнением SELECT-запросов ( на примере MySql-драйвера):
Интерфейс lmbDbConnection, который реализует класс lmbMysqlConnection содержит метод newStatement($sql), который на базе sql-кода создает объект утверждения (statement) того или иного типа. При наличии ключевого слова SELECT, lmbMysqlConnection создает объект класса lmbMysqlQueryStatement.
lmb_require('limb/dbal/src/drivers/mysql/lmbMysqlConnection.class.php'); $config = array('host' => 'localhost', 'user' => 'root', 'password' => 'secret', 'database' => 'my_datatase', 'charset' => 'utf8'); $connection = new lmbMysqlConnection($config); $sql = 'SELECT * FROM news'; $statement = $connection->newStatement($sql); // возвратит объект класса lmbMysqlQueryStatement
Объект $statement класса lmnMysqlQueryStatement реализует интерфейс lmbDbQueryStatement и содержит ссылку на объект подключения класса lmbMysqlConnection.
Создание объекта $statement еще не значит выполнение реального запроса к базе данных. Это происходит в DBAL как можно позже. До выполнения реального запроса можно произвести некоторые модификации, особенно это актуально при работе с наборами данных (см. ниже)
Из $statement можно получить различные данные:
Самым интересным для нас является метод lmbDbQueryStatement :: getRecordSet(), который возвращает итератор с набором данных. По сути getRecordSet() возвращает курсор на результат запроса - это значит, что данные в память загружаются только по мере прохождения по итератору, а не сразу все.
Итак, lmbDbQueryStatement :: getRecordSet() возвращает объект, который реализует интерфейс lmbDbRecordSet. В нашем случае это будет объект класса lmbMysqlRecordSet.
lmbDbRecordSet является расширением для интерфейса lmbCollectionInterface, это значит, что набор данных должен поддерживать:
Пример:
[...] $statement = $connection->newStatement($sql); // возвратит объект класса lmbMysqlQueryStatement $rs = $statement->getRecordSet(); echo $rs->count(); // выведет количество элементов в выборке. count() приводит к выполнению отдельного запроса к базе данных. $rs->sort(array('title' => 'ASC')); $rs->paginate(0, 10); for($rs->rewind(); $rs->valid(); $rs->next()) { $record = $rs->current(); echo $record['title'] . "\n"; }
Обратите внимание, методы at($pos) и count() интерфейса lmbDbRecordSet приводят к выполнению отдельных запросов к базе данных, отличных от «основного» запроса record_set-а.
Реальный запрос к базе данных при работе с record_set-ом происходит при вызове метода rewind(), явно или неявно(например, при использовании конструкции foreach).
Метод current() record_set-а возвращает объект, реализующий интерфейс lmbDbRecord (в нашем случае это объект класса lmbMysqlRecord), который в свою очередь является расширением интерфейса lmbSetInterface.
Рассмотрим, как выглядит статическая диаграмма классов, связанных с выполнением запросов, связанных с модификацией базы данных(на примере MySql-драйвера):
Эти запросы отличаются тем, что на запросы DELETE,UPDATE и INSERT, создаются объекты, реализующие интерфейсы lmbDbManipulationStatement и lmbDbInsertStatement.
Основным методом для выполнения утверждения является метод lmbDbStatement :: execute().
Интерфейс lmbDbManipulationStatement также содержит метод getAffectedRowsCount() который возвращает количество записей в базе данных, затронутых выполнением запроса.
$sql = "DELETE * FROM founding_fathers WHERE last_name LIKE :last_name:%"; $stmt = $connection->newStatement($sql); $stmt->setVarChar('last_name', 'Iva'); $stmt->execute(); // выполнит запрос. echo 'Removed ' . $stmt->getAffectedRowCount() . ' rows';
Конструкции вида :last_name: - это placeholder-ы для значений. Интейрфейс lmbDbStatement содержит различные методы для установки значений в placeholder-ы, type-cast и escape значений:
Есть более базовый метод lmbDbStatement :: set($name, $value), который пытается самостоятельно угадать тип переданного значения.
Интерфейс lmbDbInsertStatement содержит метод insertId($field_name = 'id'), который является аналогом execute(), однако возвращает значение поля $field_name только что вставленной записи. Этот метод полезен, например, если первичный ключ является автоинкрементным.
Driver также содержит средства для получения meta-информации о базе данных.
Статическая диаграмма классов выглядит следующим образом:
Мы не будем заострять внимание на этой подсистеме, и подробно ее описывать. Meta-подсистема активно используется в классе lmbTableGateway и в пакете ACTIVE_RECORD.
Получение информации о структу базы данных занимает некоторое время, поэтому для ускорения работы эти информацию лучше кешировать. Чтобы включить эту возможность нужно определить значение константы LIMB_CACHE_DB_META_IN_FILE как true, где-то в setup.php файле приложения, например:
@define('LIMB_CACHE_DB_META_IN_FILE', true);
Обсуждение