Kapitel 5. Zend_Db

Inhaltsverzeichnis

5.1. Zend_Db_Adapter
5.1.1. Einführung
5.1.2. Quoting gegen SQL Injection
5.1.3. Direkte Abfragen
5.1.4. Transaktionen
5.1.5. Zeilen einfügen
5.1.6. Zeilen aktualisieren
5.1.7. Zeilen löschen
5.1.8. Zeilen holen
5.2. Zend_Db_Profiler
5.2.1. Introduction
5.2.2. Using the Profiler
5.2.3. Advanced Profiler Usage
5.3. Zend_Db_Select
5.3.1. Introduction
5.3.2. Columns FROM a Table
5.3.3. Columns from JOINed Tables
5.3.4. WHERE Conditions
5.3.5. GROUP BY Clause
5.3.6. HAVING Conditions
5.3.7. ORDER BY Clause
5.3.8. LIMIT By Count and Offset
5.3.9. LIMIT By Page And Count
5.4. Zend_Db_Table
5.4.1. Introduction
5.4.2. Getting Started
5.4.3. Table Name and Primary Key
5.4.4. Inserting Rows
5.4.5. Updating Rows
5.4.6. Deleting Rows
5.4.7. Finding Rows by Primary Key
5.4.8. Fetching One Row
5.4.9. Fetching Multiple Rows
5.4.10. Adding Domain Logic
5.5. Zend_Db_Table_Row
5.5.1. Einführung
5.5.2. Zeilen holen
5.5.3. Werte ändern
5.6. Zend_Db_Table_Rowset
5.6.1. Introduction
5.6.2. Fetching a Rowset
5.6.3. Iterating Through the Rowset

5.1. Zend_Db_Adapter

5.1.1. Einführung

Zend_Db_Adapter ist die Datenbankabstraktionsschicht für das Zend Framework. Basierend auf PDO kannst Du Zend_Db_Adapter verwenden, um unter Verwendung der gleichen API zu jedem der unterstützten SQL Datenbanksysteme eine Verbindung aufzubauen bzw. damit zu arbeiten. Diese beinhalten Microsoft SQL Server, MySQL, PostgreSQL, SQLite und andere.

Um eine Instanz von Zend_Db_Adapter für dein spezielles Datenbank Backend zu erstellen, mußt du Zend_Db::factory() mit dem Namen des Adapters und einem Array mit Parametern aufrufen, welche die Verbindung beschreiben. Hier ein Beispiel für einen Verbindungsaufbau zu einer MySQL Datenbank mit Namen "camelot" auf deinem lokalen Server als Benutzer mit Namen "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 mit Namen "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 mit Namen "camelot.sq2": Für eine speicherbasierende SQlite Datenbank gebe keinen DSN Präfix an und verwende einen Datenbanknamen ":memory:".

<?php

require_once 'Zend/Db.php';

$params = array ('dbname' => 'camelot.sq2',
                 'dsnprefix' => 'sqlite2');

$db = Zend_Db::factory('PDO_SQLITE', $params);

?>

So oder so kannst Du die exakt selbe API verwenden, um die Datenbank abzufragen.

5.1.2. Quoting gegen SQL Injection

Du solltest die Werte immer in Anführungszeichen setzen, die in einer SQL Anweisung verwendet werden; dies hilft dabei, Attacken per SQL Injection zu vermeiden. Zend_Db_Adapter stellt zwei Methoden (über das zugrunde liegende PDO Objekt) bereit, um dir zu helfen, werte manuell in Anführungszeichen zu setzen.

Die erste davon ist die quote() Methode. Sie wird einen skalaren Wert entsprechend für deinen Datenbank Adapter in Anführungszeichen setzen; wenn du versuchst, ein Array in Anführungszeichen zu setzen, gibt es einen durch Komma getrennten String mit den Arraywerten zurück, wobei jeder richtig in Anführungszeichen gesetzt wird (dies ist hilfreich für Funktionen, die einen Listenparameter entgegen kommen)).

<?php

// Erstelle ein $db Objekt unter der Annahme eines Mysql Adapters

// setze einen Skalar in Anführungszeichen
$value = $db->quote('St John"s Wort');
// $value ist nun '"St John\"s Wort"' (beachte die umschließenden Anführungszeichen)

// setze ein Array in Anführungszeichen
$value = $db->quote(array('a', 'b', 'c');
// $value ist nun '"a", "b", "c"' (ein durch Komma getrennter String)

?>

Die zweite ist die quoteInto() Methode. Du stellst einen Basisstring mit einem Fragezeichen als Platzhalter bereit und dann einen Skalar oder ein Array, um es in dem String mit Anführungszeichen zu versehen. Dies ist nützlich für die Konstruktion von Abfragen oder Klauseln "as-you-go". Skalare und Arrays verhalten sich genauso wie bei der quote() Methode.

<?php
	
// Erstelle ein $db Objekt unter der Annahme eines Mysql Adapters

// setze einen Skalar in einer WHERE Klausel in Anführungszeichen
$where = $db->quoteInto('id = ?', 1);
// $where ist nun 'id = "1"' (beachte die umschließenden Anführungszeichen)

// setze ein Array in einer WHERE Klausel in Anführungszeichen
$where = $db->quoteInto('id IN(?)', array(1, 2, 3));
// $where ist nun 'id IN("1", "2", "3")' (ein durch Komma getrennter String)

?>

5.1.3. Direkte Abfragen

Sobald du eine Zend_Db_Adapter Instanz hast, kannst du Abfragen direkt in SQL ausführen. Zend_Db_Adapter übergibt diese Abfragen an das zugrunde liegende PDO Objekt, welches sie aufbereitet und ausführt, und gibt dann ein PDOStatement Objekt zurück, um die Ergebnisse (soweit vorhanden) zu verarbeiten.

<?php
	
// Erstelle ein $db Objekt und frage dann die Datenbank
// mit einer korrekt quotierten SQL Abfrage ab.
$sql = $db->quoteInto(
    'SELECT * FROM example WHERE date > ?',
    '2006-01-01'
);
$result = $db->query($sql);

// verwende das PDOStatement $result, um alle Zeilen als Array zu erhalten
$rows = $result->fetchAll();

?>

Du kannst Daten automatisch mit einer Abfrage verbinden. Dies bedeutet, dass du mehrere benannte Platzhalter in der Abfrage setzen und dann ein Array mit den Daten übergeben kannst, welche diese Platzhalter ersetzen. Die ersetzten Werte werden für dich automatisch in Anführungszeichen gesetzt, um größere Sicherheit gegen Attacken 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 zu erhalten
$rows = $result->fetchAll();

?>

Optional möchtest du vielleicht Daten manuell aufbereiten und mit der SQL Abfrage verbinden. Hierfür verwende die prepare() Methode, um ein aufbereitetes PDOStatement zu erhalten, das du direkt verarbeiten kannst.

<?php
	
// Erstelle ein $db Objekt und frage dann die Datenbank ab.
// Dieses Mal bereite ein PDOStatement auf für das manuelle Verbinden.
$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 zu erhalten
$rows = $stmt->fetchAll();

?>

5.1.4. Transaktionen

Standardmäßig sind PDO (und damit auch Zend_Db_Adapter) im "auto-commit" Modus. Das heißt, dass alle Abfragen abgearbeitet werden, wenn sie ausgeführt werden. Wenn du sie innerhalb einer Transaktion ausführen möchtest, rufe einfach die beginTransaction() Methode auf und danach entweder commit() oder rollBack() für deine Änderungen. Zend_Db_Adapter kehrt in den "auto-commit" Modus zurück, bis du beginTransaction() wieder aufrufst.

<?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();
}

?>

5.1.5. Zeilen einfügen

Der Einfachheit halber kannst du die insert() Methode verwenden, um für dich eine INSERT Anweisung zu erstellen und mit den einzufügenden Daten zu verknüpfen. (Die verknüpften Daten werden automatisch in Anführungszeichen gesetzt, um Attacken per SQL Injection zu vermeiden.)

Der Rückgabewert ist nicht die zuletzt eingefügte ID, da eine Tabelle keine automatisch inkrementierte Spalte haben muß. Stattdessen enthält der Rückgabewert die Zahl der beeinflussten Zeilen (normalerweise 1). Wenn du die ID des zuletzt eingefügten Datensatzes haben möchtest, rufe die lastInsertId() Methode nach dem Einfügen auf.

<?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();

?>

5.1.6. Zeilen aktualisieren

Der Einfachheit halber kannst du die update() Methode verwenden, um für dich eine UPDATE Anweisung zu erstellen und mit den zu aktualisierenden Daten zu verknüpfen. (Die verknüpften Daten werden automatisch in Anführungszeichen gesetzt, um Attacken per SQL Injection zu vermeiden.)

Du kannst eine optionale WHERE Klausel übergeben um anzugeben, welche Zeilen aktualisiert werden sollen. (Beachte, dass die WHERE Klausel kein verknüpfter Parameter ist, so dass du die Werte selber in Anführungszeichen setzen musst.)

<?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);

?>

5.1.7. Zeilen löschen

Der Einfachheit halber kannst du die delete() Methode verwenden, um für dich eine DELETE Anweisung zu erstellen. Du kannst eine optionale WHERE Klausel übergeben um anzugeben, welche Zeilen gelöscht werden sollen. (Beachte, dass die WHERE Klausel kein verknüpfter Parameter ist, so dass du die Werte selber in Anführungszeichen setzen musst.)

<?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);

?>

5.1.8. Zeilen holen

Obwohl du die Datenbank direkt mit der query() Methode abfragen kannst, wirst du häufig nur Zeilen selektieren und die Ergebnisse zurückerhalten wollen. Der Satz von fetch*() Methoden macht dies für dich. Für jede der fetch*() Methoden, übergibst du eine SQL SELECT Anweisung; wenn du benannte Platzhalter in der Anweisung verwendest, kannst du zudem ein Array mit zu verknüpfenden Werte übergeben, die in Anführungszeichen gesetzt und in der Anweisung ausgetauscht werden. Die fetch*() Methoden lauten:

  • 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 Splate wird als Array Schlüssel verwendet
$result = $db->fetchAssoc(
    "SELECT * FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// hole die erste Splate aller 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 einen Satz 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 Zeile
$result = $db->fetchRow(
    "SELECT * FROM round_table WHERE first_name = :name",
    array('name' => 'Lancelot')
);

?>