Ab Drupal7 wurde der Datenbank Layer komplett überarbeitet bzw. neu geschrieben. Nun lassen sich neben PostgreSQL und MySQL zum Beispiel auch SQLite nutzen. Wobei zukünftig auch andere Schnittstellen hinzukommen werden, da auf PDO gesetzt wird. Neben der reinen Drupal Datenbank können jetzt auch ohne weiteres Zusatz-Datenbanken in den Verbindungseinstellungen (settings.php) genutzt werden. So kann man z.B. die Datenbank mittels Lastenausgleich auf master und slave aufteilen oder auch komplett fremden Datenbank nutzen.
Verbindung definieren
Alle Datenbankverbindungen werden innerhalb der Datei settings.php meist unter sites/all definiert. Nach einer Standard Drupal Installation findet man hier üblicherweise nur eine Datenbankverbindung:
//mysql $databases['default']['default'] = array( 'driver' => 'mysql', 'database' => 'drupaldb1', 'username' => 'username', 'password' => 'secret', 'host' => 'dbserver1', ); //sqlite $databases['default']['extra'] = array( 'driver' => 'sqlite', 'file' => 'files/extradb.sqlite', );
Durch die Schlüsselkeys extra und default kann man die Datenbanken dann direkt ansprechen.
Datenbank nutzen
Sämtliche Datenbankfunktion nutzen logischerweise die default Verbindung als Standard. Sollten Verbindungsnamen mit slave vorhanden so wird wohl ein internen Algorithmus genutzt der dann zwischen master und slave wechselt. Habe ich bisher allerdings noch nicht getestet. Möchte man also eine extra Datenbank nutzen sollte man diese Namen meiden.
Mittels target Parameter für alle Drupal-Datenbankfunktionen kann definiert werden, auf welche Datenbank zugegriffen werden soll. Alternativ kann die default Verbindung auch mit der Funktion db_set_active überschrieben werden. Mehr dazu gibt es hier: Database configuration | drupal.org
$result = db_query("SELECT nid, title FROM {node}", array(), array(
'target' => 'extra',
'fetch' => PDO::FETCH_ASSOC,
));
$record = $result->fetchAll();Die genannten Aufruf kann man auch wunderbar in eine extra Funktion auslagern. So kann man z.B. für eigene Erweiterungen gezielt alle Abfragen umleiten.
function MYMODULE_database_result($query, $paramter = array()) {
$result = db_query($query, $paramter, array(
'target' => 'slave',
'fetch' => PDO::FETCH_ASSOC,
));
return $result;
}
// result as array
$res = MYMODULE_database_result('select * from table WHERE hash=:hash' , array(':hash' => $hash))->fetchAll()
print_r($res);Es wird übrigens erst dann eine Verbindung zu Datenbank aufgebaut, wenn diese benötigt wird.
Daten auslesen
Wie bei älteren Drupal Version auch steht für Abfrage die Funktion db_query() bereit. Sie wurde nun durch die neue PDO Schnittstelle durch weitere Parameter erweitert. Zusätzlich wurde der Rückgabe Wert angepasst, der jetzt ein Objekt zurück gibt, mit dem wieder viel einfach die Ausgabe steuern können. Neben einem Array oder einzelnem Feld kann das Ergebnis auch direkt in eine Klasse übergeben werden. Wem die genannten Beispiele nicht reichen sollte man hier nachsehen: Static queries | drupal.org
$result = db_query("SELECT nid, title FROM {node} WHERE type = :type", array(
':type' => 'page',
));Mit dem $result Objekt können wir jetzt selber definieren, wie die Daten ausgegeben werden soll.
// Retrieve all records into an indexed array. $result->fetchAll(); // Retrieve all records into an associative array keyed by the field in the result specified. $result->fetchAllAssoc($field); // Retrieve a 2-column result set as an associative array of field 1 => field 2. $result->fetchAllKeyed(); // Retrieve a 1-column result set as one single array. $result->fetchCol();
Am meisten nutze ich fetchAll(), es liefert ein Array zurück, was man dann in Drupal an diverse Theme Functions übergeben kann.
Insert oder Update
Jeder kennt sicher das Problem: Wenn man eine Tabellenzeile eintragen will und vorher prüfen muss, ob der Datensatz bereits vorhanden ist. Das übernimmt ab jetzt zentral die Funktion db_merge(). Da dieser Syntax je nach verwendeter Datenbank anderes aussieht, sollte nur diese Funktion genutzt werden, ebenso könnte natürlich auch db_query() genutzt werden. Durch db_merge übernimmt Drupal die Generierung des SQL Statement, so dass wird uns keine Gedanken machen müssen.
$status = db_merge('example')
->key(array('name' => $name))
->fields(array(
'field1' => $value1,
'field2' => $value2,
))
->execute();db_merge() gibt übrigens als Rückgabe Wert nur aus ob der Datensatz geupdated bzw. neu erstellt wurde. Für z.B. den Primärschlüssel oder eine üblich ID muss man eine gesonderte Abfrage erstellen.
switch ($status) {
case SAVED_NEW:
// INSERT
break;
case SAVED_UPDATED:
// Update
break;
}Auch Interessant ist, dass wir je nach Update oder Insert andere Feldwerte übergeben können.
Wenn der Datensatz upgedatet wird, wird der Inhalt von $alternate1 genutzt, egal was vorher über fields-> definiert wurde
->update(array(
'field1' => $alternate1,
))Das Feld Field1 wird um eins erhöht. Also ein Zähler
->expression('field1', 'field1 + :inc', array(':inc' => 1))Mehr zu den db_merge gibts hier: Merge queries | drupal.org
UTF-8
Nutzt man Umlaute oder andere Zeichen muss man dafür sorgen, dass alle Daten, die an die Drupal Datenbankfunktionen übergeben werden, auch in UTF-8 codiert sind. Ansonsten kriegt man einen Leeren PDO Fehler Präsendiert, mit dem an logischerweise erst mal gar nichts anfangen kann. Sollte man die Daten also konvertieren müssen nutzt man die Drupal Funktion check_plain() alternativ kann man auch die PHP Funktion utf8_encode() nutzen.