Zum Inhalt springen

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.

PHP
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:

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;
}
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.

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

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.

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 erkennt den passenden Treiber anhand von DatabaseConnection::driverName() automatisch.

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

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:

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.

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:

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

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() 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, readSchema und selectAll, um den Datenbankzustand zu erfassen.
  • Applier verwendet readForeignKeys, um die Reihenfolge der Operationen zu bestimmen, und übergibt den Treiber an SqlGenerator zum 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.