| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.db.table.rowset">
- <title>Zend_Db_Table_Rowset</title>
- <sect2 id="zend.db.table.rowset.introduction">
- <title>Einführung</title>
- <para>
- Wenn eine Datenbankabfrage über eine Tabellenklasse ausgeführt wird, genauer über deren
- Methoden <methodname>find()</methodname> und <methodname>fetchAll()</methodname>, wird
- das Ergebnis als Objekt vom Typ <classname>Zend_Db_Table_Rowset_Abstract</classname>
- zurückgegeben. Ein Zeilensatz enthält eine Sammlung von Objekten die von
- <classname>Zend_Db_Table_Row_Abstract</classname> abgeleitet sind. Man kann durch das
- Rowset iterieren und auf individuelle Zeilen Objekte zugreifen, sowie Daten in Zeilen
- lesen und modifizieren.
- </para>
- </sect2>
- <sect2 id="zend.db.table.rowset.fetch">
- <title>Einen Zeilensatz lesen</title>
- <para>
- <classname>Zend_Db_Table_Abstract</classname> bietet die Methoden
- <methodname>find()</methodname> und <methodname>fetchAll()</methodname>, die beide ein
- Objekt vom Typ <classname>Zend_Db_Table_Rowset_Abstract</classname> zurückgeben.
- </para>
- <example id="zend.db.table.rowset.fetch.example">
- <title>Einen Zeilensatz lesen</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $rowset = $bugs->fetchAll("bug_status = 'NEW'");
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.rowset.rows">
- <title>Zeilen aus einem Zeilensatz auslesen</title>
- <para>
- Der Zeilensatz selber ist normalerweise weniger interessant als die Zeilen, die er
- enthält. Dieser Abschnitt zeigt, wie die Zeilen, die im Zeilensatz enthalten sind,
- auslesbar sind.
- </para>
- <para>
- Eine normale Abfrage gibt null Zeilen zurück, wenn keine Zeilen in der Datenbank die
- Bedingungen der Abfrage erfüllt. Daher kann eine Zeilensatz-Objekt auch null
- Zeilenobjekte enthalten. Weil <classname>Zend_Db_Table_Rowset_Abstract</classname> auch
- das Interface <classname>Countable</classname> (dt.: Zählbar) implementiert, kann die
- Funktion <methodname>count()</methodname> genutzt werden, um die Anzahl der Zeilen im
- Zeilensatz zu erhalten.
- </para>
- <example id="zend.db.table.rowset.rows.counting.example">
- <title>Zeilen in einem Zeilensatz zählen</title>
- <programlisting language="php"><![CDATA[
- $rowset = $bugs->fetchAll("bug_status = 'FIXED'");
- $rowCount = count($rowset);
- if ($rowCount > 0) {
- echo "$rowCount Zeilen gefunden!";
- } else {
- echo 'keine Zeilen für die Abfrage gefunden.';
- }
- ]]></programlisting>
- </example>
- <example id="zend.db.table.rowset.rows.current.example">
- <title>Eine einzelne Zeile aus einem Zeilensatz auslesen</title>
- <para>
- Die einfachste Art, eine Zeile aus einem Zeilensatz auszulesen, ist die Methode
- <methodname>current()</methodname>. Diese ist vor allem dann nützlich, wenn der
- Zeilensatz genau eine Zeile enthält.
- </para>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $rowset = $bugs->fetchAll("bug_id = 1");
- $row = $rowset->current();
- ]]></programlisting>
- </example>
- <para>
- Wenn der Zeilensatz keine Zeilen enthält, gibt <methodname>current()</methodname> den
- <acronym>PHP</acronym> Wert <constant>NULL</constant> zurück.
- </para>
- <example id="zend.db.table.rowset.rows.iterate.example">
- <title>Einen Zeilensatz durchlaufen</title>
- <para>
- Objekte, die von <classname>Zend_Db_Table_Rowset_Abstract</classname> abstammen,
- implementieren das <classname>SeekableIterator</classname> Interface, was bedeutet,
- dass es mit <methodname>foreach()</methodname> durchlaufen werden kann. Jeder Wert,
- der auf diesem Weg zurückgegeben wird, ist ein
- <classname>Zend_Db_Table_Row_Abstract</classname>-Objekt, das zu einem Eintrag in
- der Tabelle gehört.
- </para>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- // Alle Zeilen aus der Tabelle lesen
- $rowset = $bugs->fetchAll();
- foreach ($rowset as $row) {
- // Ausgabe: 'Zend_Db_Table_Row' oder ähnlich,
- // je nach benutzter Zeilenklasse
- echo get_class($row) . "\n";
- // Spalte einer Zeile auslesen
- $status = $row->bug_status;
- // eine Spalte der aktuellen Zeile modifizieren
- $row->assigned_to = 'mmouse';
- // Änderung in der Datenbank speichern
- $row->save();
- }
- ]]></programlisting>
- </example>
- <example id="zend.db.table.rowset.rows.seek.example">
- <title>Eine bekannte Position in einem Rowset suchen</title>
- <para>
- <classname>SeekableIterator</classname> erlaubt es eine Position zu suchen auf die
- der Iterator springen soll. Hierfür kann einfach die <methodname>seek()</methodname>
- Methode verwendet werden. Es kann ein Integer übergeben werden die der Nummer der
- Zeile repräsentiert auf die das Rowset als nächstes zeigen soll, wobei man nicht
- vergessen sollte das der Index mit 0 beginnt. Wenn der Index falsch ist, z.b. nicht
- existiert, wird eine Ausnahme geworfen. Man sollte <methodname>count()</methodname>
- verwenden um die Anzahl an Ergebnissen zu prüfen bevor eine Position gesucht wird.
- </para>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- // Alle Einträge von der Tabelle holen
- $rowset = $bugs->fetchAll();
- // Den Iterator zum 9ten Element bringen (null ist das erste Element) :
- $rowset->seek(8);
- // es empfangen
- $row9 = $rowset->current();
- // und es verwenden
- $row9->assigned_to = 'mmouse';
- $row9->save();
- ]]></programlisting>
- </example>
- <para>
- <methodname>getRow()</methodname> erlaubt es eine spezielle Zeile im Rowset zu erhalten
- wenn dessen Position bekannt ist; trotzdem sollte nicht vergessen werden dass die
- Position mit dem Index Null beginnt. Der erste Parameter für
- <methodname>getRow()</methodname> ist ein Integer für die gewünschte Position. Der
- zweite optionale Parameter ist ein Boolean; Es teilt dem Rowset Iterator mit ob er zur
- gleichen Zeit diese Position suchen muss, oder nicht (standard ist
- <constant>FALSE</constant>). Diese Methode gibt standardmäßig ein
- <classname>Zend_Db_Table_Row</classname> Objekt zurück. Wenn die angefragte Position
- nicht existiert wird eine Ausnahme geworfen. Hier ist ein Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- // Alle Einträge von der Tabelle holen
- $rowset = $bugs->fetchAll();
- // Sofort das 9te Element holen:
- $row9->getRow(8);
- // und es verwenden:
- $row9->assigned_to = 'mmouse';
- $row9->save();
- ]]></programlisting>
- <para>
- Sobald der Zugriff auf ein Zeilenobjekt besteht, kann dieses mit den Methoden
- manipuliert werden, die in <link linkend="zend.db.table.row">Zend_Db_Table_Row</link>
- beschrieben werden.
- </para>
- </sect2>
- <sect2 id="zend.db.table.rowset.to-array">
- <title>Einen Zeilensatz als Array lesen</title>
- <para>
- Auf die gesamten Daten in einem Zeilensatz kann mithilfe der Methode
- <methodname>toArray()</methodname> des Zeilensatz-Objekts auch als Array zugegriffen
- werden. Diese Methode gibt ein Array mit einem Eintrag je Zeile zurück. Jeder dieser
- Einträge ist ein assoziatives Array mit Spaltennamen als Schlüsseln und deren Daten als
- Werten.
- </para>
- <example id="zend.db.table.rowset.to-array.example">
- <title>Benutzung von toArray()</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $rowset = $bugs->fetchAll();
- $rowsetArray = $rowset->toArray();
- $rowCount = 1;
- foreach ($rowsetArray as $rowArray) {
- echo "Zeile #$rowCount:\n";
- foreach ($rowArray as $column => $value) {
- echo "\t$column => $value\n";
- }
- ++$rowCount;
- echo "\n";
- }
- ]]></programlisting>
- </example>
- <para>
- Das Array, das von <methodname>toArray()</methodname>zurückgegeben wird, ist nicht
- update-fähig. Die Werte des Arrays können wie bei jedem Array modifiziert werden, aber
- Änderungen an diesem Array werden nicht direkt in der Datenbank gespeichert.
- </para>
- </sect2>
- <sect2 id="zend.db.table.rowset.serialize">
- <title>Einen Zeilensatz serialisieren / deserialisieren</title>
- <para>
- Objekte vom Typ <classname>Zend_Db_Table_Rowset_Abstract</classname> sind serialisierbar
- auf eine ähnliche Art, wie auch einzelne Zeilen-Objekte serialisierbar und
- deserialisierbar sind.
- </para>
- <example id="zend.db.table.rowset.serialize.example.serialize">
- <title>Einen Zeilensatz serialisieren</title>
- <para>
- <acronym>PHP</acronym>s <methodname>serialize()</methodname>-Funktion wird genutzt,
- um einen Byte-Stream zu erzeugen. Dieser repräsentiert das Zeilensatz-Objekt.
- </para>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $rowset = $bugs->fetchAll();
- // Objekt serialisieren
- $serializedRowset = serialize($rowset);
- // Jetzt kann $serializedRowset bspw.
- // in einer Datei gespeichert werden
- ]]></programlisting>
- </example>
- <example id="zend.db.table.rowset.serialize.example.unserialize">
- <title>Einen Zeilensatz deserialisieren</title>
- <para>
- <acronym>PHP</acronym>s <methodname>unserialize()</methodname> stellt aus einer
- Zeichenkette mit einem Byte-Stream ein Objekt wieder her. Die Funktion gibt das
- originale Objekt zurück.
- </para>
- <para>
- Bitte beachten: Das zurückgegebene Zeilensatz-Objekt ist
- <emphasis>nicht mit der Datenbank verbunden</emphasis>. Das Zeilensatz-Objekt kann
- durchlaufen werden und die Zeilenobjekte können gelesen werden, aber es können keine
- Zeilenwerte verändert oder andere Operationen ausgeführt werden, die eine
- Datenbankverbindung benötigen (beispielsweise Abfragen auf verwandte Tabellen).
- </para>
- <programlisting language="php"><![CDATA[
- $rowsetDisconnected = unserialize($serializedRowset);
- // Jetzt können Objekt-Methoden und -Eigenschaften genutzt werden,
- // aber nur lesend.
- $row = $rowsetDisconnected->current();
- echo $row->bug_description;
- ]]></programlisting>
- </example>
- <note>
- <title>Warum werden Zeilensatz-Objekte unverbunden deserialisiert?</title>
- <para>
- Ein serialisiertes Objekt ist eine Zeichenkette, die lesbar für jeden ist, dem sie
- vorliegt. Es könnte ein Sicherheitsrisiko sein, Parameter wie Datenbank-Loginname
- und -Passwort in simplem, unverschlüsseltem Text abzulegen. Es ist nicht
- wünschenswert, solche Daten in einer Textdatei abzulegen, die nicht geschützt ist,
- oder sie in einer E-Mail oder einem anderen Medium zu versenden, das leicht von
- potentiellen Angreifern lesbar ist. Der Leser des serialisierten Objekts sollte es
- nicht benutzen können, um Zugriff zur Datenbank zu erhalten, ohne richtige
- Logindaten zu kennen.
- </para>
- </note>
- <para>
- Ein nicht verbundenes Zeilensatz-Objekt kann mithilfe der Methode
- <methodname>setTable()</methodname> reaktiviert werden. Das Argument dieser Methode ist
- ein valides <classname>Zend_Db_Table_Abstract</classname>-Objekt,
- das vom Benutzer erstellt wird. Für das Erstellen eines Tabellenobjekts wird eine
- aktive Datenbankverbindung benötigt, also wird, indem die Tabelle wieder mit dem
- Zeilenobjekt verknüpft wird, auch der Datenbankzugriff wiederhergestellt. Ab diesem
- Zeitpunkt können Werte in den enthaltenen Zeilenobjekten wieder verändert und in der
- Datenbank gespeichert werden.
- </para>
- <example id="zend.db.table.rowset.serialize.example.set-table">
- <title>Einen Zeilensatz als Live-Daten reaktivieren</title>
- <programlisting language="php"><![CDATA[
- $rowset = unserialize($serializedRowset);
- $bugs = new Bugs();
- // Den Zeilensatz wieder mit einer Tabelle
- // und damit mit einer aktiven Datenbankverbindung verknüpfen
- $rowset->setTable($bugs);
- $row = $rowset->current();
- // Jetzt können wieder Werte geändert und danach gespeichert werden
- $row->bug_status = 'FIXED';
- $row->save();
- ]]></programlisting>
- </example>
- <para>
- Wenn ein Zeilensatz mit <methodname>setTable()</methodname> reaktiviert wird,
- reaktiviert das auch alle enthaltenen Zeilen-Objekte.
- </para>
- </sect2>
- <sect2 id="zend.db.table.rowset.extending">
- <title>Die Zeilensatz-Klasse erweitern</title>
- <para>
- Es können auch alternative Klassen für Zeilensätze benutzt werden, wenn diese
- <classname>Zend_Db_Table_Rowset_Abstract</classname> erweitern. Der Name der eigenen
- Zeilensatz-Klasse wird entweder in der geschützten Tabellenklassen-Eigenschaft
- <varname>$_rowsetClass</varname> oder als Teil des Array-Arguments des Konstruktors
- eines Tabellenobjekts übergeben.
- </para>
- <example id="zend.db.table.rowset.extending.example">
- <title>Eine eigene Zeilensatz-Klasse angeben</title>
- <programlisting language="php"><![CDATA[
- class MyRowset extends Zend_Db_Table_Rowset_Abstract
- {
- // ...Anpassungen
- }
- // Eine eigene Zeilensatz-Klasse angeben, die standardmäßig
- // in allen Instanzen der Tabellenklasse benutzt wird.
- class Products extends Zend_Db_Table_Abstract
- {
- protected $_name = 'products';
- protected $_rowsetClass = 'MyRowset';
- }
- // Oder eine eigene Zeilensatz-Klasse angeben, die in einer
- // Instanz einer Tabellenklasse benutzt wird
- $bugs = new Bugs(array('rowsetClass' => 'MyRowset'));
- ]]></programlisting>
- </example>
- <para>
- Typischerweise reicht die Standardklasse <classname>Zend_Db_Rowset</classname> für die
- meisten Benutzungsfälle aus. Trotzdem könnte es nützlich sein, neue Logik in einen
- Zeilensatz einzubauen, die für eine bestimmte Tabelle nötig ist. Beispielsweise könnte
- eine neue Methode einen Durchschnitt aller Zeilen im Zeilensatz errechnen.
- </para>
- <example id="zend.db.table.rowset.extending.example-aggregate">
- <title>Eine Zeilensatz-Klasse mit einer neuen Methode</title>
- <programlisting language="php"><![CDATA[
- class MyBugsRowset extends Zend_Db_Table_Rowset_Abstract
- {
- /**
- * Suche nach der Zeile im Zeilensatz, deren
- * 'updated_at'-Spalte den größten Wert hat.
- */
- public function getLatestUpdatedRow()
- {
- $max_updated_at = 0;
- $latestRow = null;
- foreach ($this as $row) {
- if ($row->updated_at > $max_updated_at) {
- $latestRow = $row;
- }
- }
- return $latestRow;
- }
- }
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_rowsetClass = 'MyBugsRowset';
- }
- ]]></programlisting>
- </example>
- </sect2>
- </sect1>
|