Драйверы баз данных
merql отделяет транспорт подключения от диалекта базы данных. Адаптер DatabaseConnection выполняет SQL через PDO или mysqli, а Driver обрабатывает метаданные SQL, специфичные для ядра базы данных, и заключение идентификаторов в кавычки. Встроенные драйверы доступны для MySQL и SQLite.
use Merql\Driver\DriverFactory;
$driver = DriverFactory::create($connection);
// Auto-detects MySQL or SQLite from the connection driver identity.
Интерфейс Driver
Каждый драйвер реализует пять методов:
use Merql\Driver\Driver;
interface Driver
{
public function quoteIdentifier(string $name): string;
public function listTables(DatabaseConnection $connection): array;
public function readSchema(DatabaseConnection $connection, string $table): TableSchema;
public function readForeignKeys(DatabaseConnection $connection): array;
public function selectAll(string $table): string;
}
| Метод | Назначение |
|---|---|
quoteIdentifier |
Заключить имя таблицы или столбца в кавычки для использования в SQL. |
listTables |
Вернуть все пользовательские таблицы в текущей базе данных. |
readSchema |
Прочитать имена и типы столбцов, первичный ключ и уникальные ключи таблицы. |
readForeignKeys |
Вернуть карту зависимостей дочерних таблиц от родительских. |
selectAll |
Сформировать запрос SELECT * для таблицы. |
MysqlDriver
Для метаданных используются запросы INFORMATION_SCHEMA, а идентификаторы заключаются в обратные кавычки.
use Merql\Driver\MysqlDriver;
$driver = new MysqlDriver();
$driver->quoteIdentifier('posts');
// `posts`
$driver->quoteIdentifier('my`table');
// `my``table`
$tables = $driver->listTables($connection);
// ['comments', 'posts', 'users']
$schema = $driver->readSchema($connection, 'posts');
// TableSchema with columns, primaryKey, uniqueKeys
$fks = $driver->readForeignKeys($connection);
// ['comments' => ['posts', 'users']]
Для получения списка таблиц используются запросы к INFORMATION_SCHEMA.TABLES с фильтрацией по текущей базе данных и типу BASE TABLE. Для чтения схемы выполняются запросы к INFORMATION_SCHEMA.COLUMNS для получения столбцов и к INFORMATION_SCHEMA.KEY_COLUMN_USAGE для получения первичного и уникальных ключей.
SqliteDriver
Для метаданных используются запросы PRAGMA, а идентификаторы заключаются в двойные кавычки.
use Merql\Driver\SqliteDriver;
$driver = new SqliteDriver();
$driver->quoteIdentifier('posts');
// "posts"
$driver->quoteIdentifier('my"table');
// "my""table"
$tables = $driver->listTables($connection);
// Queries sqlite_master, excludes sqlite_* internal tables.
$schema = $driver->readSchema($connection, 'posts');
// Uses PRAGMA table_info() and PRAGMA index_list().
$fks = $driver->readForeignKeys($connection);
// Uses PRAGMA foreign_key_list() for each table.
DriverFactory
DriverFactory автоматически определяет подходящий драйвер по DatabaseConnection::driverName().
use Merql\Connection;
use Merql\Driver\DriverFactory;
$connection = Connection::mysql('127.0.0.1', 'mydb', 'root', '');
$driver = DriverFactory::create($connection);
// Returns MysqlDriver
$connection = Connection::sqlite(':memory:');
$driver = DriverFactory::create($connection);
// Returns SqliteDriver
Если идентификатор драйвера подключения не распознан, выбрасывается RuntimeException с сообщением Unsupported database driver: <name>. В merql нет драйвера PostgreSQL.
Регистрация пользовательских драйверов
Для баз данных, отличных от MySQL и SQLite, напишите класс, реализующий Driver, и зарегистрируйте его. Ниже PostgresDriver обозначает ваш собственный класс:
use Merql\Driver\DriverFactory;
DriverFactory::register('pgsql', PostgresDriver::class);
$connection = Connection::fromDsn('pgsql:host=localhost;dbname=mydb', 'user', 'pass');
$driver = DriverFactory::create($connection);
// Returns your PostgresDriver instance.
Класс драйвера должен реализовывать интерфейс Driver. Первый аргумент register() — это идентификатор драйвера подключения.
Сброс
Для тестирования сбросьте фабрику до состояния по умолчанию:
DriverFactory::reset();
// Reverts to only MySQL and SQLite drivers.
Вспомогательный класс подключения
Класс Connection создает адаптеры с разумными значениями по умолчанию. Адаптеры PDO используют исключения при ошибках, ассоциативный режим выборки, настоящие подготовленные выражения и преобразование результатов выборки в строки. Адаптер mysqli задает utf8mb4, использует режим исключений mysqli и подготовленные выражения, а также приводит полученные значения к тому же формату: строка или null.
use Merql\Connection;
// MySQL.
$connection = Connection::mysql('127.0.0.1', 'my_database', 'root', 'password');
$connection = Connection::mysql('db.example.com', 'mydb', 'user', 'pass', port: 3307);
// MySQLi.
$connection = Connection::mysqli('127.0.0.1', 'my_database', 'root', 'password');
// SQLite.
$connection = Connection::sqlite(':memory:');
$connection = Connection::sqlite('/var/data/app.sqlite');
// Any MySQL or SQLite PDO DSN.
$connection = Connection::fromDsn('mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4', 'user', 'pass');
fromDsn() принимает любой DSN, который может открыть PDO, но merql может создавать снимки и применять изменения только через зарегистрированный драйвер. Подключение pgsql: открывается (если установлен pdo_pgsql), но конструкторы Merql::init(), Snapshotter, Applier и GuardedApplier вызывают DriverFactory::create(), который выбрасывает RuntimeException: Unsupported database driver: pgsql, если вы не зарегистрировали драйвер для него и не передали драйвер явно.
Connection::sqlite() также автоматически включает PRAGMA foreign_keys = ON, который требуется SQLite для обеспечения ссылочной целостности внешних ключей.
Где используются драйверы
Драйверы используются во всем merql:
- Snapshotter использует
listTables,readSchemaиselectAllдля получения снимка состояния базы данных. - Applier использует
readForeignKeysдля определения порядка операций и передает драйвер вSqlGeneratorдля заключения идентификаторов в кавычки. - SqlGenerator использует
quoteIdentifierдля формирования безопасных SQL.
Если передать подключение в Snapshotter или Applier, не указав драйвер, автоматически вызывается DriverFactory::create().