Inhaltsverzeichnis
Zend_Db_Adapter
ist die Datenbankabstraktionsschicht des Zend-Frameworks.
Sie basiert auf PDO und erlaubt es, über eine einheitliche API (Schnittstelle) Verbindungen
zu allen von PDO unterstützten Datenbanksystemen aufzubauen und mit diesen zu arbeiten.
Unterstützte Datenbanken sind unter anderem: Microsoft SQL Server, MySQL, PostgreSQL und SQLite.
Um eine Instanz von Zend_Db_Adapter
für ein spezielles Datenbank-Backend
zu erstellen muss man Zend_Db::factory()
mit dem Namen des Adapters und
einem Array von Parametern aufrufen, welche die Verbindung beschreiben. Hier ein
Beispiel für einen Verbindungsaufbau zu einer MySQL-Datenbank namens "camelot" auf
einem lokalen Server unter Verwendung des Benutzernamens "malory":
<?php require_once 'Zend/Db.php'; $params = array ('host' => '127.0.0.1', 'username' => 'malory', 'password' => '******', 'dbname' => 'camelot'); $db = Zend_Db::factory('PDO_MYSQL', $params); ?>
Ähnlich erfolgt der Verbindungsaufbau zu einer SQlite-Datenbank namens "camelot.sq3":
<?php require_once 'Zend/Db.php'; $params = array ('dbname' => 'camelot.sq3'); $db = Zend_Db::factory('PDO_SQLITE', $params); ?>
Ähnlich erfolgt der Verbindungsaufbau zu einer SQLite2-Datenbank namens "camelot.sq2":
<?php require_once 'Zend/Db.php'; $params = array ('dbname' => 'camelot.sq2', 'dsnprefix' => 'sqlite2'); $db = Zend_Db::factory('PDO_SQLITE', $params); ?>
Wenn eine im RAM liegende SQlite-Datenbank benutzt werden soll wird kein DSN-Präfix angegeben und der Datenbankname lautet ":memory:".
So oder so kann immer die gleiche API verwendet werden um Abfragen auf die Datenbank durchzuführen.
Das so genannte Quoting sollte auf alle Werte angewendet werden, die in SQL-Anweisungen
eingesetzt werden; dies hilft dabei, Angriffen per SQL-Injection vorzubeugen.
Zend_Db_Adapter
stellt (über das zugrunde liegende PDO Objekt)
zwei hilfreiche Methoden für diesen Zweck bereit.
Die erste davon ist die quote()
-Methode. Sie nimmt die für den jeweils
verwendeten Datenbank-Adapter nötigen Umwandlungen vor; der Methode kann auch ein Array
übergeben werden, dann gibt sie einen durch Kommata getrennten String mit den Array-Werten
zurück, wobei jeder Wert entsprechend umgeschrieben wird (dies ist hilfreich für Funktionen,
die einen Listen-Parameter erwarten).
<?php // Erstelle ein $db-Objekt (am Beispiel eines Mysql-Adapters) // Benutzung von quote() für einen einzelnen Wert $value = $db->quote('St John"s Wort'); // $value ist nun '"St John\"s Wort"' (beachten Sie die umschließenden Anführungszeichen) // Benutzung von quote() für ein Array $value = $db->quote(array('a', 'b', 'c'); // $value ist nun '"a", "b", "c"' (ein durch Kommata getrennter String) ?>
Die Zweite ist die quoteInto()
-Methode. Sie erwarten einen String mit
einem Fragezeichen als Platzhalter und entweder einen einzelnen Wert oder ein Array von Werten,
der/die an dieser Stelle eingefügt werden soll/en.
Dies ist nützlich um Abfragen oder Bedingungen auf die Schnelle zu generieren.
Die Behandlung der Werte ist dabei identisch wie bei der Nutzung der quote()
-Methode.
<?php // Erstelle ein $db-Objekt (am Beispiel eines Mysql-Adapters) // setze einen einzelnen Wert in eine WHERE-Bedingung ein $where = $db->quoteInto('id = ?', 1); // $where ist nun 'id = "1"' (beachte die umschließenden Anführungszeichen) // setze die Inhalte eines Arrays in eine WHERE-Bedingung ein $where = $db->quoteInto('id IN(?)', array(1, 2, 3)); // $where ist nun 'id IN("1", "2", "3")' (ein durch Kommata getrennter String) ?>
Nachdem man eine Instanz von Zend_Db_Adapter
hat, kann man direkt SQL-Abfragen ausführen.
Zend_Db_Adapter
übergibt diese Abfragen an das zugrunde
liegende PDO-Objekt, welches sie aufbereitet und ausführt, und gibt ein
PDOStatement-Objekt zurück, damit man die Ergebnisse (soweit vorhanden) weiter verarbeiten kann.
<?php // Erstelle ein $db-Objekt und stelle dann eine // sicher formatierte SQL-Abfrage an die Datenbank. $sql = $db->quoteInto( 'SELECT * FROM example WHERE date > ?', '2006-01-01' ); $result = $db->query($sql); // verwende das PDOStatement $result, um alle Zeilen als Array abzurufen $rows = $result->fetchAll(); ?>
Man kann Daten automatisch in eine Abfrage einbinden. Das bedeutet, dass man mehrere benannte Platzhalter in der Abfrage unterbringen und dann ein Array mit den Daten übergeben kann, welche diese Platzhalter ersetzen. Die ersetzten Werte werden dabei automatisch umgeschrieben, um größere Sicherheit gegen Angriffe per SQL-Injection zu bieten.
<?php // Erstelle ein $db-Objekt und frage dann die Datenbank ab. // Dieses Mal: Verwende Platzhalter. $result = $db->query( 'SELECT * FROM example WHERE date > :placeholder', array('placeholder' => '2006-01-01') ); // verwende das PDOStatement $result, um alle Zeilen als Array abzurufen $rows = $result->fetchAll(); ?>
Optional ist es auch möglich, Daten manuell aufzubereiten und mit der SQL-Abfrage zu
verbinden. Hierfür verwendet man die prepare()
-Methode, um ein vorbereitetes
PDOStatement
zu erhalten, welches man direkt bearbeiten kann.
<?php // Erstelle ein $db-Objekt und frage dann die Datenbank ab. // Dieses Mal: Bereite ein PDOStatement für das manuelle Verbinden auf. $stmt = $db->prepare('SELECT * FROM example WHERE date > :placeholder'); $stmt->bindValue('placeholder', '2006-01-01'); $stmt->execute(); // verwende das PDOStatement $result, um alle Zeilen als Array abzurufen $rows = $stmt->fetchAll(); ?>
Standardmäßig sind PDO (und damit auch Zend_Db_Adapter
) im "auto-commit"
Modus. Das heißt, dass alle Abfragen sofort unwiderruflich ausgeführt werden, wenn sie gestellt werden.
Wenn sie innerhalb einer Transaktion ausgeführt werden sollen, kann einfach die Methode
beginTransaction()
aufgerufen werden, dann besteht die Möglichkeit,
Änderungen entweder mit commit()
zu bestätigen oder mit
rollBack()
rückgängig zu machen. Zend_Db_Adapter
kehrt
in den "auto-commit" Modus zurück, bis beginTransaction()
wieder
aufgerufen wird.
<?php // Erstelle ein $db-Objekt und starte dann eine Transaktion $db->beginTransaction(); // Versuche eine Abfrage // wenn erfolgreich, verarbeite die Änderungen // wenn nicht erfolgreich, setze Änderungen zurück try { $db->query(...); $db->commit(); } catch (Exception $e) { $db->rollBack(); echo $e->getMessage(); } ?>
Der Einfachheit halber kann man die insert()
-Methode verwenden, um eine
INSERT Anweisung zu erstellen und mit den einzufügenden Daten zu verknüpfen.
(Die verknüpften Daten werden automatisch umgeschrieben, um Angriffe per
SQL-Injection zu vermeiden.)
Der Rückgabewert ist nicht die zuletzt eingefügte ID, da eine
Tabelle keine automatisch inkrementierte Spalte haben muss. Stattdessen enthält der
Rückgabewert die Zahl der beeinflussten Zeilen (normalerweise 1). Um die ID des
zuletzt eingefügten Datensatzes zu ermitteln, kann man die lastInsertId()
-Methode
nach dem Einfügen aufrufen.
<?php // // INSERT INTO round_table // (noble_title, first_name, favorite_color) // VALUES ("King", "Arthur", "blue"); // // Erstelle ein $db-Objekt und dann... // die einzufügenden Daten im Spalte => Wert Format $row = array ( 'noble_title' => 'King', 'first_name' => 'Arthur', 'favorite_color' => 'blue', ); // die Tabelle, in der die Daten eingefügt werden sollen $table = 'round_table'; // füge die Daten ein und hole die ID der eingefügten Zeile $rows_affected = $db->insert($table, $row); $last_insert_id = $db->lastInsertId(); ?>
Der Einfachheit halber kann man die update()
-Methode verwenden, um
eine UPDATE-Anweisung zu erstellen und mit den zu aktualisierenden Daten zu
verknüpfen. (Die verknüpften Daten werden automatisch umgeschrieben, um
Angriffe per SQL-Injection zu vermeiden.)
Es ist möglich, eine WHERE-Klausel zu übergeben um festzulegen, welche Zeilen aktualisiert werden sollen.
<?php // // UPDATE round_table // SET favorite_color = "yellow" // WHERE first_name = "Robin"; // // Erstelle ein $db-Objekt und dann... // die neuen Werte, die aktualisiert werden sollen, im Spalte => Wert Format. $set = array ( 'favorite_color' => 'yellow', ); // die zu aktualisierende Tabelle $table = 'round_table'; // die WHERE-Klausel $where = $db->quoteInto('first_name = ?', 'Robin'); // aktualisiere die Tabelle und hole die Anzahl der beeinflussten Zeilen $rows_affected = $db->update($table, $set, $where); ?>
If you have multiple WHERE clauses that should be applied to the UPDATE query, you can provide an array of
such clauses to the update()
method. These clauses are combined with the AND operator.
Combining clauses with the OR operator must be performed manually:
<?php $set = array('favorite_color' => 'yellow'); // multiple conditions combined with AND $where = array( $db->quoteInto('first_name = ?', $firstName), $db->quoteInto('noble_title = ?', $nobleTitle) ); $count = $db->update('round_table', $set, $where); // multiple conditions combined with OR $firstNameOne = $db->quote($firstNameOne); $firstNameTwo = $db->quote($firstNameTwo); $where = "first_name = $firstNameOne OR first_name = $firstNameTwo"; $count = $db->update('round_table', $set, $where); ?>
Anmerkung | |
---|---|
The values and identifiers of the WHERE clause(s) are not quoted for you. If you have values or
identifiers that require quoting, you are responsible for doing this. Use the |
Der Einfachheit halber kann man die delete()
-Methode verwenden, um
eine DELETE Anweisung zu erstellen. Es ist möglich, eine WHERE-Klausel zu
übergeben um anzugeben, welche Zeilen gelöscht werden sollen. (Man beachte, dass
die WHERE-Klausel kein verknüpfter Parameter ist, so dass die enthaltenen Werte
manuell aufbereitet werden müssen, um Angriffe per SQL-Injection zu vermeiden.)
<?php // // DELETE FROM round_table // WHERE first_name = "Patsy"; // // Erstelle ein $db-Objekt und dann... // die Tabelle, aus der gelöscht werden soll $table = 'round_table'; // die WHERE-Klausel $where = $db->quoteInto('first_name = ?', 'Patsy'); // aktualisiere die Tabelle und hole die Anzahl der beeinflussten Zeilen $rows_affected = $db->delete($table, $where); ?>
As with the update()
method, you may use an
array of WHERE clauses for the $where
argument to the delete()
method.
Anmerkung | |
---|---|
The values and identifiers of the WHERE clause(s) are not quoted for you. If you have values or
identifiers that require quoting, you are responsible for doing this. Use the |
Obwohl man die Datenbank direkt mit der query()
-Methode abfragen kann,
will man meistens nur Zeilen selektieren und die Ergebnisse zurückerhalten. Diese
Aufgabe erledigen die fetch*()
-Methoden. Für jede der
fetch*()
-Methoden übergibt man eine SQL-SELECT-Anweisung; wenn man
benannte Platzhalter in der Anweisung verwendet, kann man zudem ein Array mit zu
verknüpfenden Werten übergeben, die dann zum Schutz gegen SQL-Injection aufbereitet
und in die Anweisung eingesetzt werden. Diese fetch*()
-Methoden gibt es:
fetchAll()
fetchAssoc()
fetchCol()
fetchOne()
fetchPairs()
fetchRow()
<?php // Erstelle ein $db-Objekt und dann... // hole alle Spalten aller Zeilen als sequentielles Array $result = $db->fetchAll( "SELECT * FROM round_table WHERE noble_title = :title", array('title' => 'Sir') ); // hole alle Spalten aller Zeilen als assoziatives Array // die erste Spalte wird als Array-Schlüssel verwendet $result = $db->fetchAssoc( "SELECT * FROM round_table WHERE noble_title = :title", array('title' => 'Sir') ); // hole die erste Spalte aller zurück gelieferten Zeilen $result = $db->fetchCol( "SELECT first_name FROM round_table WHERE noble_title = :title", array('title' => 'Sir') ); // hole nur den ersten Wert $result = $db->fetchOne( "SELECT COUNT(*) FROM round_table WHERE noble_title = :title", array('title' => 'Sir') ); // hole eine Sequenz von Schlüssel-Wert-Paaren; die erste Spalte ist // der Array-Schlüssel, die zweite Spalte ist der Array-Wert $result = $db->fetchPairs( "SELECT first_name, favorite_color FROM round_table WHERE noble_title = :title", array('title' => 'Sir') ); // hole nur die erste der zurück gelieferten Zeilen $result = $db->fetchRow( "SELECT * FROM round_table WHERE first_name = :name", array('name' => 'Lancelot') ); ?>
[1] Der englische Begriff "quoting" bezeichnet das Entfernen einer Sonderbedeutung eines Zeichens durch Voranstellen oder Umklammern mit speziellen Zeichen (Backslash, Anführungsstriche usw.) Die genauen Regeln für das jeweilige Quoting sind abhängig vom Zielsystem, an welches die Daten übergeben werden.