| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 21587 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.db.table.relationships">
- <title>Zend_Db_Table Relationships</title>
- <sect2 id="zend.db.table.relationships.introduction">
- <title>Einführung</title>
- <para>
- In einer relationalen Datenbank haben Tabellen Relationen zueinander. Eine Entität in
- einer Tabelle kann zu einer oder mehrerer Entitäten in einer anderen Tabelle, durch
- Verwendung von referentiellen Integritätsverknüpfungen die im Datenbank Schema
- definiert sind, verknüpft werden.
- </para>
- <para>
- Die <classname>Zend_Db_Table_Row</classname> Klasse besitzt Methoden für die Abfrage von
- verknüpften Zeilen in anderen Tabellen.
- </para>
- </sect2>
- <sect2 id="zend.db.table.relationships.defining">
- <title>Verknüpfungen definieren</title>
- <para>
- Die Klassen für jede eigene Tabelle müssen durch das Erweitern der abstrakten Klasse
- <classname>Zend_Db_Table_Abstract</classname>, wie in <link
- linkend="zend.db.table.defining">diesem Kapitel</link> beschrieben, definiert
- werden. Siehe auch in <link linkend="zend.db.adapter.example-database">diesem
- Kapitel</link> für die Beschreibung einer Beispieldatenbank für welche der folgende
- Beispielcode designed wurde.
- </para>
- <para>
- Anbei sind die <acronym>PHP</acronym> Klassendefinitionen für diese Tabellen:
- </para>
- <programlisting language="php"><![CDATA[
- class Accounts extends Zend_Db_Table_Abstract
- {
- protected $_name = 'accounts';
- protected $_dependentTables = array('Bugs');
- }
- class Products extends Zend_Db_Table_Abstract
- {
- protected $_name = 'products';
- protected $_dependentTables = array('BugsProducts');
- }
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_dependentTables = array('BugsProducts');
- protected $_referenceMap = array(
- 'Reporter' => array(
- 'columns' => 'reported_by',
- 'refTableClass' => 'Accounts',
- 'refColumns' => 'account_name'
- ),
- 'Engineer' => array(
- 'columns' => 'assigned_to',
- 'refTableClass' => 'Accounts',
- 'refColumns' => 'account_name'
- ),
- 'Verifier' => array(
- 'columns' => array('verified_by'),
- 'refTableClass' => 'Accounts',
- 'refColumns' => array('account_name')
- )
- );
- }
- class BugsProducts extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs_products';
- protected $_referenceMap = array(
- 'Bug' => array(
- 'columns' => array('bug_id'),
- 'refTableClass' => 'Bugs',
- 'refColumns' => array('bug_id')
- ),
- 'Product' => array(
- 'columns' => array('product_id'),
- 'refTableClass' => 'Products',
- 'refColumns' => array('product_id')
- )
- );
- }
- ]]></programlisting>
- <para>
- Wenn <classname>Zend_Db_Table</classname> verwendet wird um kaskadierende
- <constant>UPDATE</constant> und <constant>DELETE</constant> Operationen zu emulieren,
- muß das <varname>$_dependentTables</varname> Array in der Klasse für die Eltern-Tabelle
- definiert werden. Der Klassenname muß für jede abhängige Komponente aufgelistet werden.
- Hierbei muß der Klassenname und nicht der physikalische Name der <acronym>SQL</acronym>
- Tabelle verwendet werden.
- </para>
- <note>
- <para>
- Die Deklaration von <varname>$_dependentTables</varname> sollte übergangen werden
- wenn referentielle Integritätsverknüpfungen im <acronym>RDBMS</acronym> Server
- verwendet werden um kaskadierende Operationen zu implementieren. Siehe
- <link linkend="zend.db.table.relationships.cascading">dieses Kapitel</link> für
- weitere Informationen.
- </para>
- </note>
- <para>
- Das <varname>$_referenceMap</varname> Array muß in der Klasse für jede abhängige
- Tabelle deklariert werden. Das ist ein assoziatives Array von Referenz-"Regeln". Eine
- Referenzregel identifiziert welche Tabelle in der Relation die Elterntabelle ist, und
- listet auch welche Spalten in der abhängigen Tabelle welche Spalten in der
- Elterntabelle referenzieren.
- </para>
- <para>
- Der Schlüssel der Regel ist ein String der als Index zum
- <varname>$_referenceMap</varname> Array verwendet wird. Dieser Regelschlüssel wird
- verwendet um jede Referenzen von Abhängigkeiten zu idenzifizieren. Es sollte ein
- sprechender Name für diesen Regelschlüssel ausgewählt werden. Deshalb ist es das beste
- einen String zu verwendet welcher Teil eines <acronym>PHP</acronym> Methodennamens sein
- kann, wie man später sieht.
- </para>
- <para>
- Im Beispiel <acronym>PHP</acronym> Code von oben, sind die Regelschlüssel in der Bugs
- Tabelle folgende: <command>'Reporter'</command>, <command>'Engineer'</command>,
- <command>'Verifier'</command>, und <command>'Product'</command>.
- </para>
- <para>
- Die Werte von jedem Regeleintrag im <varname>$_referenceMap</varname> Array sind auch
- ein assoziatives Array. Die Elemente dieses Regeleintrages werden im folgenden
- beschrieben:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>columns</emphasis> => Ein String oder ein Array von
- Strings welche die Namen der entfernten Schlüsselspalte der abhängigen Tabelle
- benennen.
- </para>
- <para>
- Es ist üblich das dies eine einzelne Spalte ist, aber einige Tabellen haben
- mehr-spaltige Schlüssel.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>refTableClass</emphasis> => Der Klassenname der
- Elterntabelle. Es sollte der Klassenname und nicht der physikalische Name der
- <acronym>SQL</acronym> Tabelle verwendet werden.
- </para>
- <para>
- Es ist für eine abhängige Tabelle üblich eine eigene Referenz zu Ihrer
- Elterntabelle zu haben, aber einige Tabellen haben mehrfache Referenzen zu der
- gleichen Elterntabelle. In der Beispieldatenbank gibt es eine Referenz von der
- <command>bugs</command> Tabelle zu der <command>products</command> Tabelle, aber
- drei Referenzen von der <command>bugs</command> Tabelle zur
- <command>accounts</command> Tabelle. Jede Referenz sollte in einen separaten
- Eintrag im <varname>$_referenceMap</varname> Array gegeben werden.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>refColumns</emphasis> => Ein String oder ein Array von
- Strings die den Spaltennamen des primären Schlüssels in der Elterntabelle
- benennen.
- </para>
- <para>
- Es ist üblich das dies eine einzelne Spalte ist, aber einige Tabellen haben
- mehr-spaltige Schlüssel. Wenn die Referenz einen mehr-spaltigen Schlüssel
- verwendet, muß die Reihenfolge der Spalten im <command>'columns'</command>
- Eintrag der Reihenfolge der Spalten im <command>'refColumns'</command> Eintrag
- entsprechen.
- </para>
- <para>
- Dieses Element kann optional spezifiziert werden. Wenn
- <property>refColumns</property> nicht spezifiziert wird, werden standardmäßig
- die Spalten verwendet, die als primäre Schlüsselspalten in der Elterntabelle
- bekannt sind.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>onDelete</emphasis> => Eine Regel für eine Aktion die
- ausgeführt wird wenn eine Zeile in der Elterntabelle gelöscht wird. Siehe auch
- <link linkend="zend.db.table.relationships.cascading">dieses Kapitel</link> für
- weitere Informationen.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>onUpdate</emphasis> => Eine Regel für eine Aktion die
- ausgeführt wird wenn Werte in der primären Schlüsselspalte der Elterntabelle
- aktualisiert werden. Siehe auch
- <link linkend="zend.db.table.relationships.cascading">dieses Kapitel</link> für
- weitere Informationen.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.db.table.relationships.fetching.dependent">
- <title>Eine abhängige Zeile holen</title>
- <para>
- Wenn man ein Zeilen Objekt als Ergebnis einer Abfrage auf einer Elterntabelle hat,
- können Zeilen der abhängigen Tabellen geholt werden, welche die aktuelle Zeile
- referenzieren. Hierbei kann die folgende Methode verwendet werden:
- </para>
- <programlisting language="php"><![CDATA[
- $row->findDependentRowset($table, [$rule]);
- ]]></programlisting>
- <para>
- Diese Methode gibt ein <classname>Zend_Db_Table_Rowset_Abstract</classname> Objekt
- zurück, welche ein Set von Zeilen der abhängigen Tabelle <varname>$table</varname>
- enthält die die Zeile referenzieren die durch das <varname>$row</varname> Objekt
- identifiziert werden.
- </para>
- <para>
- Das erste Argument <varname>$table</varname> kann ein String sein, der die abhängige
- Tabelle durch Ihren Klassennamen spezifiziert. Man kann die abhängige Tabelle auch durch
- Verwendung eines Objekts dieser Tabellenklasse spezifizieren.
- </para>
- <example id="zend.db.table.relationships.fetching.dependent.example">
- <title>Eine abhängige Zeile holen</title>
- <para>
- Dieses Beispiel zeigt wie man ein Zeilenobjekt von der Tabelle
- <command>Accounts</command> erhält und die <command>Bugs</command> findet die durch
- diesen Account mitgeteilt wurden.
- </para>
- <programlisting language="php"><![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- $bugsReportedByUser = $user1234->findDependentRowset('Bugs');
- ]]></programlisting>
- </example>
- <para>
- Das zweite Argument <varname>$rule</varname> ist optional. Es ist ein String der den
- Regelschlüssel im <varname>$_referenceMap</varname> Array der abhängigen Tebellenklasse
- benennt. Wenn keine Regel spezifiziert wird, wird die erste Regel im Array verwendet
- welche die Elterntabelle referenziert. Wenn eine andere Regel als die erste verwendet
- werden soll, muß der Schlüssel spezifiziert werden.
- </para>
- <para>
- Im obigen Beispiel wird der Regelschlüssel nicht spezifiziert, sodas standardmäßig die
- Regel verwendet wird die als erste der Elterntabelle entspricht. Das ist die Regel
- <command>'Reporter'</command>.
- </para>
- <example id="zend.db.table.relationships.fetching.dependent.example-by">
- <title>Eine anhängige Zeile durch eine spezifische Regel erhalten</title>
- <para>
- Das Beispiel zeigt wie ein Zeilenobjekt von der <command>Accounts</command> Tabelle
- erhalten werden kann, und die zugeordneten <command>Bugs</command> die vom Benutzer
- dieses Accounts bereits gefixed wurden, gefunden werden können. Der String des
- Regelschlüssels der zu dieser Referenziellen Abhängigkeit in dem Beispiel
- korrespondiert ist <command>'Engineer'</command>.
- </para>
- <programlisting language="php"><![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- $bugsAssignedToUser = $user1234->findDependentRowset('Bugs', 'Engineer');
- ]]></programlisting>
- </example>
- <para>
- Es können auch Kriterien, Sortierungen und Limits zur Relation hinzugefügt werden indem
- das Select Objekt der Elternzeilen verwendet wird.
- </para>
- <example id="zend.db.table.relationships.fetching.dependent.example-by-select">
- <title>
- Ein anhängiges Zeilenset erhalten indem Zend_Db_Table_Select verwendet wird
- </title>
- <para>
- Dieses Beispiel zeigt wir ein Zeilenobjekt von der Tabelle
- <command>Accounts</command> empfangen werden kann, und die zugeordneten
- <command>Bugs</command> die vom Benutzer dieses Zugangs zu beheben sind, gefunden
- werden können, beschränkt auf 3 Zeilen und nach Name sortiert.
- </para>
- <programlisting language="php"><![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- $select = $accountsTable->select()->order('name ASC')
- ->limit(3);
- $bugsAssignedToUser = $user1234->findDependentRowset('Bugs',
- 'Engineer',
- $select);
- ]]></programlisting>
- </example>
- <para>
- Alternativ können Zeilen von einer abhängigen Tabelle abgefragt werden indem ein
- spezieller Mechanismus verwendet wird der "magische Methode" genannt wird.
- <classname>Zend_Db_Table_Row_Abstract</classname> ruft die Methode:
- <methodname>findDependentRowset('<TabellenKlasse>', '<Regel>')</methodname>
- auf wenn eine Methode am Zeilenobjekt aufgerufen wird die einem der folgenden Patterns
- entspricht:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <command>$row->find<TabellenKlasse>()</command>
- </para>
- </listitem>
- <listitem>
- <para>
- <command>$row->find<TabellenKlasse>By<Regel>()</command>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- In den obigen Patterns, sind <command><TabellenKlasse></command> und
- <command><Regel></command> Strings die mit dem Klassennamen der abhängigen Tabelle
- korrespondieren, und der Regelschlüssel der abhängigen Tabelle der die Enterntabelle
- referenziert.
- </para>
- <note>
- <para>
- Einige Applikationsframeworks, wie Ruby on Rails, verwenden einen Mechanismus der
- "inflection" genannt wird um die Änderung der Schreibweise von Identifizierern
- abhängig von der Verwendung zu erlauben. Der Einfachheit halber, bietet
- <classname>Zend_Db_Table_Row</classname> keinen Inflection Mechanismus an. Die
- Identität der Tabelle und der Regelschlüssel die im Methodenaufruf genannt werden
- müssen der Schreibweise der Klasse und des Regelschlüssels exakt entsprechen.
- </para>
- </note>
- <example id="zend.db.table.relationships.fetching.dependent.example-magic">
- <title>Holen von abhängigen Zeilen durch Verwendung der magischen Methode</title>
- <para>
- Dieses Beispiel zeigt wie abhängige Zeilen gefunden werden, entsprechend des
- vorherigen Beispiel. In diesem Fall, verwendet die Anwendung den magischen
- Methodenaufruf anstatt die Tabelle und Regel als String zu spezifizieren.
- </para>
- <programlisting language="php"><![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- // Verwendung der standard Referenzregel
- $bugsReportedBy = $user1234->findBugs();
- // Eine Referenzregel spezifizieren
- $bugsAssignedTo = $user1234->findBugsByEngineer();
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.relationships.fetching.parent">
- <title>Eine Elternzeile holen</title>
- <para>
- Wenn man ein Zeilenobjekt als Ergebnis einer Abfrage auf eine abhängige Tabelle hat,
- kann man die Zeile vom Elternteil zu der die abhängige Zeile referenziert holen.
- Hierbei verwendet man die Methode:
- </para>
- <programlisting language="php"><![CDATA[
- $row->findParentRow($table, [$rule]);
- ]]></programlisting>
- <para>
- Es sollte immer exakt eine Zeile in der Elterntabelle durch eine abhängige Zeile
- referenziert sein, deshalb gibt diese Methode ein Zeilen Objekt und kein Zeilenset
- Objekt zurück.
- </para>
- <para>
- Das erste Argument <varname>$table</varname> kann ein String sein der die Elterntabelle
- durch Ihren Klassennamen spezifiziert. Man kann die Elterntabelle auch durch Verwendung
- eines Objektes dieser Tabellenklasse spezifizieren.
- </para>
- <example id="zend.db.table.relationships.fetching.parent.example">
- <title>Eine Elternzeile holen</title>
- <para>
- Dieses Beispiel zeigt wie ein Zeilen Objekt von der Tabelle <command>Bugs</command>
- geholt werden kann (zum Beispiel einer dieser Fehler mit Status 'NEW'), und die
- Zeile in der <command>Accounts</command> Tabelle für diesen Benutzer, der den Fehler
- gemeldet hat, gefunden werden kann.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?' => 'NEW'));
- $bug1 = $bugsRowset->current();
- $reporter = $bug1->findParentRow('Accounts');
- ]]></programlisting>
- </example>
- <para>
- Das zweite Argument <varname>$rule</varname> ist optional. Es ist ein Strung der den
- Regelschlüssel im <varname>$_referenceMap</varname> Array der abhängigen Tabellenklasse
- benennt. Wenn diese Regel nicht spezifiziert wird, wird die erste Regel im Array
- genommen das die Elterntabelle referenziert. Wenn eine andere Regel als der erste
- genommen werden muß, dann muß der Schlüssel spezifiziert werden.
- </para>
- <para>
- Im obigen Beispiel wird der Regelschlüssel nicht spezifiziert, sodas standardmäßig die
- Regel verwendet wird die als erste der Elterntabelle entspricht. Das ist die Regel
- <command>'Reporter'</command>.
- </para>
- <example id="zend.db.table.relationships.fetching.parent.example-by">
- <title>Eine Elternzeile durch eine spezifizierte Regel holen</title>
- <para>
- Dieses Beispiel zeigt wie ein Zeilenobjekt von der Tabelle <command>Bugs</command>
- geholt werden kann, und der Account für den Ingenieur der zugeordnet wurde, diesen
- Fehler zu beheben, gefunden werden kann. Der Regelschlüssel der in diesem Beispiel
- der referenzierten Abhängigkeit entspricht ist <command>'Engineer'</command>.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
- $bug1 = $bugsRowset->current();
- $engineer = $bug1->findParentRow('Accounts', 'Engineer');
- ]]></programlisting>
- </example>
- <para>
- Alternativ, können Zeilen von der Elterntabelle abgefragt werden indem eine
- "magische Methode" verwendet wird. <classname>Zend_Db_Table_Row_Abstract</classname>
- ruft die Methode:
- <methodname>findParentRow('<TableClass>', '<Rule>')</methodname> auf
- wenn eine Methode auf dem Zeilenobjekt aufgerufen wird die einer der folgenden Pattern
- entspricht:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <command>$row->findParent<TabellenKlasse>([Zend_Db_Table_Select
- $select])</command>
- </para>
- </listitem>
- <listitem>
- <para>
- <command>$row->findParent<TabellenKlasse>By<Regel>(
- [Zend_Db_Table_Select $select])</command>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- In den obigen Pattern sind, <command><TabellenKlasse></command> und
- <command><Regel></command> Strings die dem Klassennamen der Elterntabelle
- entsprechen, und der Regelname der abhängigen Tabelle der die Elterntabelle
- referenziert.
- </para>
- <note>
- <para>
- Die Identität der Tabelle und des Regelschlüssels die im Aufruf der Methode genannt
- werden, müssen der Schreibweise der Klasse und des Regelschlüssels exakt
- entsprechen.
- </para>
- </note>
- <example id="zend.db.table.relationships.fetching.parent.example-magic">
- <title>Die Elternzeile durch verwenden der magischen Methode holen</title>
- <para>
- Dieses Beispiel zeigt wie Elternzeilen gefunden werden, ähnlich dem vorherigen
- Beispiel. In diesem Fall verwendet die Anwendung den Aufruf der magischen Methode
- statt der Spezifizierung von Tabelle und Regel als Strings.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
- $bug1 = $bugsRowset->current();
- // Verwenden der standardmäßigen Referenzregel
- $reporter = $bug1->findParentAccounts();
- // Die Referenzregel spezifizieren
- $engineer = $bug1->findParentAccountsByEngineer();
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.relationships.fetching.many-to-many">
- <title>Ein Zeilenset über eine Viele-zu-Viele Verknüpfung holen</title>
- <para>
- Wenn man ein Zeilenobjekt als Ergebnis einer Abfrage auf eine Tabelle in einer
- Viele-Zu-Viele Verknüpfung hat (für die Zwecke dieses Beispiels, nennen wir das die
- "Original" Tabelle), können entsprechende Zeilen in der anderen Tabelle (nennen wir das
- die "Ziel" Tabelle) über eine Verknüpfungstabelle geholt werden. Hierbei wird die
- folgende Methode verwendet:
- </para>
- <programlisting language="php"><![CDATA[
- $row->findManyToManyRowset($table,
- $intersectionTable,
- [$rule1,
- [$rule2,
- [Zend_Db_Table_Select $select]
- ]
- ]);
- ]]></programlisting>
- <para>
- Diese Methode gibt ein <classname>Zend_Db_Table_Rowset_Abstract</classname> zurück
- welches Zeilen von der Tabelle <varname>$table</varname> enthält, und der Viele-Zu-Viele
- Abhängigkeit entspricht. Das aktuelle Zeilenobjekt <varname>$row</varname> von der
- originalen Tabelle wird verwendet um Zeilen in der Verknüpfungstabelle zu finden, und es
- ist mit der Zieltabelle verbunden.
- </para>
- <para>
- Das erste Argument <varname>$table</varname> kann ein String sein der die Zieltabelle in
- der Viele-Zu-Viele Verknüpfung durch seinen Klassennamen spezifiziert. Es kann auch die
- Zieltabelle durch Verwendung eines Objekts dieser Tabellenklasse spezifiziert werden.
- </para>
- <para>
- Das zweite Argument <varname>$intersectionTable</varname> kann ein String sein, der die
- Verknüpfungstabelle zwischen diesen zwei Tabellen in der Viele-Zu-Viele Verknüpfung,
- durch seinen Klassennamen, spezifiziert. Die Verknüpfungstabelle kann auch durch
- Verwendung eines Objektes dieser Tabellenklasse spezifiziert werden.
- </para>
- <example id="zend.db.table.relationships.fetching.many-to-many.example">
- <title>Ein Zeilenset mit einer Viele-Zu-Viele Methode holen</title>
- <para>
- Dieses Beispiel zeigt wie man ein Zeilenobjekt von der Originaltabelle
- <command>Bugs</command> erhält, und wie Zeilen von der Zieltabelle
- <command>Products</command> gefunden werden können die Produkte repräsentieren
- welche diesem Bug zugeordnet sind.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->find(1234);
- $bug1234 = $bugsRowset->current();
- $productsRowset = $bug1234->findManyToManyRowset('Products',
- 'BugsProducts');
- ]]></programlisting>
- </example>
- <para>
- Das dritte und vierte Argument <varname>$rule1</varname> und <varname>$rule2</varname>
- sind optional. Das sind Strings die den Regelschlüssel im
- <varname>$_referenceMap</varname> Array der verknüpfungstabelle benennen.
- </para>
- <para>
- Der <varname>$rule1</varname> Schlüssel benennt die Regel für die Verknüpfung der
- Verknüpfungstabelle zur Originaltabelle. In diesem Beispiel ist das die verknüpfung von
- <command>BugsProducts</command> zu <command>Bugs</command>.
- </para>
- <para>
- Der <varname>$rule2</varname> Schlüssel benennt die Regel für die Verknüpfung der
- Verknüpfungstabelle zur Zieltabelle. In diesem Beispiel ist der die Verknüpfung von
- <command>Bugs</command> zu <command>Products</command>.
- </para>
- <para>
- Ähnlich den Methoden für das finden von Eltern- und abhängigen Zeilen verwendet die
- Methode, wenn keine Regel spezifiziert wird, die erste Regel im
- <varname>$_referenceMap</varname> Array das den Tabellen in der Verknüpfung entspricht.
- Wenn eine andere Regel als die erste verwendet werden soll, muß der Schlüssel
- spezifiziert werden.
- </para>
- <para>
- Im obigen Beispiel wird der Regelschlüssel nicht spezifiziert, sodas standardmäßig die
- ersten passenden Regeln verwendet werden. In diesem Fall ist <varname>$rule1</varname>
- <command>'Reporter'</command> und <varname>$rule2</varname> ist
- <command>'Product'</command>.
- </para>
- <example id="zend.db.table.relationships.fetching.many-to-many.example-by">
- <title>
- Ein Zeilenset mit einer Viele-Zu-Viele Methode durch eine spezielle Regel holen
- </title>
- <para>
- Dieses Beispiel zeigt wie man ein Zeilenobjekt von der Originaltabelle
- <command>Bugs</command> erhält, und Zeilen von der Zieltabelle
- <command>Products</command> findet die Produkte repräsentieren die dem Fehler
- zugeordnet sind.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->find(1234);
- $bug1234 = $bugsRowset->current();
- $productsRowset = $bug1234->findManyToManyRowset('Products',
- 'BugsProducts',
- 'Bug');
- ]]></programlisting>
- </example>
- <para>
- Alternativ können Zeilen von der Zieltabelle in einer Viele-Zu-Viele Verknüpfung
- abgefragt werden inden eine "magische Methode" verwendet wird.
- <classname>Zend_Db_Table_Row_Abstract</classname> ruft die Methode:
- <command>findManyToManyRowset('<TabellenKlasse>',
- '<VerknüpfungTabellenKlasse>', '<Regel1>', '<Regel2>')</command>
- auf, wenn eine Methode aufgerufen wird die einem der folgenden Pattern entspricht:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <command>$row->find<TabellenKlasse>Via<VerknüpfungsTabellenKlasse>
- ([Zend_Db_Table_Select $select])</command>
- </para>
- </listitem>
- <listitem>
- <para>
- <command>$row->find<TabellenKlasse>Via<VerknüpfungsTabellenKlasse>By<Regel1>
- ([Zend_Db_Table_Select $select])</command>
- </para>
- </listitem>
- <listitem>
- <para>
- <command>$row->find<TabellenKlasse>Via<VerknüpfungsTabellenKlasse>By<Regel1>And<Regel2>
- ([Zend_Db_Table_Select $select])</command>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- In den oben gezeigten Pattern sind <command><TabellenKlasse></command> und
- <command><VerknüpfungsTabellenKlasse></command> Strings die den Klassennamen der
- Zieltabelle und der Verknüpfungstabelle entsprechen. <command><Regel1></command>
- und <command><Regel2></command> sind Strings die den Regelschlüssel in der
- Verknüpfungstabelle entsprechen, welche die Originaltabelle und die Zieltabelle
- referenzieren.
- </para>
- <note>
- <para>
- Die Tabelleneinheiten und die Regelschlüssel die in der aufgerufenen Methode
- benannt werden, müssen exakt der Schreibweise der Klasse und des Regelschlüssels
- entsprechen.
- </para>
- </note>
- <example id="zend.db.table.relationships.fetching.many-to-many.example-magic">
- <title>Zeilensets durch Verwendung der magischen Viele-Zu-Viele Methode holen</title>
- <para>
- Dieses Beispiel zeigt wie Zeilen in der Zieltabelle einer Viele-Zu-Viele
- Verknüpfung gefunden werden können, in der Produkte die einen Bezug zu einem
- angegebenen Fehler haben, entsprechen.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->find(1234);
- $bug1234 = $bugsRowset->current();
- // Verwendung der standardmäßigen Referenzregel
- $products = $bug1234->findProductsViaBugsProducts();
- // Spezifizieren der Referenzregel
- $products = $bug1234->findProductsViaBugsProductsByBug();
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.relationships.cascading">
- <title>Schreiboperationen kaskadieren</title>
- <note>
- <title>Deklarieren von DRI in der Datenbank:</title>
- <para>
- Die Deklaration von kaskadierenden Operationen in
- <classname>Zend_Db_Table</classname> <emphasis>nur</emphasis> für
- <acronym>RDBMS</acronym> Marken gedacht die keine deklarative referentielle
- Integrität unterstützen (<acronym>DRI</acronym>).
- </para>
- <para>
- Zum Beispiel, bei der Verwendung von MySQL's MyISAM Speicherengine oder SQLite.
- Diese Lösungen unterstützen kein <acronym>DRI</acronym>. Hierbei ist es hilfreich
- die kaskadierenden Operationen mit <classname>Zend_Db_Table</classname> zu
- deklarieren.
- </para>
- <para>
- Wenn die eigene <acronym>RDBMS</acronym> <acronym>DRI</acronym> implementiert sowie
- die ON <constant>DELETE</constant> und ON <constant>UPDATE</constant> Klauseln,
- sollten diese Klauseln im eigenen Datenbank Schema deklariert werden, anstatt das
- kaskadierende Feature von <classname>Zend_Db_Table</classname> zu verwenden. Die
- Deklaration von <acronym>DRI</acronym> Regeln in der <acronym>RDBMS</acronym> ist
- besser für die Geschwindigkeit der Datenbank, Konsistenz und Integrität.
- </para>
- <para>
- Am wichtigsten ist aber das die kaskadierenden Operationen nicht in beiden, der
- <acronym>RDBMS</acronym> und der eigenen <classname>Zend_Db_Table</classname>
- Klasse deklariert werden.
- </para>
- </note>
- <para>
- Kaskadierende Operationen können deklariert werden um anhand einer abhängigen Tabelle
- ausgeführt zu werden wenn ein <constant>UPDATE</constant> oder ein
- <constant>DELETE</constant> an einer Zeile in einer Elterntabelle ausgeführt wird.
- </para>
- <example id="zend.db.table.relationships.cascading.example-delete">
- <title>Beispiel für ein kaskadierendes Löschen</title>
- <para>
- Dieses Beispiel zeigt das Löschen einer Zeile in der <command>Products</command>
- Tabelle, welche konfiguriert ist um automatisch abhängige Zeilen in der
- <command>Bugs</command> Tabelle zu löschen.
- </para>
- <programlisting language="php"><![CDATA[
- $productsTable = new Products();
- $productsRowset = $productsTable->find(1234);
- $product1234 = $productsRowset->current();
- $product1234->delete();
- // Kaskadiert automatisch zur Bugs Tabelle und löscht abhängige Zeilen.
- ]]></programlisting>
- </example>
- <para>
- Genauso kann es gewünscht sein, wenn man ein <constant>UPDATE</constant> verwendet um
- den Wert eines primären Schlüssels in einer Elterntabelle zu verändern, das sich auch
- den Wert im entfernten Schlüssel der abhängigen Tabellen automatisch von selbst
- aktualisiert um dem neuen Wert zu entsprechen, sodas solche Referenzen aktuel gehalten
- werden.
- </para>
- <para>
- Normalerweise ist es nicht notwendig die Werte eines primären Schlüssels, der durch
- eine Sequenz von anderen Mechanismen erstellt wurde, zu aktualisieren. Aber wenn man
- einen <emphasis>natürlichen Schlüssel</emphasis> verwendet, der den Wert plötzlich
- ändert, ist es besser kaskadierende Aktualisierungen auf abhängigen Tabellen
- durchzuführen.
- </para>
- <para>
- Um eine kaskadierende Abhängigkeit in <classname>Zend_Db_Table</classname> zu
- deklarieren, müssen die Regeln in <varname>$_referenceMap</varname> bearbeitet werden.
- Die assoziativen Arrayschlüssel <command>'onDelete'</command> und
- <command>'onUpdate'</command> müssen auf den String 'cascade' (oder die Konstante
- <constant>self::CASCADE</constant>) gesetzt werden. Bevor eine Zeile von der
- Elterntabelle gelöscht wird oder dessen Wert des primären Schlüssels aktualisiert wird,
- werden alle Zeilen in der abhängigen Tabelle, welche die Eltern-Zeilen referenzieren,
- zuerst gelöscht oder aktualisiert.
- </para>
- <example id="zend.db.table.relationships.cascading.example-declaration">
- <title>Beispieldeklaration einer kaskadierenden Operation</title>
- <para>
- Im unten angeführten Beispiel, werden die Zeilen in der <command>Bugs</command>
- Tabelle automatisch gelöscht wenn eine Zeile in der <command>Products</command>
- Tabelle zu der Sie referenzieren gelöscht wird. Das <command>'onDelete'</command>
- Element des Referenzplan Eintrages wird auf <constant>self::CASCADE</constant>
- gesetzt.
- </para>
- <para>
- Es wird in diesem Beispiel keine kaskadierende Aktualisierung durchgeführt wenn der
- primäre Schlüsselwert in der Elternklasse verändert wird. Das
- <command>'onUpdate'</command> Element des Referenzplan Eintrages ist
- <constant>self::RESTRICT</constant>. Das gleiche Ergebnis erhält man durch
- Unterdrückung des <command>'onUpdate'</command> Eintrages.
- </para>
- <programlisting language="php"><![CDATA[
- class BugsProducts extends Zend_Db_Table_Abstract
- {
- ...
- protected $_referenceMap = array(
- 'Product' => array(
- 'columns' => array('product_id'),
- 'refTableClass' => 'Products',
- 'refColumns' => array('product_id'),
- 'onDelete' => self::CASCADE,
- 'onUpdate' => self::RESTRICT
- ),
- ...
- );
- }
- ]]></programlisting>
- </example>
- <sect3 id="zend.db.table.relationships.cascading.notes">
- <title>Notizen betreffend kaskadierenden Operationen</title>
- <para>
- <emphasis>Kaskadierende Operationen die durch <classname>Zend_Db_Table</classname>
- aufgerufen werden sind nicht atomar.</emphasis>
- </para>
- <para>
- Das bedeutet, das wenn die eigene Datenbank referentielle integrative Verknüpfungen
- implementiert und erzwingt, ein kaskadierends <constant>UPDATE</constant> das durch
- eine <classname>Zend_Db_Table</classname> Klasse ausgeführt wird mit der Verknüpfung
- kollidiert, und in einem referentiellen integrativen Verstoß mündet. Ein
- kaskadierendes <constant>UPDATE</constant> kann in
- <classname>Zend_Db_Table</classname> <emphasis>nur</emphasis> dann verwendet werden
- wenn die eigene Datenbank die referentielle integrative Verknüpfung nicht erzwingt.
- </para>
- <para>
- Ein kaskadierendes <constant>DELETE</constant> erleidet weniger durch das Problem
- des referentiellen integrativen Verstoßes. Abhängige Zeilen können genauso gelöscht
- werden wie durch eine nicht-atomare Aktion bevor die Elternzeile welche diese
- referenziert gelöscht wird.
- </para>
- <para>
- Trotzdem, für beide <constant>UPDATE</constant> und <constant>DELETE</constant>,
- erzeugt die Änderung der Datenbank in einem nicht-atomaren Weg auch das Risiko das
- ein anderer Datenbankbenutzer die Daten in einem inkonsistenten Status sieht. Wenn,
- zum Beispiel, eine Zeile und alle Ihre abhängigen Zeilen, gelöscht werden, gibt es
- eine kleine Chance das ein anderes Datenbank Clientprogramm die Datenbank abfragen
- kann nachdem die abhängigen Zeilen gelöscht wurden, aber bevor die Elternzeilen
- gelöscht wurden. Dieses Clientprogramm kann die Elternzeilen ohne abhängige Zeilen
- sehen, und diese als gewünschten Status der Daten annehmen. Es gibt keinen Weg für
- diesen Clienten herauszufinden das die Abfrage der Datenbank mitten während einer
- Änderung gelesen wurde.
- </para>
- <para>
- Der Fall von nicht-atomaren Änderungen kann durch die Verwendung von Transaktionen
- entschärft werden indem die Änderungen isoliert werden. Aber einige
- <acronym>RDBMS</acronym> Marken unterstützen keine Transaktionen, oder erlauben dem
- Clienten "schmutzige" Änderungen zu lesen die noch nicht fertiggestellt wurden.
- </para>
- <para>
- <emphasis>Kaskadierende Operationen in <classname>Zend_Db_Table</classname> werden
- nur durch <classname>Zend_Db_Table</classname> aufgerufen.</emphasis>
- </para>
- <para>
- Kaskadierendes Löschen und Aktualisieren welches in den eigenen
- <classname>Zend_Db_Table</classname> Klassen definiert wurde werden ausgeführt wenn
- die <methodname>save()</methodname> oder <methodname>delete()</methodname> Methoden
- der Zeilenklasse ausgeführt werden. Trotzdem, wenn ein Update oder Löschen von
- Daten durch Verwendung eines anderen Interfaces durchgeführt wird, wie durch ein
- Abfragetool oder eine andere Anwendung, werden die kaskadierenden Operationen nicht
- ausgeführt. Selbst wenn die <methodname>update()</methodname> und
- <methodname>delete()</methodname> Methoden in der
- <classname>Zend_Db_Adapter</classname> Klasse verwendet werden, werden die
- kaskadierenden Operationen die in der eigenen <classname>Zend_Db_Table</classname>
- Klasse definiert wurden, nicht ausgeführt.
- </para>
- <para>
- <emphasis>Kein kaskadierendes <constant>INSERT</constant>.</emphasis>
- </para>
- <para>
- Es gibt keine Unterstützung für ein kaskadierendes <constant>INSERT</constant>. Man
- muß eine Zeile in eine Elterntabelle in einer Operation hinzufügen, und Zeilen zu
- einer abhängigen Tabelle in einer unabhängigen Operation hinzufügen.
- </para>
- </sect3>
- </sect2>
- </sect1>
|