| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 15851 -->
- <!-- 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
- <xref linkend="zend.db.table.defining" /> beschrieben, definiert werden. Siehe auch
- unter <xref linkend="zend.db.adapter.example-database" /> für eine Beschreibug einer
- Beispieldatenbank für welche der folgende Beispielcode designed wurde.
- </para>
- <para>
- Anbei sind die PHP 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 UPDATE und
- DELETE 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 SQL Tabelle verwendet werden.
- </para>
- <note>
- <para>
- Die Deklaration von <varname>$_dependentTables</varname> sollte übergangen werden wenn
- referentielle Integritätsverknüpfungen im RDBMS Server verwendet werden um
- kaskadierende Operationen zu implementieren. Siehe
- <xref linkend="zend.db.table.relationships.cascading" /> für weitere Informationen.
- </para>
- </note>
- <para>
- Das <varname>$_referenceMap</varname> Array muß in der Klasse für jede unabhä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 PHP Methodennamens sein kann, wie man später sieht.
- </para>
- <para>
- Im Beispiel PHP Code von oben, sind die Regelschlüssel in der Bugs Tabelle folgende:
- <code>'Reporter'</code>, <code>'Engineer'</code>, <code>'Verifier'</code>, und
- <code>'Product'</code>.
- </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 die 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
- SQL 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
- <code>bugs</code> Tabelle zu der <code>products</code> Tabelle, aber drei
- Referenzen von der <code>bugs</code> Tabelle zur <code>accounts</code> 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 <code>'columns'</code> Eintrag
- der Reihenfolge der Spalten im <code>'refColumns'</code> Eintrag entsprechen.
- </para>
- <para>
- Dieses Element kann optional spezifiziert werden. Wenn <code>refColumns</code>
- nicht spezifiziert wird, werden standardmäßig die Spalte verwendet, die als
- primäre Schlüsselspalte 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
- <xref linkend="zend.db.table.relationships.cascading" /> 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
- <xref linkend="zend.db.table.relationships.cascading" /> 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, die 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
- <code>Accounts</code> erhält und die <code>Bugs</code> 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
- die 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
- <code>'Reporter'</code>.
- </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 <code>Accounts</code> Tabelle
- erhalten werden kann, und die zugeordneten <code>Bugs</code> 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 <code>'Engineer'</code>.
- </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>
- <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
- <code>Accounts</code> empfangen werden kann, und die zugeordneten
- <code>Bugs</code> 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>
- 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:
- <code>findDependentRowset('<TabellenKlasse>', '<Regel>')</code> auf wenn
- eine Methode am Zeilenobjekt aufgerufen wird die einem der folgenden Patterns
- entspricht:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>$row->find<TabellenKlasse>()</code>
- </para>
- </listitem>
- <listitem>
- <para>
- <code>$row->find<TabellenKlasse>By<Regel>()</code>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- In den obigen Patterns, sind <code><TabellenKlasse></code> und
- <code><Regel></code> 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 <code>Bugs</code>
- geholt werden kann (zum Beispiel einer dieser Fehler mit Status 'NEW'), und die
- Zeile in der <code>Accounts</code> 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
- <code>'Reporter'</code>.
- </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 <code>Bugs</code> 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 <code>'Engineer'</code>.
- </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: <code>findParentRow('<TableClass>', '<Rule>')</code> auf
- wenn eine Methode auf dem Zeilenobjekt aufgerufen wird die einer der folgenden Pattern
- entspricht:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>$row->findParent<TabellenKlasse>([Zend_Db_Table_Select
- $select])</code>
- </para>
- </listitem>
- <listitem>
- <para>
- <code>$row->findParent<TabellenKlasse>By<Regel>(
- [Zend_Db_Table_Select $select])</code>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- In den obigen Pattern sind, <code><TabellenKlasse></code> und
- <code><Regel></code> 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
- <code>Bugs</code> erhält, und wie Zeilen von der Zieltabelle <code>Products</code>
- gefunden werden können die Produkte repräsentieren die 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
- <code>BugsProducts</code> zu <code>Bugs</code>.
- </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
- <code>Bugs</code> zu <code>Products</code>.
- </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>
- <code>'Reporter'</code> und <varname>$rule2</varname> ist <code>'Product'</code>.
- </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
- <code>Bugs</code> erhält, und Zeilen von der Zieltabelle <code>Products</code>
- 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:
- <code>findManyToManyRowset('<TabellenKlasse>',
- '<VerknüpfungTabellenKlasse>', '<Regel1>', '<Regel2>')</code> auf,
- wenn eine Methode aufgerufen wird die einem der folgenden Pattern entspricht:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>$row->find<TabellenKlasse>Via<VerknüpfungsTabellenKlasse>(
- [Zend_Db_Table_Select $select])</code>
- </para>
- </listitem>
- <listitem>
- <para>
- <code>$row->find<TabellenKlasse>Via<VerknüpfungsTabellenKlasse>By<Regel1>(
- [Zend_Db_Table_Select $select])</code>
- </para>
- </listitem>
- <listitem>
- <para>
- <code>$row->find<TabellenKlasse>Via<VerknüpfungsTabellenKlasse>By<Regel1>And<Regel2>(
- [Zend_Db_Table_Select $select])</code>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- In den oben gezeigten Pattern sind <code><TabellenKlasse></code> und
- <code><VerknüpfungsTabellenKlasse></code> Strings die den Klassennamen der
- Zieltabelle und der Verknüpfungstabelle entsprechen. <code><Regel1></code> und
- <code><Regel2></code> sind Strings die den Regelschlüssel in der
- Verknüpfungstabelle entsprechen, die 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 RDBMS Marken
- gedacht die keine deklarative referentielle Integrität unterstützen (DRI).
- </para>
- <para>
- Zum Beispiel, bei der Verwendung von MySQL's MyISAM Speicherengine oder SQLite.
- Diese Lösungen unterstützen kein DRI. Hierbei ist es hilfreich die kaskadierenden
- Operationen mit <classname>Zend_Db_Table</classname> zu deklarieren.
- </para>
- <para>
- Wenn die eigene RDBMS DRI implementiert sowie die <code>ON DELETE</code> und
- <code>ON UPDATE</code> 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 DRI Regeln in
- der RDBMS 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
- RDBMS 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 <code>UPDATE</code> oder ein <code>DELETE</code> 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 <code>Products</code> Tabelle,
- welche konfiguriert ist um automatisch abhängige Zeilen in der <code>Bugs</code>
- 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 <code>UPDATE</code> 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 <code>'onDelete'</code> und <code>'onUpdate'</code> müssen
- auf den String 'cascade' (oder die Konstante <code>self::CASCADE</code>) 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, die 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 <code>Bugs</code> Tabelle
- automatisch gelöscht wenn eine Zeile in der <code>Products</code> Tabelle zu der
- Sie referenzieren gelöscht wird. Das <code>'onDelete'</code> Element des
- Referenzplan Eintrages wird auf <code>self::CASCADE</code> 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
- <code>'onUpdate'</code> Element des Referenzplan Eintrages ist
- <code>self::RESTRICT</code>. Das gleiche Ergebnis erhält man durch Unterdrückung des
- <code>'onUpdate'</code> 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 <code>UPDATE</code> 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 <code>UPDATE</code> 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 <code>DELETE</code> 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 die diese
- referenziert gelöscht wird.
- </para>
- <para>
- Trotzdem, für beide <code>UPDATE</code> und <code>DELETE</code>, 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ärend 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 RDBMS 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 <code>save()</code> oder <code>delete()</code> 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 <code>update()</code> und <code>delete()</code> 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 <code>INSERT</code>.</emphasis>
- </para>
- <para>
- Es gibt keine Unterstützung für ein kaskadierendes <code>INSERT</code>. 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>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|