[ZF-10089] Zend_Log
[zend.git] / documentation / manual / es / module_specs / Zend_Db_Table-Relationships.xml
blob363c58543a717de49c86deedbd5f920411496612
1 <?xml version="1.0" encoding="UTF-8"?>
2     <!-- EN-Revision: 17598 -->
3     <!-- Reviewed: no -->
4 <sect1 id="zend.db.table.relationships">
6     <title>Zend_Db_Table Relationships</title>
8     <sect2 id="zend.db.table.relationships.introduction">
10         <title>Introduction</title>
12         <para>
13             Tables have relationships to each other in a relational database. An entity in one
14             table can be linked to one or more entities in another table by using referential
15             integrity constraints defined in the database schema.
16        </para>
18         <para>
19             The
20             <classname>Zend_Db_Table_Row</classname>
21             class has methods for querying related rows
22             in other tables.
23         </para>
25     </sect2>
27     <sect2 id="zend.db.table.relationships.defining">
29         <title>Defining Relationships</title>
31         <para>
32             Define classes for each of your tables, extending the abstract class
33             <classname>Zend_Db_Table_Abstract</classname>
34             , as described in
35             <xref linkend="zend.db.table.defining"/>
36             . Also
37             see
38             <xref linkend="zend.db.adapter.example-database"/>
39             for a description of the
40             example database for which the following example code is
41             designed.
42         </para>
44         <para>
45             Below are the
46             <acronym>PHP</acronym>
47             class definitions for these tables:
48         </para>
50         <programlisting language="php"><![CDATA[
51 class Accounts extends Zend_Db_Table_Abstract
53     protected $_name            = 'accounts';
54     protected $_dependentTables = array('Bugs');
57 class Products extends Zend_Db_Table_Abstract
59     protected $_name            = 'products';
60     protected $_dependentTables = array('BugsProducts');
63 class Bugs extends Zend_Db_Table_Abstract
65     protected $_name            = 'bugs';
67     protected $_dependentTables = array('BugsProducts');
69     protected $_referenceMap    = array(
70         'Reporter' => array(
71             'columns'           => 'reported_by',
72             'refTableClass'     => 'Accounts',
73             'refColumns'        => 'account_name'
74         ),
75         'Engineer' => array(
76             'columns'           => 'assigned_to',
77             'refTableClass'     => 'Accounts',
78             'refColumns'        => 'account_name'
79         ),
80         'Verifier' => array(
81             'columns'           => array('verified_by'),
82             'refTableClass'     => 'Accounts',
83             'refColumns'        => array('account_name')
84         )
85     );
88 class BugsProducts extends Zend_Db_Table_Abstract
90     protected $_name = 'bugs_products';
92     protected $_referenceMap    = array(
93         'Bug' => array(
94             'columns'           => array('bug_id'),
95             'refTableClass'     => 'Bugs',
96             'refColumns'        => array('bug_id')
97         ),
98         'Product' => array(
99             'columns'           => array('product_id'),
100             'refTableClass'     => 'Products',
101             'refColumns'        => array('product_id')
102         )
103     );
106 ]]></programlisting>
108         <para>
109             If you use
110             <classname>Zend_Db_Table</classname>
111             to emulate cascading UPDATE and DELETE
112             operations, declare the
113             <varname>$_dependentTables</varname>
114             array in the class for the
115             parent table. List the class name for each dependent table.
116             Use the class name, not the
117             physical name of the
118             <acronym>SQL</acronym>
119             table.
120         </para>
122         <note>
124             <para>
125                 Skip declaration of
126                 <varname>$_dependentTables</varname>
127                 if you use referential
128                 integrity constraints in the
129                 <acronym>RDBMS</acronym>
130                 server to implement cascading
131                 operations. See
132                 <xref linkend="zend.db.table.relationships.cascading"/>
133                 for more
134                 information.
135             </para>
137         </note>
139         <para>
140             Declare the
141             <varname>$_referenceMap</varname>
142             array in the class for each dependent
143             table. This is an associative array of reference
144             "rules". A reference rule identifies
145             which table is the parent table in the relationship,
146             and also lists which columns in the
147             dependent table reference which columns in the parent
148             table.
149         </para>
151         <para>
152             The rule key is a string used as an index to the
153             <varname>$_referenceMap</varname>
154             array. This rule key is used to identify each reference relationship. Choose a
155             descriptive name for this rule key. It's best to use a string that can be part of a
156             <acronym>PHP</acronym>
157             method name, as you will see later.
158         </para>
160         <para>
161             In the example
162             <acronym>PHP</acronym>
163             code above, the rule keys in the Bugs table class
164             are:
165             <code>'Reporter'</code>
166             ,
167             <code>'Engineer'</code>
168             ,
169             <code>'Verifier'</code>
170             , and
171             <code>'Product'</code>
172             .
173         </para>
175         <para>
176             The value of each rule entry in the
177             <varname>$_referenceMap</varname>
178             array is also an
179             associative array. The elements of this rule entry are described below:
180         </para>
182         <itemizedlist>
183             <listitem>
184                 <para>
185                     <emphasis>columns</emphasis>
186                     => A string or an array of strings
187                     naming the foreign key column name(s) in the
188                     dependent table.
189                 </para>
191                 <para>
192                     It's common for this to be a single column, but some tables have multi-column
193                     keys.
194                </para>
195             </listitem>
197             <listitem>
198                 <para>
199                     <emphasis>refTableClass</emphasis>
200                     => The class name of the parent table. Use
201                     the class name, not the physical name
202                     of the
203                     <acronym>SQL</acronym>
204                     table.
205                 </para>
207                 <para>
208                     It's common for a dependent table to have only one reference to its parent
209                     table, but some tables have multiple references to the same parent table. In
210                     the
211                     example database, there is one reference from the
212                     <code>bugs</code>
213                     table
214                     to the
215                     <code>products</code>
216                     table, but three references from the
217                     <code>bugs</code>
218                     table to the
219                     <code>accounts</code>
220                     table. Put each reference
221                     in a separate entry in the
222                     <varname>$_referenceMap</varname>
223                     array.
224                 </para>
225             </listitem>
227             <listitem>
228                 <para>
229                     <emphasis>refColumns</emphasis>
230                     => A string or an array of
231                     strings naming the primary key column name(s) in the
232                     parent table.
233                 </para>
235                 <para>
236                     It's common for this to be a single column, but some tables have multi-column
237                     keys. If the reference uses a multi-column key, the order of columns in the
238                     <code>'columns'</code>
239                     entry must match the order of columns in the
240                     <code>'refColumns'</code>
241                     entry.
242                 </para>
244                 <para>
245                     It is optional to specify this element. If you don't specify the
246                     <code>refColumns</code>
247                     , the column(s) reported as the primary key columns of
248                     the parent table are used
249                     by default.
250                 </para>
251             </listitem>
253             <listitem>
254                 <para>
255                     <emphasis>onDelete</emphasis>
256                     => The rule for an action to
257                     execute if a row is deleted in the parent table. See
258                     <xref linkend="zend.db.table.relationships.cascading"/>
259                     for more information.
260                 </para>
261             </listitem>
263             <listitem>
264                 <para>
265                     <emphasis>onUpdate</emphasis>
266                     => The rule for an action to
267                     execute if values in primary key columns are updated
268                     in the parent table. See
269                     <xref linkend="zend.db.table.relationships.cascading"/>
270                     for more information.
271                 </para>
272             </listitem>
273         </itemizedlist>
275     </sect2>
277     <sect2 id="zend.db.table.relationships.fetching.dependent">
279         <title>Fetching a Dependent Rowset</title>
281         <para>
282             If you have a Row object as the result of a query on a parent table, you can fetch
283             rows
284             from dependent tables that reference the current row. Use the method:
285        </para>
287         <programlisting language="php"><![CDATA[
288 $row->findDependentRowset($table, [$rule]);
289 ]]></programlisting>
291         <para>
292             This method returns a
293             <classname>Zend_Db_Table_Rowset_Abstract</classname>
294             object,
295             containing a set of rows from the dependent table
296             <varname>$table</varname>
297             that refer
298             to the row identified by the
299             <varname>$row</varname>
300             object.
301         </para>
303         <para>
304             The first argument
305             <varname>$table</varname>
306             can be a string that specifies the
307             dependent table by its class name. You can also
308             specify the dependent table by using an
309             object of that table class.
310         </para>
312         <example id="zend.db.table.relationships.fetching.dependent.example">
314             <title>Fetching a Dependent Rowset</title>
316             <para>
317                 This example shows getting a Row object from the table
318                 <code>Accounts</code>
319                 , and
320                 finding the
321                 <code>Bugs</code>
322                 reported by that account.
323             </para>
325             <programlisting language="php"><![CDATA[
326 $accountsTable = new Accounts();
327 $accountsRowset = $accountsTable->find(1234);
328 $user1234 = $accountsRowset->current();
330 $bugsReportedByUser = $user1234->findDependentRowset('Bugs');
331 ]]></programlisting>
333         </example>
335         <para>
336             The second argument
337             <varname>$rule</varname>
338             is optional. It is a string that names the
339             rule key in the
340             <varname>$_referenceMap</varname>
341             array of the dependent table class. If
342             you don't specify a rule, the first rule in the
343             array that references the parent table
344             is used. If you need to use a rule other than the
345             first, you need to specify the key.
346         </para>
348         <para>
349             In the example code above, the rule key is not specified, so the rule used by default
350             is
351             the first one that matches the parent table. This is the rule
352             <code>'Reporter'</code>
353             .
354         </para>
356         <example id="zend.db.table.relationships.fetching.dependent.example-by">
358             <title>Fetching a Dependent Rowset By a Specific Rule</title>
360             <para>
361                 This example shows getting a Row object from the table
362                 <code>Accounts</code>
363                 , and
364                 finding the
365                 <code>Bugs</code>
366                 assigned to be fixed by the user of that account. The
367                 rule key string that
368                 corresponds to this reference relationship in this example is
369                 <code>'Engineer'</code>
370                 .
371             </para>
373             <programlisting language="php"><![CDATA[
374 $accountsTable = new Accounts();
375 $accountsRowset = $accountsTable->find(1234);
376 $user1234 = $accountsRowset->current();
378 $bugsAssignedToUser = $user1234->findDependentRowset('Bugs', 'Engineer');
379 ]]></programlisting>
381         </example>
383         <para>
384             You can also add criteria, ordering and limits to your relationships using the parent
385             row's select object.
386        </para>
388         <para>
390             <example id="zend.db.table.relationships.fetching.dependent.example-by-select">
392                 <title>Fetching a Dependent Rowset using a Zend_Db_Table_Select</title>
394                 <para>
395                     This example shows getting a Row object from the table
396                     <code>Accounts</code>
397                     ,
398                     and finding the
399                     <code>Bugs</code>
400                     assigned to be fixed by the user of that
401                     account, limited only to 3 rows and
402                     ordered by name.
403                 </para>
405                 <programlisting language="php"><![CDATA[
406 $accountsTable = new Accounts();
407 $accountsRowset = $accountsTable->find(1234);
408 $user1234 = $accountsRowset->current();
409 $select = $accountsTable->select()->order('name ASC')
410                                   ->limit(3);
412 $bugsAssignedToUser = $user1234->findDependentRowset('Bugs',
413                                                      'Engineer',
414                                                      $select);
415 ]]></programlisting>
417             </example>
419             Alternatively, you can query rows from a dependent table using a special mechanism
420             called a "magic method".
421             <classname>Zend_Db_Table_Row_Abstract</classname>
422             invokes the
423             method:
424             <methodname>findDependentRowset('&lt;TableClass&gt;',
425                 '&lt;Rule&gt;')</methodname>
426             if you invoke a method on the Row object matching
427             either of the following patterns:
428         </para>
430         <itemizedlist>
431             <listitem>
432                 <para>
433                     <code>$row->find&lt;TableClass&gt;()</code>
434                 </para>
435             </listitem>
437             <listitem>
438                 <para>
439                     <code>$row->find&lt;TableClass&gt;By&lt;Rule&gt;()</code>
440                 </para>
441             </listitem>
442         </itemizedlist>
444         <para>
445             In the patterns above,
446             <code>&lt;TableClass&gt;</code>
447             and
448             <code>&lt;Rule&gt;</code>
449             are
450             strings that correspond to the class name of the dependent table, and the dependent
451             table's rule key that references the parent table.
452         </para>
454         <note>
456             <para>
457                 Some application frameworks, such as Ruby on Rails, use a mechanism called
458                 "inflection" to allow the spelling of identifiers to change depending on usage. For
459                 simplicity,
460                 <classname>Zend_Db_Table_Row</classname>
461                 does not provide any inflection
462                 mechanism. The table identity and the rule key named
463                 in the method call must match
464                 the spelling of the class and rule key exactly.
465             </para>
467         </note>
469         <example id="zend.db.table.relationships.fetching.dependent.example-magic">
471             <title>Fetching Dependent Rowsets using the Magic Method</title>
473             <para>
474                 This example shows finding dependent Rowsets equivalent to those in the previous
475                 examples. In this case, the application uses the magic method invocation instead of
476                 specifying the table and rule as strings.
477            </para>
479             <programlisting language="php"><![CDATA[
480 $accountsTable = new Accounts();
481 $accountsRowset = $accountsTable->find(1234);
482 $user1234 = $accountsRowset->current();
484 // Use the default reference rule
485 $bugsReportedBy = $user1234->findBugs();
487 // Specify the reference rule
488 $bugsAssignedTo = $user1234->findBugsByEngineer();
489 ]]></programlisting>
491         </example>
493     </sect2>
495     <sect2 id="zend.db.table.relationships.fetching.parent">
497         <title>Fetching a Parent Row</title>
499         <para>
500             If you have a Row object as the result of a query on a dependent table, you can fetch
501             the row in the parent to which the dependent row refers. Use the method:
502        </para>
504         <programlisting language="php"><![CDATA[
505 $row->findParentRow($table, [$rule]);
506 ]]></programlisting>
508         <para>
509             There always should be exactly one row in the parent table referenced by a dependent
510             row, therefore this method returns a Row object, not a Rowset object.
511        </para>
513         <para>
514             The first argument
515             <varname>$table</varname>
516             can be a string that specifies the parent
517             table by its class name. You can also specify
518             the parent table by using an object of
519             that table class.
520         </para>
522         <example id="zend.db.table.relationships.fetching.parent.example">
524             <title>Fetching the Parent Row</title>
526             <para>
527                 This example shows getting a Row object from the table
528                 <code>Bugs</code>
529                 (for
530                 example one of those bugs with status 'NEW'), and finding the row in the
531                 <code>Accounts</code>
532                 table for the user who reported the bug.
533             </para>
535             <programlisting language="php"><![CDATA[
536 $bugsTable = new Bugs();
537 $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?' => 'NEW'));
538 $bug1 = $bugsRowset->current();
540 $reporter = $bug1->findParentRow('Accounts');
541 ]]></programlisting>
543         </example>
545         <para>
546             The second argument
547             <varname>$rule</varname>
548             is optional. It is a string that names the
549             rule key in the
550             <varname>$_referenceMap</varname>
551             array of the dependent table class. If
552             you don't specify a rule, the first rule in the
553             array that references the parent table
554             is used. If you need to use a rule other than the
555             first, you need to specify the key.
556         </para>
558         <para>
559             In the example above, the rule key is not specified, so the rule used by default is the
560             first one that matches the parent table. This is the rule
561             <code>'Reporter'</code>
562             .
563         </para>
565         <example id="zend.db.table.relationships.fetching.parent.example-by">
567             <title>Fetching a Parent Row By a Specific Rule</title>
569             <para>
570                 This example shows getting a Row object from the table
571                 <code>Bugs</code>
572                 , and
573                 finding the account for the engineer assigned to fix that bug. The rule key
574                 string
575                 that corresponds to this reference relationship in this example is
576                 <code>'Engineer'</code>
577                 .
578             </para>
580             <programlisting language="php"><![CDATA[
581 $bugsTable = new Bugs();
582 $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
583 $bug1 = $bugsRowset->current();
585 $engineer = $bug1->findParentRow('Accounts', 'Engineer');
586 ]]></programlisting>
588         </example>
590         <para>
591             Alternatively, you can query rows from a parent table using a "magic method".
592             <classname>Zend_Db_Table_Row_Abstract</classname>
593             invokes the method:
594             <methodname>findParentRow('&lt;TableClass&gt;', '&lt;Rule&gt;')</methodname>
595             if you
596             invoke a method on the Row object matching either of the following patterns:
597         </para>
599         <itemizedlist>
600             <listitem>
601                 <para>
602                     <code>$row->findParent&lt;TableClass&gt;([Zend_Db_Table_Select $select])</code>
603                 </para>
604             </listitem>
606             <listitem>
607                 <para>
608                     <code>$row->findParent&lt;TableClass&gt;By&lt;Rule&gt;([Zend_Db_Table_Select
609                         $select])</code>
610                 </para>
611             </listitem>
612         </itemizedlist>
614         <para>
615             In the patterns above,
616             <code>&lt;TableClass&gt;</code>
617             and
618             <code>&lt;Rule&gt;</code>
619             are strings that correspond to the class name of the parent table, and the dependent
620             table's rule key that references the parent table.
621         </para>
623         <note>
625             <para>
626                 The table identity and the rule key named in the method call must match the
627                 spelling of the class and rule key exactly.
628            </para>
630         </note>
632         <example id="zend.db.table.relationships.fetching.parent.example-magic">
634             <title>Fetching the Parent Row using the Magic Method</title>
636             <para>
637                 This example shows finding parent Rows equivalent to those in the previous
638                 examples. In this case, the application uses the magic method invocation instead of
639                 specifying the table and rule as strings.
640            </para>
642             <programlisting language="php"><![CDATA[
643 $bugsTable = new Bugs();
644 $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
645 $bug1 = $bugsRowset->current();
647 // Use the default reference rule
648 $reporter = $bug1->findParentAccounts();
650 // Specify the reference rule
651 $engineer = $bug1->findParentAccountsByEngineer();
652 ]]></programlisting>
654         </example>
656     </sect2>
658     <sect2 id="zend.db.table.relationships.fetching.many-to-many">
660         <title>Fetching a Rowset via a Many-to-many Relationship</title>
662         <para>
663             If you have a Row object as the result of a query on one table in a many-to-many
664             relationship (for purposes of the example, call this the "origin" table), you can
665             fetch
666             corresponding rows in the other table (call this the "destination" table) via an
667             intersection table. Use the method:
668        </para>
670         <programlisting language="php"><![CDATA[
671 $row->findManyToManyRowset($table,
672                            $intersectionTable,
673                            [$rule1,
674                                [$rule2,
675                                    [Zend_Db_Table_Select $select]
676                                ]
677                            ]);
678 ]]></programlisting>
680         <para>
681             This method returns a
682             <classname>Zend_Db_Table_Rowset_Abstract</classname>
683             containing
684             rows from the table
685             <varname>$table</varname>
686             , satisfying the many-to-many relationship.
687             The current Row object
688             <varname>$row</varname>
689             from the origin table is used to find
690             rows in the intersection table, and that is joined
691             to the destination table.
692         </para>
694         <para>
695             The first argument
696             <varname>$table</varname>
697             can be a string that specifies the
698             destination table in the many-to-many relationship by
699             its class name. You can also
700             specify the destination table by using an object of that
701             table class.
702         </para>
704         <para>
705             The second argument
706             <varname>$intersectionTable</varname>
707             can be a string that specifies
708             the intersection table between the two tables in the
709             many-to-many relationship by
710             its class name. You can also specify the intersection table
711             by using an object of that
712             table class.
713         </para>
715         <example id="zend.db.table.relationships.fetching.many-to-many.example">
717             <title>Fetching a Rowset with the Many-to-many Method</title>
719             <para>
720                 This example shows getting a Row object from the origin table
721                 <code>Bugs</code>
722                 , and finding rows from the destination table
723                 <code>Products</code>
724                 , representing products related to that bug.
725             </para>
727             <programlisting language="php"><![CDATA[
728 $bugsTable = new Bugs();
729 $bugsRowset = $bugsTable->find(1234);
730 $bug1234 = $bugsRowset->current();
732 $productsRowset = $bug1234->findManyToManyRowset('Products',
733                                                  'BugsProducts');
734 ]]></programlisting>
736         </example>
738         <para>
739             The third and fourth arguments
740             <varname>$rule1</varname>
741             and
742             <varname>$rule2</varname>
743             are optional. These are strings that name the rule keys in the
744             <varname>$_referenceMap</varname>
745             array of the intersection table.
746         </para>
748         <para>
749             The
750             <varname>$rule1</varname>
751             key names the rule for the relationship from the
752             intersection table to the origin table.
753             In this example, this is the relationship from
754             <code>BugsProducts</code>
755             to
756             <code>Bugs</code>
757             .
758         </para>
760         <para>
761             The
762             <varname>$rule2</varname>
763             key names the rule for the relationship from the
764             intersection table to the destination
765             table. In this example, this is the relationship
766             from
767             <code>Bugs</code>
768             to
769             <code>Products</code>
770             .
771         </para>
773         <para>
774             Similarly to the methods for finding parent and dependent rows, if you don't specify a
775             rule, the method uses the first rule in the
776             <varname>$_referenceMap</varname>
777             array that
778             matches the tables in the relationship. If you need to use a rule other than
779             the first,
780             you need to specify the key.
781         </para>
783         <para>
784             In the example code above, the rule key is not specified, so the rules used by default
785             are the first ones that match. In this case,
786             <varname>$rule1</varname>
787             is
788             <code>'Reporter'</code>
789             and
790             <varname>$rule2</varname>
791             is
792             <code>'Product'</code>
793             .
794         </para>
796         <example id="zend.db.table.relationships.fetching.many-to-many.example-by">
798             <title>Fetching a Rowset with the Many-to-many Method By a Specific Rule</title>
800             <para>
801                 This example shows geting a Row object from the origin table
802                 <code>Bugs</code>
803                 , and finding rows from the destination table
804                 <code>Products</code>
805                 , representing products related to that bug.
806             </para>
808             <programlisting language="php"><![CDATA[
809 $bugsTable = new Bugs();
810 $bugsRowset = $bugsTable->find(1234);
811 $bug1234 = $bugsRowset->current();
813 $productsRowset = $bug1234->findManyToManyRowset('Products',
814                                                  'BugsProducts',
815                                                  'Bug');
816 ]]></programlisting>
818         </example>
820         <para>
821             Alternatively, you can query rows from the destination table in a many-to-many
822             relationship using a "magic method."
823             <classname>Zend_Db_Table_Row_Abstract</classname>
824             invokes the method:
825             <code>findManyToManyRowset('&lt;TableClass&gt;',
826                 '&lt;IntersectionTableClass&gt;', '&lt;Rule1&gt;', '&lt;Rule2&gt;')</code>
827             if you invoke
828             a method matching any of the following patterns:
829         </para>
831         <itemizedlist>
832             <listitem>
833                 <para>
834                     <code>$row->find&lt;TableClass&gt;Via&lt;IntersectionTableClass&gt;
835                         ([Zend_Db_Table_Select $select])</code>
836                 </para>
837             </listitem>
839             <listitem>
840                 <para>
841                     <code>$row->find&lt;TableClass&gt;Via&lt;IntersectionTableClass&gt;By&lt;Rule1&gt;
842                         ([Zend_Db_Table_Select $select])</code>
843                 </para>
844             </listitem>
846             <listitem>
847                 <para>
848                     <code>$row->find&lt;TableClass&gt;Via&lt;IntersectionTableClass&gt;By&lt;Rule1&gt;And&lt;Rule2&gt;
849                         ([Zend_Db_Table_Select $select])</code>
850                 </para>
851             </listitem>
852         </itemizedlist>
854         <para>
855             In the patterns above,
856             <code>&lt;TableClass&gt;</code>
857             and
858             <code>&lt;IntersectionTableClass&gt;</code>
859             are strings that correspond to the class
860             names of the destination table and the
861             intersection table, respectively.
862             <code>&lt;Rule1&gt;</code>
863             and
864             <code>&lt;Rule2&gt;</code>
865             are strings that correspond
866             to the rule keys in the intersection table that reference the
867             origin table and the
868             destination table, respectively.
869         </para>
871         <note>
873             <para>
874                 The table identities and the rule keys named in the method call must match the
875                 spelling of the class and rule key exactly.
876            </para>
878         </note>
880         <example id="zend.db.table.relationships.fetching.many-to-many.example-magic">
882             <title>Fetching Rowsets using the Magic Many-to-many Method</title>
884             <para>
885                 This example shows finding rows in the destination table of a many-to-many
886                 relationship representing products related to a given bug.
887            </para>
889             <programlisting language="php"><![CDATA[
890 $bugsTable = new Bugs();
891 $bugsRowset = $bugsTable->find(1234);
892 $bug1234 = $bugsRowset->current();
894 // Use the default reference rule
895 $products = $bug1234->findProductsViaBugsProducts();
897 // Specify the reference rule
898 $products = $bug1234->findProductsViaBugsProductsByBug();
899 ]]></programlisting>
901         </example>
903     </sect2>
905     <sect2 id="zend.db.table.relationships.cascading">
907         <title>Cascading Write Operations</title>
909         <note>
911             <title>Declare DRI in the database:</title>
913             <para>
914                 Declaring cascading operations in
915                 <classname>Zend_Db_Table</classname>
916                 is intended
917                 <emphasis>only</emphasis>
918                 for
919                 <acronym>RDBMS</acronym>
920                 brands that do not support
921                 declarative referential integrity (DRI).
922             </para>
924             <para>
925                 For example, if you use MySQL's MyISAM storage engine, or SQLite, these solutions
926                 do
927                 not support DRI. You may find it helpful to declare the cascading operations
928                 with
929                 <classname>Zend_Db_Table</classname>
930                 .
931             </para>
933             <para>
934                 If your
935                 <acronym>RDBMS</acronym>
936                 implements DRI and the
937                 <code>ON DELETE</code>
938                 and
939                 <code>ON UPDATE</code>
940                 clauses, you should declare these clauses in your database
941                 schema, instead of using
942                 the cascading feature in
943                 <classname>Zend_Db_Table</classname>
944                 . Declaring cascading DRI rules in the
945                 <acronym>RDBMS</acronym>
946                 is better for database performance, consistency, and
947                 integrity.
948             </para>
950             <para>
951                 Most importantly, do not declare cascading operations both in the
952                 <acronym>RDBMS</acronym>
953                 and in your
954                 <classname>Zend_Db_Table</classname>
955                 class.
956             </para>
958         </note>
960         <para>
961             You can declare cascading operations to execute against a dependent table when you
962             apply
963             an
964             <constant>UPDATE</constant>
965             or a
966             <constant>DELETE</constant>
967             to a row in a
968             parent table.
969         </para>
971         <example id="zend.db.table.relationships.cascading.example-delete">
973             <title>Example of a Cascading Delete</title>
975             <para>
976                 This example shows deleting a row in the
977                 <code>Products</code>
978                 table, which is
979                 configured to automatically delete dependent rows in the
980                 <code>Bugs</code>
981                 table.
982             </para>
984             <programlisting language="php"><![CDATA[
985 $productsTable = new Products();
986 $productsRowset = $productsTable->find(1234);
987 $product1234 = $productsRowset->current();
989 $product1234->delete();
990 // Automatically cascades to Bugs table
991 // and deletes dependent rows.
992 ]]></programlisting>
994         </example>
996         <para>
997             Similarly, if you use
998             <constant>UPDATE</constant>
999             to change the value of a primary key
1000             in a parent table, you may want the value in foreign
1001             keys of dependent tables to be
1002             updated automatically to match the new value, so that such
1003             references are kept up to
1004             date.
1005         </para>
1007         <para>
1008             It's usually not necessary to update the value of a primary key that was generated by a
1009             sequence or other mechanism. But if you use a
1010             <emphasis>natural key</emphasis>
1011             that may
1012             change value occasionally, it is more likely that you need to apply cascading
1013             updates
1014             to dependent tables.
1015         </para>
1017         <para>
1018             To declare a cascading relationship in the
1019             <classname>Zend_Db_Table</classname>
1020             , edit
1021             the rules in the
1022             <varname>$_referenceMap</varname>
1023             . Set the associative array keys
1024             <code>'onDelete'</code>
1025             and
1026             <code>'onUpdate'</code>
1027             to the string 'cascade' (or the
1028             constant
1029             <constant>self::CASCADE</constant>
1030             ). Before a row is deleted from the parent
1031             table, or its primary key values updated, any
1032             rows in the dependent table that refer to
1033             the parent's row are deleted or updated first.
1034         </para>
1036         <example id="zend.db.table.relationships.cascading.example-declaration">
1038             <title>Example Declaration of Cascading Operations</title>
1040             <para>
1041                 In the example below, rows in the
1042                 <code>Bugs</code>
1043                 table are automatically deleted
1044                 if the row in the
1045                 <code>Products</code>
1046                 table to which they refer is deleted. The
1047                 <code>'onDelete'</code>
1048                 element of the reference map entry is set to
1049                 <constant>self::CASCADE</constant>
1050                 .
1051             </para>
1053             <para>
1054                 No cascading update is done in the example below if the primary key value in the
1055                 parent class is changed. The
1056                 <code>'onUpdate'</code>
1057                 element of the reference map
1058                 entry is
1059                 <constant>self::RESTRICT</constant>
1060                 . You can get the same result by
1061                 omitting the
1062                 <code>'onUpdate'</code>
1063                 entry.
1064             </para>
1066             <programlisting language="php"><![CDATA[
1067 class BugsProducts extends Zend_Db_Table_Abstract
1069     ...
1070     protected $_referenceMap = array(
1071         'Product' => array(
1072             'columns'           => array('product_id'),
1073             'refTableClass'     => 'Products',
1074             'refColumns'        => array('product_id'),
1075             'onDelete'          => self::CASCADE,
1076             'onUpdate'          => self::RESTRICT
1077         ),
1078         ...
1079     );
1081 ]]></programlisting>
1083         </example>
1085         <sect3 id="zend.db.table.relationships.cascading.notes">
1087             <title>Notes Regarding Cascading Operations</title>
1089             <para>
1090                 <emphasis>
1091                     Cascading operations invoked by
1092                     <classname>Zend_Db_Table</classname>
1093                     are
1094                     not atomic.
1095                 </emphasis>
1096             </para>
1098             <para>
1099                 This means that if your database implements and enforces referential integrity
1100                 constraints, a cascading
1101                 <constant>UPDATE</constant>
1102                 executed by a
1103                 <classname>Zend_Db_Table</classname>
1104                 class conflicts with the constraint, and
1105                 results in a referential integrity
1106                 violation. You can use cascading
1107                 <constant>UPDATE</constant>
1108                 in
1109                 <classname>Zend_Db_Table</classname>
1110                 <emphasis>only</emphasis>
1111                 if your database does not enforce that referential
1112                 integrity constraint.
1113             </para>
1115             <para>
1116                 Cascading
1117                 <constant>DELETE</constant>
1118                 suffers less from the problem of referential
1119                 integrity violations. You can delete
1120                 dependent rows as a non-atomic action before
1121                 deleting the parent row that they
1122                 reference.
1123             </para>
1125             <para>
1126                 However, for both
1127                 <constant>UPDATE</constant>
1128                 and
1129                 <constant>DELETE</constant>
1130                 ,
1131                 changing the database in a non-atomic way also creates the risk that another
1132                 database user can see the data in an inconsistent state. For example, if you delete
1133                 a row and all its dependent rows, there is a small chance that another database
1134                 client program can query the database after you have deleted the dependent rows, but
1135                 before you delete the parent row. That client program may see the parent row with no
1136                 dependent rows, and assume this is the intended state of the data. There is no way
1137                 for that client to know that its query read the database in the middle of a change.
1138             </para>
1140             <para>
1141                 The issue of non-atomic change can be mitigated by using transactions to isolate
1142                 your change. But some
1143                 <acronym>RDBMS</acronym>
1144                 brands don't support transactions, or
1145                 allow clients to read "dirty" changes that have
1146                 not been committed yet.
1147             </para>
1149             <para>
1150                 <emphasis>
1151                     Cascading operations in
1152                     <classname>Zend_Db_Table</classname>
1153                     are invoked
1154                     only by
1155                     <classname>Zend_Db_Table</classname>
1156                     .
1157                 </emphasis>
1158             </para>
1160             <para>
1161                 Cascading deletes and updates defined in your
1162                 <classname>Zend_Db_Table</classname>
1163                 classes are applied if you execute the
1164                 <methodname>save()</methodname>
1165                 or
1166                 <methodname>delete()</methodname>
1167                 methods on the Row class. However, if you update
1168                 or delete data using another
1169                 interface, such as a query tool or another application,
1170                 the cascading operations are
1171                 not applied. Even when using
1172                 <methodname>update()</methodname>
1173                 and
1174                 <methodname>delete()</methodname>
1175                 methods
1176                 in the
1177                 <classname>Zend_Db_Adapter</classname>
1178                 class, cascading operations defined in
1179                 your
1180                 <classname>Zend_Db_Table</classname>
1181                 classes are not executed.
1182             </para>
1184             <para>
1185                 <emphasis>
1186                     No Cascading
1187                     <constant>INSERT</constant>
1188                     .
1189                 </emphasis>
1190             </para>
1192             <para>
1193                 There is no support for a cascading
1194                 <constant>INSERT</constant>
1195                 . You must insert a
1196                 row to a parent table in one operation, and insert row(s) to a
1197                 dependent table in a
1198                 separate operation.
1199             </para>
1201         </sect3>
1203     </sect2>
1205 </sect1>
1206     <!--
1207 vim:se ts=4 sw=4 et: