Zend_Db_Table-Relationships.xml 40 KB

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