Vai al contenuto

Driver di database

merql separa il trasporto della connessione dal dialetto del database. Un adattatore DatabaseConnection esegue SQL tramite PDO o mysqli, mentre un Driver gestisce i metadati SQL specifici del motore di database e la quotatura degli identificatori. Sono disponibili driver integrati per MySQL e SQLite.

PHP
use Merql\Driver\DriverFactory;

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

L'interfaccia Driver

Ogni driver implementa cinque metodi:

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;
}
Metodo Scopo
quoteIdentifier Quota il nome di una tabella o colonna per usarlo in SQL.
listTables Restituisce tutte le tabelle utente nel database corrente.
readSchema Legge i nomi e i tipi delle colonne, la chiave primaria e le chiavi univoche di una tabella.
readForeignKeys Restituisce una mappa delle dipendenze tra tabelle figlie e tabelle padre.
selectAll Crea una query SELECT * per una tabella.

MysqlDriver

Usa query INFORMATION_SCHEMA per i metadati e la quotatura con backtick per gli identificatori.

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']]

L'elenco delle tabelle interroga INFORMATION_SCHEMA.TABLES, filtrato per il database corrente e il tipo BASE TABLE. La lettura dello schema interroga INFORMATION_SCHEMA.COLUMNS per le colonne e INFORMATION_SCHEMA.KEY_COLUMN_USAGE per le chiavi primarie e univoche.

SqliteDriver

Usa query PRAGMA per i metadati e la quotatura con virgolette doppie per gli identificatori.

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 rileva automaticamente il driver corretto da 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

Se l'identità del driver della connessione non viene riconosciuta, viene generata una RuntimeException con il messaggio Unsupported database driver: <name>. merql non include driver PostgreSQL.

Registrazione di driver personalizzati

Per database diversi da MySQL e SQLite, scrivi una classe che implementi Driver e registrala. PostgresDriver qui sotto indica la tua classe:

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.

La classe del driver deve implementare l'interfaccia Driver. Il primo argomento di register() è l'identità del driver della connessione.

Ripristino

Per i test, ripristina la factory allo stato predefinito:

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

Helper di connessione

La classe Connection crea adattatori con impostazioni predefinite sensate. Gli adattatori PDO usano eccezioni in caso di errore, modalità di fetch associativa, prepared statement reali e valori recuperati convertiti in stringhe. L'adattatore mysqli imposta utf8mb4, usa la modalità eccezioni mysqli, prepared statement e normalizza i valori recuperati allo stesso formato stringa o 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() accetta qualsiasi DSN che PDO possa aprire, ma merql può acquisire snapshot e applicare modifiche solo tramite un driver registrato. Una connessione pgsql: si apre (se pdo_pgsql è installato), ma i costruttori di Merql::init(), Snapshotter, Applier e GuardedApplier chiamano DriverFactory::create(), che genera RuntimeException: Unsupported database driver: pgsql a meno che tu non abbia registrato un driver per esso o non ne passi uno.

Connection::sqlite() abilita anche automaticamente PRAGMA foreign_keys = ON, che SQLite richiede per l'applicazione dei vincoli di chiave esterna.

Dove vengono usati i driver

I driver sono usati in tutto merql:

  • Snapshotter usa listTables, readSchema e selectAll per acquisire lo stato del database.
  • Applier usa readForeignKeys per determinare l'ordine delle operazioni e passa il driver a SqlGenerator per la quotatura degli identificatori.
  • SqlGenerator usa quoteIdentifier per creare SQL sicuro.

Se passi una connessione a Snapshotter o Applier senza specificare un driver, DriverFactory::create() viene chiamato automaticamente.