Datenbanktreiber
merql trennt Verbindungstransport und Datenbankdialekt. Ein DatabaseConnection-Adapter führt SQL über PDO oder mysqli aus, während ein Driver datenbankmaschinenspezifische Metadaten SQL und das Quoting von Bezeichnern übernimmt. Integrierte Treiber gibt es für MySQL und SQLite.
use Merql\Driver\DriverFactory;
$driver = DriverFactory::create($connection);
// Auto-detects MySQL or SQLite from the connection driver identity.
Die Driver-Schnittstelle
Jeder Treiber implementiert fünf Methoden:
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;
}
| Methode | Zweck |
|---|---|
quoteIdentifier |
Quoted einen Tabellen- oder Spaltennamen zur Verwendung in SQL. |
listTables |
Gibt alle Benutzertabellen der aktuellen Datenbank zurück. |
readSchema |
Liest Spaltennamen, Typen, Primärschlüssel und eindeutige Schlüssel einer Tabelle. |
readForeignKeys |
Gibt eine Zuordnung von untergeordneten Tabellen zu übergeordneten Tabellen zurück. |
selectAll |
Erstellt eine SELECT *-Abfrage für eine Tabelle. |
MysqlDriver
Verwendet INFORMATION_SCHEMA-Abfragen für Metadaten und Backticks zum Quoting von Bezeichnern.
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']]
Tabellenlistenabfragen nutzen INFORMATION_SCHEMA.TABLES, gefiltert nach aktueller Datenbank und Typ BASE TABLE. Schemaabfragen nutzen INFORMATION_SCHEMA.COLUMNS für Spalten und INFORMATION_SCHEMA.KEY_COLUMN_USAGE für Primär- und eindeutige Schlüssel.
SqliteDriver
Verwendet PRAGMA-Abfragen für Metadaten und doppelte Anführungszeichen zum Quoting von Bezeichnern.
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 erkennt den passenden Treiber anhand von DatabaseConnection::driverName() automatisch.
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
Wenn die Treiberkennung der Verbindung nicht erkannt wird, wird ein RuntimeException mit der Meldung Unsupported database driver: <name> ausgelöst. merql enthält keinen PostgreSQL-Treiber.
Benutzerdefinierte Treiber registrieren
Für andere Datenbanken als MySQL und SQLite schreibst du eine Klasse, die Driver implementiert, und registrierst sie. PostgresDriver steht unten für deine eigene Klasse:
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.
Die Treiberklasse muss die Schnittstelle Driver implementieren. Das erste Argument von register() ist die Treiberkennung der Verbindung.
Zurücksetzen
Setze die Factory zum Testen auf ihren Standardzustand zurück:
DriverFactory::reset();
// Reverts to only MySQL and SQLite drivers.
Verbindungshilfsfunktion
Die Klasse Connection erstellt Adapter mit sinnvollen Standardeinstellungen. PDO-Adapter verwenden Exceptions bei Fehlern, assoziativen Abrufmodus, echte vorbereitete Anweisungen und Zeichenfolgen für abgerufene Werte. Der mysqli-Adapter setzt utf8mb4, verwendet den mysqli-Exception-Modus und vorbereitete Anweisungen und normalisiert abgerufene Werte auf dasselbe Format aus Zeichenfolge oder 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() akzeptiert jeden DSN, den PDO öffnen kann, aber merql kann nur über einen registrierten Treiber Snapshots erstellen und anwenden. Eine pgsql:-Verbindung wird geöffnet (wenn pdo_pgsql installiert ist), aber die Konstruktoren von Merql::init(), Snapshotter, Applier und GuardedApplier rufen DriverFactory::create() auf, das RuntimeException: Unsupported database driver: pgsql auslöst, sofern du dafür keinen Treiber registriert hast oder einen übergibst.
Connection::sqlite() aktiviert außerdem automatisch PRAGMA foreign_keys = ON, was SQLite für die Durchsetzung von Fremdschlüsseln benötigt.
Wo Treiber verwendet werden
Treiber kommen überall in merql zum Einsatz:
- Snapshotter verwendet
listTables,readSchemaundselectAll, um den Datenbankzustand zu erfassen. - Applier verwendet
readForeignKeys, um die Reihenfolge der Operationen zu bestimmen, und übergibt den Treiber anSqlGeneratorzum Quoting von Bezeichnern. - SqlGenerator verwendet
quoteIdentifier, um sichere SQL zu erstellen.
Wenn du eine Verbindung an Snapshotter oder Applier übergibst, ohne einen Treiber anzugeben, wird DriverFactory::create() automatisch aufgerufen.