Перейти к содержимому

Драйверы баз данных

merql отделяет транспорт подключения от диалекта базы данных. Адаптер DatabaseConnection выполняет SQL через PDO или mysqli, а Driver обрабатывает метаданные SQL, специфичные для ядра базы данных, и заключение идентификаторов в кавычки. Встроенные драйверы доступны для MySQL и SQLite.

PHP
use Merql\Driver\DriverFactory;

$driver = DriverFactory::create($connection);
// Auto-detects MySQL or SQLite from the connection driver identity.

Интерфейс Driver

Каждый драйвер реализует пять методов:

PHP
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, а идентификаторы заключаются в обратные кавычки.

PHP
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, а идентификаторы заключаются в двойные кавычки.

PHP
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().

PHP
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 обозначает ваш собственный класс:

PHP
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() — это идентификатор драйвера подключения.

Сброс

Для тестирования сбросьте фабрику до состояния по умолчанию:

PHP
DriverFactory::reset();
// Reverts to only MySQL and SQLite drivers.

Вспомогательный класс подключения

Класс Connection создает адаптеры с разумными значениями по умолчанию. Адаптеры PDO используют исключения при ошибках, ассоциативный режим выборки, настоящие подготовленные выражения и преобразование результатов выборки в строки. Адаптер mysqli задает utf8mb4, использует режим исключений mysqli и подготовленные выражения, а также приводит полученные значения к тому же формату: строка или null.

PHP
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().