Database
Table of Contents
Aufbau
Das SetaFramework beinhaltet die Database-Klasse um mit einer Datenbank zu kommunizieren. Die Database-Klasse ist grundsätzlich ein Wrapper von PDO. Aber anstatt lediglich einen anderen internen Treiber zu verwenden, wie bei PDO sind die unterstützten Plattformen als einzelne Klassen implementiert, welche die Database-Klasse erweitern:
- Mysql - beste Unterstützung
- Sqlite (keine Unterstützung für den Database Manager)
- Sqlsrv (keine Unterstützung für den Database Manager)
Wichtig sind vor allem folgende Methoden:
executeQuery()
Executes the query.
factory()
Factory method to create an instance of the database.
queryAll()
Returns an associative array with all data received by the query
queryAllAsGenerator()
queryColumn()
Returns a specific column by the given query
queryOne()
Returns the first column in the first row received by the query
queryRow()
Returns the first received row by the query
DatabaseConnectionManager
Vor SF v5.0 musste jede Applikation sich selbstständig darum kümmern eine Verbindung zur Datenbank aufzubauen. Da aber im gleichen Zuge fast alle Applikationen sich mit der selben Datenbank verbinden mussten, entstand hierbei eine Kopplung der Applikationen unter einander. Beispiel: Konquadrat und andere Applikationen besaßen ein "useSetasite"-Flag bei der Datenbank-Konfiguration.
Aus diesem Grund gibt es nun einen globalen DatabaseConnectionManager bei dem die entsprechenden Applikationen ihre Datenbank-Verbindung anfragen können.
Der DatabaseConnectionManager besitzt eine eigene Konfiguration und kann mehrere Datenbanken konfiguriert haben und über einen eindeutigen Identifier können die Datenbank-Verbindungen aufgerufen werden.
; bootstrap.ini database = @@db.ini ; ------------------------------ ; db.ini default.driver = mysql default.dsn = "$MYSQL_DSN$" default.username = "$MYSQL_USER$" default.password = "$MYSQL_PASSWORD$" default.logger.enabled = 1 default.logger.handler = additionalBlubLogger secondConnection.driver = sqlite secondConnection.dsn = sqlite::memory: ; ------------------------------ ; application.ini - neue Variante über den ConnectionManager db = secondConnection ; optional, falls nicht hinterlegt wird "default" verwendet ; ------------------------------ ; application.ini - alte Fallback Variante, die am ConnectionManager vorbei arbeitet db.driver = mysql db.dsn = "$MYSQL_DSN$" db.username = "$MYSQL_USER$" db.password = "$MYSQL_PASSWORD$"
// Konfiguration vom DI
$di = $this->getDi();
$di->addAlias(
Database::class,
static function (DatabaseConnectionManager $connectionManager, ApplicationConfig $config) {
return $connectionManager->getConnectionByApplicationConfig($config);
}
);
QueryBuilder
Das SetaFramework beinhaltet einen QueryBuilder, der es ermöglicht objektorientiert Queries zu schreiben. Zusätzlich nutzen wir diesen ebenfalls um möglichst elegant SQL-Injections zu verhindern, da der QueryBuilder selbstständig quotet und wir somit nicht auf preparedStatements angewiesen sind. Die Syntax der Klassen ist dabei so nah wie möglich am echten SQL Query gehalten.
Beispiel:
<?php
$query = (
Database\Query::select([
['users.id', 'id'],
['users.name', 'name'],
['permissions.flags', 'permissions']
])
->from('users')
->joinInner('permissions')->on('users.id', '=', 'permissions.userId')
->where('age', '>', 10)
);
/**
* @var Database $database
*/
$database->queryAll($query);
Quoten im QueryBuilder
Die Parameter können unterschiedlich gequotet werden. PDO kann für üblich eigentlich nur Werte quoten und keine Identifier (ein Identifier kann z.B. ein Spaltenname oder ein Tabellenname sein). Die einzelnen Methoden quoten bestimmte Parameter anders als Andere und das Standardverhalten ist nicht immer das gewünschte. An den einzelnen Methoden steht immer dran als was der Parameter gequotet wird: Wert oder Identifier.
Um ein bestimmtes Verhalten zu erzwingen kann man den Parameter in einer ValueExpression oder einem Identifier kapseln.
Um das quoten komplett zu verhindern, weil man z.B. eine Mysql-Methode verwenden möchte, muss man den entsprechenden Text in einer Expression kapsel. (z.B. ->where('creation_date', '>', new Expression('now()')))
Hierbei sollte umbedingt beachtet werden, dass man hier durch keine SQL-Injections ermöglicht.
Ansonsten gibt es noch eine besondere Klasse zum quoten: QuoteLaterExpression
Die QuoteLaterExpression erwartet eine Closure als Parameter. Sobald die Expression gequotet wird, wird die Closure aufgerufen mit einem QuoteInterface. Die Closure MUSS einen string zurück geben.
