Zend_Db_Table-Relationships.xml 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 21587 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.db.table.relationships">
  5. <title>Zend_Db_Table Relationships</title>
  6. <sect2 id="zend.db.table.relationships.introduction">
  7. <title>Einführung</title>
  8. <para>
  9. In einer relationalen Datenbank haben Tabellen Relationen zueinander. Eine Entität in
  10. einer Tabelle kann zu einer oder mehrerer Entitäten in einer anderen Tabelle, durch
  11. Verwendung von referentiellen Integritätsverknüpfungen die im Datenbank Schema
  12. definiert sind, verknüpft werden.
  13. </para>
  14. <para>
  15. Die <classname>Zend_Db_Table_Row</classname> Klasse besitzt Methoden für die Abfrage von
  16. verknüpften Zeilen in anderen Tabellen.
  17. </para>
  18. </sect2>
  19. <sect2 id="zend.db.table.relationships.defining">
  20. <title>Verknüpfungen definieren</title>
  21. <para>
  22. Die Klassen für jede eigene Tabelle müssen durch das Erweitern der abstrakten Klasse
  23. <classname>Zend_Db_Table_Abstract</classname>, wie in <link
  24. linkend="zend.db.table.defining">diesem Kapitel</link> beschrieben, definiert
  25. werden. Siehe auch in <link linkend="zend.db.adapter.example-database">diesem
  26. Kapitel</link> für die Beschreibung einer Beispieldatenbank für welche der folgende
  27. Beispielcode designed wurde.
  28. </para>
  29. <para>
  30. Anbei sind die <acronym>PHP</acronym> Klassendefinitionen für diese Tabellen:
  31. </para>
  32. <programlisting language="php"><![CDATA[
  33. class Accounts extends Zend_Db_Table_Abstract
  34. {
  35. protected $_name = 'accounts';
  36. protected $_dependentTables = array('Bugs');
  37. }
  38. class Products extends Zend_Db_Table_Abstract
  39. {
  40. protected $_name = 'products';
  41. protected $_dependentTables = array('BugsProducts');
  42. }
  43. class Bugs extends Zend_Db_Table_Abstract
  44. {
  45. protected $_name = 'bugs';
  46. protected $_dependentTables = array('BugsProducts');
  47. protected $_referenceMap = array(
  48. 'Reporter' => array(
  49. 'columns' => 'reported_by',
  50. 'refTableClass' => 'Accounts',
  51. 'refColumns' => 'account_name'
  52. ),
  53. 'Engineer' => array(
  54. 'columns' => 'assigned_to',
  55. 'refTableClass' => 'Accounts',
  56. 'refColumns' => 'account_name'
  57. ),
  58. 'Verifier' => array(
  59. 'columns' => array('verified_by'),
  60. 'refTableClass' => 'Accounts',
  61. 'refColumns' => array('account_name')
  62. )
  63. );
  64. }
  65. class BugsProducts extends Zend_Db_Table_Abstract
  66. {
  67. protected $_name = 'bugs_products';
  68. protected $_referenceMap = array(
  69. 'Bug' => array(
  70. 'columns' => array('bug_id'),
  71. 'refTableClass' => 'Bugs',
  72. 'refColumns' => array('bug_id')
  73. ),
  74. 'Product' => array(
  75. 'columns' => array('product_id'),
  76. 'refTableClass' => 'Products',
  77. 'refColumns' => array('product_id')
  78. )
  79. );
  80. }
  81. ]]></programlisting>
  82. <para>
  83. Wenn <classname>Zend_Db_Table</classname> verwendet wird um kaskadierende
  84. <constant>UPDATE</constant> und <constant>DELETE</constant> Operationen zu emulieren,
  85. muß das <varname>$_dependentTables</varname> Array in der Klasse für die Eltern-Tabelle
  86. definiert werden. Der Klassenname muß für jede abhängige Komponente aufgelistet werden.
  87. Hierbei muß der Klassenname und nicht der physikalische Name der <acronym>SQL</acronym>
  88. Tabelle verwendet werden.
  89. </para>
  90. <note>
  91. <para>
  92. Die Deklaration von <varname>$_dependentTables</varname> sollte übergangen werden
  93. wenn referentielle Integritätsverknüpfungen im <acronym>RDBMS</acronym> Server
  94. verwendet werden um kaskadierende Operationen zu implementieren. Siehe
  95. <link linkend="zend.db.table.relationships.cascading">dieses Kapitel</link> für
  96. weitere Informationen.
  97. </para>
  98. </note>
  99. <para>
  100. Das <varname>$_referenceMap</varname> Array muß in der Klasse für jede abhängige
  101. Tabelle deklariert werden. Das ist ein assoziatives Array von Referenz-"Regeln". Eine
  102. Referenzregel identifiziert welche Tabelle in der Relation die Elterntabelle ist, und
  103. listet auch welche Spalten in der abhängigen Tabelle welche Spalten in der
  104. Elterntabelle referenzieren.
  105. </para>
  106. <para>
  107. Der Schlüssel der Regel ist ein String der als Index zum
  108. <varname>$_referenceMap</varname> Array verwendet wird. Dieser Regelschlüssel wird
  109. verwendet um jede Referenzen von Abhängigkeiten zu idenzifizieren. Es sollte ein
  110. sprechender Name für diesen Regelschlüssel ausgewählt werden. Deshalb ist es das beste
  111. einen String zu verwendet welcher Teil eines <acronym>PHP</acronym> Methodennamens sein
  112. kann, wie man später sieht.
  113. </para>
  114. <para>
  115. Im Beispiel <acronym>PHP</acronym> Code von oben, sind die Regelschlüssel in der Bugs
  116. Tabelle folgende: <command>'Reporter'</command>, <command>'Engineer'</command>,
  117. <command>'Verifier'</command>, und <command>'Product'</command>.
  118. </para>
  119. <para>
  120. Die Werte von jedem Regeleintrag im <varname>$_referenceMap</varname> Array sind auch
  121. ein assoziatives Array. Die Elemente dieses Regeleintrages werden im folgenden
  122. beschrieben:
  123. </para>
  124. <itemizedlist>
  125. <listitem>
  126. <para>
  127. <emphasis>columns</emphasis> => Ein String oder ein Array von
  128. Strings welche die Namen der entfernten Schlüsselspalte der abhängigen Tabelle
  129. benennen.
  130. </para>
  131. <para>
  132. Es ist üblich das dies eine einzelne Spalte ist, aber einige Tabellen haben
  133. mehr-spaltige Schlüssel.
  134. </para>
  135. </listitem>
  136. <listitem>
  137. <para>
  138. <emphasis>refTableClass</emphasis> => Der Klassenname der
  139. Elterntabelle. Es sollte der Klassenname und nicht der physikalische Name der
  140. <acronym>SQL</acronym> Tabelle verwendet werden.
  141. </para>
  142. <para>
  143. Es ist für eine abhängige Tabelle üblich eine eigene Referenz zu Ihrer
  144. Elterntabelle zu haben, aber einige Tabellen haben mehrfache Referenzen zu der
  145. gleichen Elterntabelle. In der Beispieldatenbank gibt es eine Referenz von der
  146. <command>bugs</command> Tabelle zu der <command>products</command> Tabelle, aber
  147. drei Referenzen von der <command>bugs</command> Tabelle zur
  148. <command>accounts</command> Tabelle. Jede Referenz sollte in einen separaten
  149. Eintrag im <varname>$_referenceMap</varname> Array gegeben werden.
  150. </para>
  151. </listitem>
  152. <listitem>
  153. <para>
  154. <emphasis>refColumns</emphasis> => Ein String oder ein Array von
  155. Strings die den Spaltennamen des primären Schlüssels in der Elterntabelle
  156. benennen.
  157. </para>
  158. <para>
  159. Es ist üblich das dies eine einzelne Spalte ist, aber einige Tabellen haben
  160. mehr-spaltige Schlüssel. Wenn die Referenz einen mehr-spaltigen Schlüssel
  161. verwendet, muß die Reihenfolge der Spalten im <command>'columns'</command>
  162. Eintrag der Reihenfolge der Spalten im <command>'refColumns'</command> Eintrag
  163. entsprechen.
  164. </para>
  165. <para>
  166. Dieses Element kann optional spezifiziert werden. Wenn
  167. <property>refColumns</property> nicht spezifiziert wird, werden standardmäßig
  168. die Spalten verwendet, die als primäre Schlüsselspalten in der Elterntabelle
  169. bekannt sind.
  170. </para>
  171. </listitem>
  172. <listitem>
  173. <para>
  174. <emphasis>onDelete</emphasis> => Eine Regel für eine Aktion die
  175. ausgeführt wird wenn eine Zeile in der Elterntabelle gelöscht wird. Siehe auch
  176. <link linkend="zend.db.table.relationships.cascading">dieses Kapitel</link> für
  177. weitere Informationen.
  178. </para>
  179. </listitem>
  180. <listitem>
  181. <para>
  182. <emphasis>onUpdate</emphasis> => Eine Regel für eine Aktion die
  183. ausgeführt wird wenn Werte in der primären Schlüsselspalte der Elterntabelle
  184. aktualisiert werden. Siehe auch
  185. <link linkend="zend.db.table.relationships.cascading">dieses Kapitel</link> für
  186. weitere Informationen.
  187. </para>
  188. </listitem>
  189. </itemizedlist>
  190. </sect2>
  191. <sect2 id="zend.db.table.relationships.fetching.dependent">
  192. <title>Eine abhängige Zeile holen</title>
  193. <para>
  194. Wenn man ein Zeilen Objekt als Ergebnis einer Abfrage auf einer Elterntabelle hat,
  195. können Zeilen der abhängigen Tabellen geholt werden, welche die aktuelle Zeile
  196. referenzieren. Hierbei kann die folgende Methode verwendet werden:
  197. </para>
  198. <programlisting language="php"><![CDATA[
  199. $row->findDependentRowset($table, [$rule]);
  200. ]]></programlisting>
  201. <para>
  202. Diese Methode gibt ein <classname>Zend_Db_Table_Rowset_Abstract</classname> Objekt
  203. zurück, welche ein Set von Zeilen der abhängigen Tabelle <varname>$table</varname>
  204. enthält die die Zeile referenzieren die durch das <varname>$row</varname> Objekt
  205. identifiziert werden.
  206. </para>
  207. <para>
  208. Das erste Argument <varname>$table</varname> kann ein String sein, der die abhängige
  209. Tabelle durch Ihren Klassennamen spezifiziert. Man kann die abhängige Tabelle auch durch
  210. Verwendung eines Objekts dieser Tabellenklasse spezifizieren.
  211. </para>
  212. <example id="zend.db.table.relationships.fetching.dependent.example">
  213. <title>Eine abhängige Zeile holen</title>
  214. <para>
  215. Dieses Beispiel zeigt wie man ein Zeilenobjekt von der Tabelle
  216. <command>Accounts</command> erhält und die <command>Bugs</command> findet die durch
  217. diesen Account mitgeteilt wurden.
  218. </para>
  219. <programlisting language="php"><![CDATA[
  220. $accountsTable = new Accounts();
  221. $accountsRowset = $accountsTable->find(1234);
  222. $user1234 = $accountsRowset->current();
  223. $bugsReportedByUser = $user1234->findDependentRowset('Bugs');
  224. ]]></programlisting>
  225. </example>
  226. <para>
  227. Das zweite Argument <varname>$rule</varname> ist optional. Es ist ein String der den
  228. Regelschlüssel im <varname>$_referenceMap</varname> Array der abhängigen Tebellenklasse
  229. benennt. Wenn keine Regel spezifiziert wird, wird die erste Regel im Array verwendet
  230. welche die Elterntabelle referenziert. Wenn eine andere Regel als die erste verwendet
  231. werden soll, muß der Schlüssel spezifiziert werden.
  232. </para>
  233. <para>
  234. Im obigen Beispiel wird der Regelschlüssel nicht spezifiziert, sodas standardmäßig die
  235. Regel verwendet wird die als erste der Elterntabelle entspricht. Das ist die Regel
  236. <command>'Reporter'</command>.
  237. </para>
  238. <example id="zend.db.table.relationships.fetching.dependent.example-by">
  239. <title>Eine anhängige Zeile durch eine spezifische Regel erhalten</title>
  240. <para>
  241. Das Beispiel zeigt wie ein Zeilenobjekt von der <command>Accounts</command> Tabelle
  242. erhalten werden kann, und die zugeordneten <command>Bugs</command> die vom Benutzer
  243. dieses Accounts bereits gefixed wurden, gefunden werden können. Der String des
  244. Regelschlüssels der zu dieser Referenziellen Abhängigkeit in dem Beispiel
  245. korrespondiert ist <command>'Engineer'</command>.
  246. </para>
  247. <programlisting language="php"><![CDATA[
  248. $accountsTable = new Accounts();
  249. $accountsRowset = $accountsTable->find(1234);
  250. $user1234 = $accountsRowset->current();
  251. $bugsAssignedToUser = $user1234->findDependentRowset('Bugs', 'Engineer');
  252. ]]></programlisting>
  253. </example>
  254. <para>
  255. Es können auch Kriterien, Sortierungen und Limits zur Relation hinzugefügt werden indem
  256. das Select Objekt der Elternzeilen verwendet wird.
  257. </para>
  258. <example id="zend.db.table.relationships.fetching.dependent.example-by-select">
  259. <title>
  260. Ein anhängiges Zeilenset erhalten indem Zend_Db_Table_Select verwendet wird
  261. </title>
  262. <para>
  263. Dieses Beispiel zeigt wir ein Zeilenobjekt von der Tabelle
  264. <command>Accounts</command> empfangen werden kann, und die zugeordneten
  265. <command>Bugs</command> die vom Benutzer dieses Zugangs zu beheben sind, gefunden
  266. werden können, beschränkt auf 3 Zeilen und nach Name sortiert.
  267. </para>
  268. <programlisting language="php"><![CDATA[
  269. $accountsTable = new Accounts();
  270. $accountsRowset = $accountsTable->find(1234);
  271. $user1234 = $accountsRowset->current();
  272. $select = $accountsTable->select()->order('name ASC')
  273. ->limit(3);
  274. $bugsAssignedToUser = $user1234->findDependentRowset('Bugs',
  275. 'Engineer',
  276. $select);
  277. ]]></programlisting>
  278. </example>
  279. <para>
  280. Alternativ können Zeilen von einer abhängigen Tabelle abgefragt werden indem ein
  281. spezieller Mechanismus verwendet wird der "magische Methode" genannt wird.
  282. <classname>Zend_Db_Table_Row_Abstract</classname> ruft die Methode:
  283. <methodname>findDependentRowset('&lt;TabellenKlasse&gt;', '&lt;Regel&gt;')</methodname>
  284. auf wenn eine Methode am Zeilenobjekt aufgerufen wird die einem der folgenden Patterns
  285. entspricht:
  286. </para>
  287. <itemizedlist>
  288. <listitem>
  289. <para>
  290. <command>$row->find&lt;TabellenKlasse&gt;()</command>
  291. </para>
  292. </listitem>
  293. <listitem>
  294. <para>
  295. <command>$row->find&lt;TabellenKlasse&gt;By&lt;Regel&gt;()</command>
  296. </para>
  297. </listitem>
  298. </itemizedlist>
  299. <para>
  300. In den obigen Patterns, sind <command>&lt;TabellenKlasse&gt;</command> und
  301. <command>&lt;Regel&gt;</command> Strings die mit dem Klassennamen der abhängigen Tabelle
  302. korrespondieren, und der Regelschlüssel der abhängigen Tabelle der die Enterntabelle
  303. referenziert.
  304. </para>
  305. <note>
  306. <para>
  307. Einige Applikationsframeworks, wie Ruby on Rails, verwenden einen Mechanismus der
  308. "inflection" genannt wird um die Änderung der Schreibweise von Identifizierern
  309. abhängig von der Verwendung zu erlauben. Der Einfachheit halber, bietet
  310. <classname>Zend_Db_Table_Row</classname> keinen Inflection Mechanismus an. Die
  311. Identität der Tabelle und der Regelschlüssel die im Methodenaufruf genannt werden
  312. müssen der Schreibweise der Klasse und des Regelschlüssels exakt entsprechen.
  313. </para>
  314. </note>
  315. <example id="zend.db.table.relationships.fetching.dependent.example-magic">
  316. <title>Holen von abhängigen Zeilen durch Verwendung der magischen Methode</title>
  317. <para>
  318. Dieses Beispiel zeigt wie abhängige Zeilen gefunden werden, entsprechend des
  319. vorherigen Beispiel. In diesem Fall, verwendet die Anwendung den magischen
  320. Methodenaufruf anstatt die Tabelle und Regel als String zu spezifizieren.
  321. </para>
  322. <programlisting language="php"><![CDATA[
  323. $accountsTable = new Accounts();
  324. $accountsRowset = $accountsTable->find(1234);
  325. $user1234 = $accountsRowset->current();
  326. // Verwendung der standard Referenzregel
  327. $bugsReportedBy = $user1234->findBugs();
  328. // Eine Referenzregel spezifizieren
  329. $bugsAssignedTo = $user1234->findBugsByEngineer();
  330. ]]></programlisting>
  331. </example>
  332. </sect2>
  333. <sect2 id="zend.db.table.relationships.fetching.parent">
  334. <title>Eine Elternzeile holen</title>
  335. <para>
  336. Wenn man ein Zeilenobjekt als Ergebnis einer Abfrage auf eine abhängige Tabelle hat,
  337. kann man die Zeile vom Elternteil zu der die abhängige Zeile referenziert holen.
  338. Hierbei verwendet man die Methode:
  339. </para>
  340. <programlisting language="php"><![CDATA[
  341. $row->findParentRow($table, [$rule]);
  342. ]]></programlisting>
  343. <para>
  344. Es sollte immer exakt eine Zeile in der Elterntabelle durch eine abhängige Zeile
  345. referenziert sein, deshalb gibt diese Methode ein Zeilen Objekt und kein Zeilenset
  346. Objekt zurück.
  347. </para>
  348. <para>
  349. Das erste Argument <varname>$table</varname> kann ein String sein der die Elterntabelle
  350. durch Ihren Klassennamen spezifiziert. Man kann die Elterntabelle auch durch Verwendung
  351. eines Objektes dieser Tabellenklasse spezifizieren.
  352. </para>
  353. <example id="zend.db.table.relationships.fetching.parent.example">
  354. <title>Eine Elternzeile holen</title>
  355. <para>
  356. Dieses Beispiel zeigt wie ein Zeilen Objekt von der Tabelle <command>Bugs</command>
  357. geholt werden kann (zum Beispiel einer dieser Fehler mit Status 'NEW'), und die
  358. Zeile in der <command>Accounts</command> Tabelle für diesen Benutzer, der den Fehler
  359. gemeldet hat, gefunden werden kann.
  360. </para>
  361. <programlisting language="php"><![CDATA[
  362. $bugsTable = new Bugs();
  363. $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?' => 'NEW'));
  364. $bug1 = $bugsRowset->current();
  365. $reporter = $bug1->findParentRow('Accounts');
  366. ]]></programlisting>
  367. </example>
  368. <para>
  369. Das zweite Argument <varname>$rule</varname> ist optional. Es ist ein Strung der den
  370. Regelschlüssel im <varname>$_referenceMap</varname> Array der abhängigen Tabellenklasse
  371. benennt. Wenn diese Regel nicht spezifiziert wird, wird die erste Regel im Array
  372. genommen das die Elterntabelle referenziert. Wenn eine andere Regel als der erste
  373. genommen werden muß, dann muß der Schlüssel spezifiziert werden.
  374. </para>
  375. <para>
  376. Im obigen Beispiel wird der Regelschlüssel nicht spezifiziert, sodas standardmäßig die
  377. Regel verwendet wird die als erste der Elterntabelle entspricht. Das ist die Regel
  378. <command>'Reporter'</command>.
  379. </para>
  380. <example id="zend.db.table.relationships.fetching.parent.example-by">
  381. <title>Eine Elternzeile durch eine spezifizierte Regel holen</title>
  382. <para>
  383. Dieses Beispiel zeigt wie ein Zeilenobjekt von der Tabelle <command>Bugs</command>
  384. geholt werden kann, und der Account für den Ingenieur der zugeordnet wurde, diesen
  385. Fehler zu beheben, gefunden werden kann. Der Regelschlüssel der in diesem Beispiel
  386. der referenzierten Abhängigkeit entspricht ist <command>'Engineer'</command>.
  387. </para>
  388. <programlisting language="php"><![CDATA[
  389. $bugsTable = new Bugs();
  390. $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
  391. $bug1 = $bugsRowset->current();
  392. $engineer = $bug1->findParentRow('Accounts', 'Engineer');
  393. ]]></programlisting>
  394. </example>
  395. <para>
  396. Alternativ, können Zeilen von der Elterntabelle abgefragt werden indem eine
  397. "magische Methode" verwendet wird. <classname>Zend_Db_Table_Row_Abstract</classname>
  398. ruft die Methode:
  399. <methodname>findParentRow('&lt;TableClass&gt;', '&lt;Rule&gt;')</methodname> auf
  400. wenn eine Methode auf dem Zeilenobjekt aufgerufen wird die einer der folgenden Pattern
  401. entspricht:
  402. </para>
  403. <itemizedlist>
  404. <listitem>
  405. <para>
  406. <command>$row->findParent&lt;TabellenKlasse&gt;([Zend_Db_Table_Select
  407. $select])</command>
  408. </para>
  409. </listitem>
  410. <listitem>
  411. <para>
  412. <command>$row->findParent&lt;TabellenKlasse&gt;By&lt;Regel&gt;(
  413. [Zend_Db_Table_Select $select])</command>
  414. </para>
  415. </listitem>
  416. </itemizedlist>
  417. <para>
  418. In den obigen Pattern sind, <command>&lt;TabellenKlasse&gt;</command> und
  419. <command>&lt;Regel&gt;</command> Strings die dem Klassennamen der Elterntabelle
  420. entsprechen, und der Regelname der abhängigen Tabelle der die Elterntabelle
  421. referenziert.
  422. </para>
  423. <note>
  424. <para>
  425. Die Identität der Tabelle und des Regelschlüssels die im Aufruf der Methode genannt
  426. werden, müssen der Schreibweise der Klasse und des Regelschlüssels exakt
  427. entsprechen.
  428. </para>
  429. </note>
  430. <example id="zend.db.table.relationships.fetching.parent.example-magic">
  431. <title>Die Elternzeile durch verwenden der magischen Methode holen</title>
  432. <para>
  433. Dieses Beispiel zeigt wie Elternzeilen gefunden werden, ähnlich dem vorherigen
  434. Beispiel. In diesem Fall verwendet die Anwendung den Aufruf der magischen Methode
  435. statt der Spezifizierung von Tabelle und Regel als Strings.
  436. </para>
  437. <programlisting language="php"><![CDATA[
  438. $bugsTable = new Bugs();
  439. $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
  440. $bug1 = $bugsRowset->current();
  441. // Verwenden der standardmäßigen Referenzregel
  442. $reporter = $bug1->findParentAccounts();
  443. // Die Referenzregel spezifizieren
  444. $engineer = $bug1->findParentAccountsByEngineer();
  445. ]]></programlisting>
  446. </example>
  447. </sect2>
  448. <sect2 id="zend.db.table.relationships.fetching.many-to-many">
  449. <title>Ein Zeilenset über eine Viele-zu-Viele Verknüpfung holen</title>
  450. <para>
  451. Wenn man ein Zeilenobjekt als Ergebnis einer Abfrage auf eine Tabelle in einer
  452. Viele-Zu-Viele Verknüpfung hat (für die Zwecke dieses Beispiels, nennen wir das die
  453. "Original" Tabelle), können entsprechende Zeilen in der anderen Tabelle (nennen wir das
  454. die "Ziel" Tabelle) über eine Verknüpfungstabelle geholt werden. Hierbei wird die
  455. folgende Methode verwendet:
  456. </para>
  457. <programlisting language="php"><![CDATA[
  458. $row->findManyToManyRowset($table,
  459. $intersectionTable,
  460. [$rule1,
  461. [$rule2,
  462. [Zend_Db_Table_Select $select]
  463. ]
  464. ]);
  465. ]]></programlisting>
  466. <para>
  467. Diese Methode gibt ein <classname>Zend_Db_Table_Rowset_Abstract</classname> zurück
  468. welches Zeilen von der Tabelle <varname>$table</varname> enthält, und der Viele-Zu-Viele
  469. Abhängigkeit entspricht. Das aktuelle Zeilenobjekt <varname>$row</varname> von der
  470. originalen Tabelle wird verwendet um Zeilen in der Verknüpfungstabelle zu finden, und es
  471. ist mit der Zieltabelle verbunden.
  472. </para>
  473. <para>
  474. Das erste Argument <varname>$table</varname> kann ein String sein der die Zieltabelle in
  475. der Viele-Zu-Viele Verknüpfung durch seinen Klassennamen spezifiziert. Es kann auch die
  476. Zieltabelle durch Verwendung eines Objekts dieser Tabellenklasse spezifiziert werden.
  477. </para>
  478. <para>
  479. Das zweite Argument <varname>$intersectionTable</varname> kann ein String sein, der die
  480. Verknüpfungstabelle zwischen diesen zwei Tabellen in der Viele-Zu-Viele Verknüpfung,
  481. durch seinen Klassennamen, spezifiziert. Die Verknüpfungstabelle kann auch durch
  482. Verwendung eines Objektes dieser Tabellenklasse spezifiziert werden.
  483. </para>
  484. <example id="zend.db.table.relationships.fetching.many-to-many.example">
  485. <title>Ein Zeilenset mit einer Viele-Zu-Viele Methode holen</title>
  486. <para>
  487. Dieses Beispiel zeigt wie man ein Zeilenobjekt von der Originaltabelle
  488. <command>Bugs</command> erhält, und wie Zeilen von der Zieltabelle
  489. <command>Products</command> gefunden werden können die Produkte repräsentieren
  490. welche diesem Bug zugeordnet sind.
  491. </para>
  492. <programlisting language="php"><![CDATA[
  493. $bugsTable = new Bugs();
  494. $bugsRowset = $bugsTable->find(1234);
  495. $bug1234 = $bugsRowset->current();
  496. $productsRowset = $bug1234->findManyToManyRowset('Products',
  497. 'BugsProducts');
  498. ]]></programlisting>
  499. </example>
  500. <para>
  501. Das dritte und vierte Argument <varname>$rule1</varname> und <varname>$rule2</varname>
  502. sind optional. Das sind Strings die den Regelschlüssel im
  503. <varname>$_referenceMap</varname> Array der verknüpfungstabelle benennen.
  504. </para>
  505. <para>
  506. Der <varname>$rule1</varname> Schlüssel benennt die Regel für die Verknüpfung der
  507. Verknüpfungstabelle zur Originaltabelle. In diesem Beispiel ist das die verknüpfung von
  508. <command>BugsProducts</command> zu <command>Bugs</command>.
  509. </para>
  510. <para>
  511. Der <varname>$rule2</varname> Schlüssel benennt die Regel für die Verknüpfung der
  512. Verknüpfungstabelle zur Zieltabelle. In diesem Beispiel ist der die Verknüpfung von
  513. <command>Bugs</command> zu <command>Products</command>.
  514. </para>
  515. <para>
  516. Ähnlich den Methoden für das finden von Eltern- und abhängigen Zeilen verwendet die
  517. Methode, wenn keine Regel spezifiziert wird, die erste Regel im
  518. <varname>$_referenceMap</varname> Array das den Tabellen in der Verknüpfung entspricht.
  519. Wenn eine andere Regel als die erste verwendet werden soll, muß der Schlüssel
  520. spezifiziert werden.
  521. </para>
  522. <para>
  523. Im obigen Beispiel wird der Regelschlüssel nicht spezifiziert, sodas standardmäßig die
  524. ersten passenden Regeln verwendet werden. In diesem Fall ist <varname>$rule1</varname>
  525. <command>'Reporter'</command> und <varname>$rule2</varname> ist
  526. <command>'Product'</command>.
  527. </para>
  528. <example id="zend.db.table.relationships.fetching.many-to-many.example-by">
  529. <title>
  530. Ein Zeilenset mit einer Viele-Zu-Viele Methode durch eine spezielle Regel holen
  531. </title>
  532. <para>
  533. Dieses Beispiel zeigt wie man ein Zeilenobjekt von der Originaltabelle
  534. <command>Bugs</command> erhält, und Zeilen von der Zieltabelle
  535. <command>Products</command> findet die Produkte repräsentieren die dem Fehler
  536. zugeordnet sind.
  537. </para>
  538. <programlisting language="php"><![CDATA[
  539. $bugsTable = new Bugs();
  540. $bugsRowset = $bugsTable->find(1234);
  541. $bug1234 = $bugsRowset->current();
  542. $productsRowset = $bug1234->findManyToManyRowset('Products',
  543. 'BugsProducts',
  544. 'Bug');
  545. ]]></programlisting>
  546. </example>
  547. <para>
  548. Alternativ können Zeilen von der Zieltabelle in einer Viele-Zu-Viele Verknüpfung
  549. abgefragt werden inden eine "magische Methode" verwendet wird.
  550. <classname>Zend_Db_Table_Row_Abstract</classname> ruft die Methode:
  551. <command>findManyToManyRowset('&lt;TabellenKlasse&gt;',
  552. '&lt;VerknüpfungTabellenKlasse&gt;', '&lt;Regel1&gt;', '&lt;Regel2&gt;')</command>
  553. auf, wenn eine Methode aufgerufen wird die einem der folgenden Pattern entspricht:
  554. </para>
  555. <itemizedlist>
  556. <listitem>
  557. <para>
  558. <command>$row->find&lt;TabellenKlasse&gt;Via&lt;VerknüpfungsTabellenKlasse&gt;
  559. ([Zend_Db_Table_Select $select])</command>
  560. </para>
  561. </listitem>
  562. <listitem>
  563. <para>
  564. <command>$row->find&lt;TabellenKlasse&gt;Via&lt;VerknüpfungsTabellenKlasse&gt;By&lt;Regel1&gt;
  565. ([Zend_Db_Table_Select $select])</command>
  566. </para>
  567. </listitem>
  568. <listitem>
  569. <para>
  570. <command>$row->find&lt;TabellenKlasse&gt;Via&lt;VerknüpfungsTabellenKlasse&gt;By&lt;Regel1&gt;And&lt;Regel2&gt;
  571. ([Zend_Db_Table_Select $select])</command>
  572. </para>
  573. </listitem>
  574. </itemizedlist>
  575. <para>
  576. In den oben gezeigten Pattern sind <command>&lt;TabellenKlasse&gt;</command> und
  577. <command>&lt;VerknüpfungsTabellenKlasse&gt;</command> Strings die den Klassennamen der
  578. Zieltabelle und der Verknüpfungstabelle entsprechen. <command>&lt;Regel1&gt;</command>
  579. und <command>&lt;Regel2&gt;</command> sind Strings die den Regelschlüssel in der
  580. Verknüpfungstabelle entsprechen, welche die Originaltabelle und die Zieltabelle
  581. referenzieren.
  582. </para>
  583. <note>
  584. <para>
  585. Die Tabelleneinheiten und die Regelschlüssel die in der aufgerufenen Methode
  586. benannt werden, müssen exakt der Schreibweise der Klasse und des Regelschlüssels
  587. entsprechen.
  588. </para>
  589. </note>
  590. <example id="zend.db.table.relationships.fetching.many-to-many.example-magic">
  591. <title>Zeilensets durch Verwendung der magischen Viele-Zu-Viele Methode holen</title>
  592. <para>
  593. Dieses Beispiel zeigt wie Zeilen in der Zieltabelle einer Viele-Zu-Viele
  594. Verknüpfung gefunden werden können, in der Produkte die einen Bezug zu einem
  595. angegebenen Fehler haben, entsprechen.
  596. </para>
  597. <programlisting language="php"><![CDATA[
  598. $bugsTable = new Bugs();
  599. $bugsRowset = $bugsTable->find(1234);
  600. $bug1234 = $bugsRowset->current();
  601. // Verwendung der standardmäßigen Referenzregel
  602. $products = $bug1234->findProductsViaBugsProducts();
  603. // Spezifizieren der Referenzregel
  604. $products = $bug1234->findProductsViaBugsProductsByBug();
  605. ]]></programlisting>
  606. </example>
  607. </sect2>
  608. <sect2 id="zend.db.table.relationships.cascading">
  609. <title>Schreiboperationen kaskadieren</title>
  610. <note>
  611. <title>Deklarieren von DRI in der Datenbank:</title>
  612. <para>
  613. Die Deklaration von kaskadierenden Operationen in
  614. <classname>Zend_Db_Table</classname> <emphasis>nur</emphasis> für
  615. <acronym>RDBMS</acronym> Marken gedacht die keine deklarative referentielle
  616. Integrität unterstützen (<acronym>DRI</acronym>).
  617. </para>
  618. <para>
  619. Zum Beispiel, bei der Verwendung von MySQL's MyISAM Speicherengine oder SQLite.
  620. Diese Lösungen unterstützen kein <acronym>DRI</acronym>. Hierbei ist es hilfreich
  621. die kaskadierenden Operationen mit <classname>Zend_Db_Table</classname> zu
  622. deklarieren.
  623. </para>
  624. <para>
  625. Wenn die eigene <acronym>RDBMS</acronym> <acronym>DRI</acronym> implementiert sowie
  626. die ON <constant>DELETE</constant> und ON <constant>UPDATE</constant> Klauseln,
  627. sollten diese Klauseln im eigenen Datenbank Schema deklariert werden, anstatt das
  628. kaskadierende Feature von <classname>Zend_Db_Table</classname> zu verwenden. Die
  629. Deklaration von <acronym>DRI</acronym> Regeln in der <acronym>RDBMS</acronym> ist
  630. besser für die Geschwindigkeit der Datenbank, Konsistenz und Integrität.
  631. </para>
  632. <para>
  633. Am wichtigsten ist aber das die kaskadierenden Operationen nicht in beiden, der
  634. <acronym>RDBMS</acronym> und der eigenen <classname>Zend_Db_Table</classname>
  635. Klasse deklariert werden.
  636. </para>
  637. </note>
  638. <para>
  639. Kaskadierende Operationen können deklariert werden um anhand einer abhängigen Tabelle
  640. ausgeführt zu werden wenn ein <constant>UPDATE</constant> oder ein
  641. <constant>DELETE</constant> an einer Zeile in einer Elterntabelle ausgeführt wird.
  642. </para>
  643. <example id="zend.db.table.relationships.cascading.example-delete">
  644. <title>Beispiel für ein kaskadierendes Löschen</title>
  645. <para>
  646. Dieses Beispiel zeigt das Löschen einer Zeile in der <command>Products</command>
  647. Tabelle, welche konfiguriert ist um automatisch abhängige Zeilen in der
  648. <command>Bugs</command> Tabelle zu löschen.
  649. </para>
  650. <programlisting language="php"><![CDATA[
  651. $productsTable = new Products();
  652. $productsRowset = $productsTable->find(1234);
  653. $product1234 = $productsRowset->current();
  654. $product1234->delete();
  655. // Kaskadiert automatisch zur Bugs Tabelle und löscht abhängige Zeilen.
  656. ]]></programlisting>
  657. </example>
  658. <para>
  659. Genauso kann es gewünscht sein, wenn man ein <constant>UPDATE</constant> verwendet um
  660. den Wert eines primären Schlüssels in einer Elterntabelle zu verändern, das sich auch
  661. den Wert im entfernten Schlüssel der abhängigen Tabellen automatisch von selbst
  662. aktualisiert um dem neuen Wert zu entsprechen, sodas solche Referenzen aktuel gehalten
  663. werden.
  664. </para>
  665. <para>
  666. Normalerweise ist es nicht notwendig die Werte eines primären Schlüssels, der durch
  667. eine Sequenz von anderen Mechanismen erstellt wurde, zu aktualisieren. Aber wenn man
  668. einen <emphasis>natürlichen Schlüssel</emphasis> verwendet, der den Wert plötzlich
  669. ändert, ist es besser kaskadierende Aktualisierungen auf abhängigen Tabellen
  670. durchzuführen.
  671. </para>
  672. <para>
  673. Um eine kaskadierende Abhängigkeit in <classname>Zend_Db_Table</classname> zu
  674. deklarieren, müssen die Regeln in <varname>$_referenceMap</varname> bearbeitet werden.
  675. Die assoziativen Arrayschlüssel <command>'onDelete'</command> und
  676. <command>'onUpdate'</command> müssen auf den String 'cascade' (oder die Konstante
  677. <constant>self::CASCADE</constant>) gesetzt werden. Bevor eine Zeile von der
  678. Elterntabelle gelöscht wird oder dessen Wert des primären Schlüssels aktualisiert wird,
  679. werden alle Zeilen in der abhängigen Tabelle, welche die Eltern-Zeilen referenzieren,
  680. zuerst gelöscht oder aktualisiert.
  681. </para>
  682. <example id="zend.db.table.relationships.cascading.example-declaration">
  683. <title>Beispieldeklaration einer kaskadierenden Operation</title>
  684. <para>
  685. Im unten angeführten Beispiel, werden die Zeilen in der <command>Bugs</command>
  686. Tabelle automatisch gelöscht wenn eine Zeile in der <command>Products</command>
  687. Tabelle zu der Sie referenzieren gelöscht wird. Das <command>'onDelete'</command>
  688. Element des Referenzplan Eintrages wird auf <constant>self::CASCADE</constant>
  689. gesetzt.
  690. </para>
  691. <para>
  692. Es wird in diesem Beispiel keine kaskadierende Aktualisierung durchgeführt wenn der
  693. primäre Schlüsselwert in der Elternklasse verändert wird. Das
  694. <command>'onUpdate'</command> Element des Referenzplan Eintrages ist
  695. <constant>self::RESTRICT</constant>. Das gleiche Ergebnis erhält man durch
  696. Unterdrückung des <command>'onUpdate'</command> Eintrages.
  697. </para>
  698. <programlisting language="php"><![CDATA[
  699. class BugsProducts extends Zend_Db_Table_Abstract
  700. {
  701. ...
  702. protected $_referenceMap = array(
  703. 'Product' => array(
  704. 'columns' => array('product_id'),
  705. 'refTableClass' => 'Products',
  706. 'refColumns' => array('product_id'),
  707. 'onDelete' => self::CASCADE,
  708. 'onUpdate' => self::RESTRICT
  709. ),
  710. ...
  711. );
  712. }
  713. ]]></programlisting>
  714. </example>
  715. <sect3 id="zend.db.table.relationships.cascading.notes">
  716. <title>Notizen betreffend kaskadierenden Operationen</title>
  717. <para>
  718. <emphasis>Kaskadierende Operationen die durch <classname>Zend_Db_Table</classname>
  719. aufgerufen werden sind nicht atomar.</emphasis>
  720. </para>
  721. <para>
  722. Das bedeutet, das wenn die eigene Datenbank referentielle integrative Verknüpfungen
  723. implementiert und erzwingt, ein kaskadierends <constant>UPDATE</constant> das durch
  724. eine <classname>Zend_Db_Table</classname> Klasse ausgeführt wird mit der Verknüpfung
  725. kollidiert, und in einem referentiellen integrativen Verstoß mündet. Ein
  726. kaskadierendes <constant>UPDATE</constant> kann in
  727. <classname>Zend_Db_Table</classname> <emphasis>nur</emphasis> dann verwendet werden
  728. wenn die eigene Datenbank die referentielle integrative Verknüpfung nicht erzwingt.
  729. </para>
  730. <para>
  731. Ein kaskadierendes <constant>DELETE</constant> erleidet weniger durch das Problem
  732. des referentiellen integrativen Verstoßes. Abhängige Zeilen können genauso gelöscht
  733. werden wie durch eine nicht-atomare Aktion bevor die Elternzeile welche diese
  734. referenziert gelöscht wird.
  735. </para>
  736. <para>
  737. Trotzdem, für beide <constant>UPDATE</constant> und <constant>DELETE</constant>,
  738. erzeugt die Änderung der Datenbank in einem nicht-atomaren Weg auch das Risiko das
  739. ein anderer Datenbankbenutzer die Daten in einem inkonsistenten Status sieht. Wenn,
  740. zum Beispiel, eine Zeile und alle Ihre abhängigen Zeilen, gelöscht werden, gibt es
  741. eine kleine Chance das ein anderes Datenbank Clientprogramm die Datenbank abfragen
  742. kann nachdem die abhängigen Zeilen gelöscht wurden, aber bevor die Elternzeilen
  743. gelöscht wurden. Dieses Clientprogramm kann die Elternzeilen ohne abhängige Zeilen
  744. sehen, und diese als gewünschten Status der Daten annehmen. Es gibt keinen Weg für
  745. diesen Clienten herauszufinden das die Abfrage der Datenbank mitten während einer
  746. Änderung gelesen wurde.
  747. </para>
  748. <para>
  749. Der Fall von nicht-atomaren Änderungen kann durch die Verwendung von Transaktionen
  750. entschärft werden indem die Änderungen isoliert werden. Aber einige
  751. <acronym>RDBMS</acronym> Marken unterstützen keine Transaktionen, oder erlauben dem
  752. Clienten "schmutzige" Änderungen zu lesen die noch nicht fertiggestellt wurden.
  753. </para>
  754. <para>
  755. <emphasis>Kaskadierende Operationen in <classname>Zend_Db_Table</classname> werden
  756. nur durch <classname>Zend_Db_Table</classname> aufgerufen.</emphasis>
  757. </para>
  758. <para>
  759. Kaskadierendes Löschen und Aktualisieren welches in den eigenen
  760. <classname>Zend_Db_Table</classname> Klassen definiert wurde werden ausgeführt wenn
  761. die <methodname>save()</methodname> oder <methodname>delete()</methodname> Methoden
  762. der Zeilenklasse ausgeführt werden. Trotzdem, wenn ein Update oder Löschen von
  763. Daten durch Verwendung eines anderen Interfaces durchgeführt wird, wie durch ein
  764. Abfragetool oder eine andere Anwendung, werden die kaskadierenden Operationen nicht
  765. ausgeführt. Selbst wenn die <methodname>update()</methodname> und
  766. <methodname>delete()</methodname> Methoden in der
  767. <classname>Zend_Db_Adapter</classname> Klasse verwendet werden, werden die
  768. kaskadierenden Operationen die in der eigenen <classname>Zend_Db_Table</classname>
  769. Klasse definiert wurden, nicht ausgeführt.
  770. </para>
  771. <para>
  772. <emphasis>Kein kaskadierendes <constant>INSERT</constant>.</emphasis>
  773. </para>
  774. <para>
  775. Es gibt keine Unterstützung für ein kaskadierendes <constant>INSERT</constant>. Man
  776. muß eine Zeile in eine Elterntabelle in einer Operation hinzufügen, und Zeilen zu
  777. einer abhängigen Tabelle in einer unabhängigen Operation hinzufügen.
  778. </para>
  779. </sect3>
  780. </sect2>
  781. </sect1>