Coverage for Doctrine_Relation

Back to coverage report

1 <?php
2 /*
3  *  $Id: Relation.php 2963 2007-10-21 06:23:59Z Jonathan.Wage $
4  *
5  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16  *
17  * This software consists of voluntary contributions made by many individuals
18  * and is licensed under the LGPL. For more information, see
19  * <http://www.phpdoctrine.org>.
20  */
21
22 /**
23  * Doctrine_Relation
24  * This class represents a relation between components
25  *
26  * @package     Doctrine
27  * @subpackage  Relation
28  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
29  * @link        www.phpdoctrine.org
30  * @since       1.0
31  * @version     $Revision: 2963 $
32  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
33  */
34 abstract class Doctrine_Relation implements ArrayAccess
35 {
36     /**
37      * RELATION CONSTANTS
38      */
39
40     /**
41      * constant for ONE_TO_ONE and MANY_TO_ONE aggregate relationships
42      */
43     const ONE_AGGREGATE         = 0;
44
45     /**
46      * constant for ONE_TO_ONE and MANY_TO_ONE composite relationships
47      */
48     const ONE_COMPOSITE         = 1;
49
50     /**
51      * constant for MANY_TO_MANY and ONE_TO_MANY aggregate relationships
52      */
53     const MANY_AGGREGATE        = 2;
54
55     /**
56      * constant for MANY_TO_MANY and ONE_TO_MANY composite relationships
57      */
58     const MANY_COMPOSITE        = 3;
59
60     const ONE   = 0;
61     const MANY  = 2;
62     
63     protected $definition = array('alias'       => true,
64                                   'foreign'     => true,
65                                   'local'       => true,
66                                   'class'       => true,
67                                   'type'        => true,
68                                   'table'       => true,
69                                   'name'        => false,
70                                   'refTable'    => false,
71                                   'onDelete'    => false,
72                                   'onUpdate'    => false,
73                                   'deferred'    => false,
74                                   'deferrable'  => false,
75                                   'constraint'  => false,
76                                   'equal'       => false,
77                                   );
78
79     /**
80      * constructor
81      *
82      * @param array $definition         an associative array with the following structure:
83      *          name                    foreign key constraint name
84      *
85      *          local                   the local field(s)
86      *
87      *          foreign                 the foreign reference field(s)
88      *
89      *          table                   the foreign table object
90      *
91      *          refTable                the reference table object (if any)
92      *
93      *          onDelete                referential delete action
94      *  
95      *          onUpdate                referential update action
96      *
97      *          deferred                deferred constraint checking 
98      *
99      *          alias                   relation alias
100      *
101      *          type                    the relation type, either Doctrine_Relation::ONE or Doctrine_Relation::MANY
102      *
103      *          constraint              boolean value, true if the relation has an explicit referential integrity constraint
104      *
105      * The onDelete and onUpdate keys accept the following values:
106      *
107      * CASCADE: Delete or update the row from the parent table and automatically delete or
108      *          update the matching rows in the child table. Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
109      *          Between two tables, you should not define several ON UPDATE CASCADE clauses that act on the same column
110      *          in the parent table or in the child table.
111      *
112      * SET NULL: Delete or update the row from the parent table and set the foreign key column or columns in the
113      *          child table to NULL. This is valid only if the foreign key columns do not have the NOT NULL qualifier 
114      *          specified. Both ON DELETE SET NULL and ON UPDATE SET NULL clauses are supported.
115      *
116      * NO ACTION: In standard SQL, NO ACTION means no action in the sense that an attempt to delete or update a primary 
117      *           key value is not allowed to proceed if there is a related foreign key value in the referenced table.
118      *
119      * RESTRICT: Rejects the delete or update operation for the parent table. NO ACTION and RESTRICT are the same as
120      *           omitting the ON DELETE or ON UPDATE clause.
121      *
122      * SET DEFAULT
123      */
124     public function __construct(array $definition)
125     {
126         $def = array();
127         foreach ($this->definition as $key => $val) {
128             if ( ! isset($definition[$key]) && $val) {
129                 throw new Doctrine_Exception($key . ' is required!');
130             }
131             if (isset($definition[$key])) {
132                 $def[$key] = $definition[$key];
133             } else {
134                 $def[$key] = null;          
135             }
136         }
137
138         $this->definition = $def;
139     }
140
141     /**
142      * hasConstraint
143      * whether or not this relation has an explicit constraint
144      *
145      * @return boolean
146      */
147     public function hasConstraint()
148     {
149         return ($this->definition['constraint'] ||
150                 ($this->definition['onUpdate']) ||
151                 ($this->definition['onDelete']));
152     }
153     public function isDeferred()
154     {
155         return $this->definition['deferred'];
156     }
157
158     public function isDeferrable()
159     {
160         return $this->definition['deferrable'];
161     }
162     public function isEqual()
163     {
164         return $this->definition['equal'];
165     }
166
167     public function offsetExists($offset)
168     {
169         return isset($this->definition[$offset]);
170     }
171
172     public function offsetGet($offset)
173     {
174         if (isset($this->definition[$offset])) {
175             return $this->definition[$offset];
176         }
177         
178         return null;
179     }
180
181     public function offsetSet($offset, $value)
182     {
183         if (isset($this->definition[$offset])) {
184             $this->definition[$offset] = $value;
185         }
186     }
187
188     public function offsetUnset($offset)
189     {
190         $this->definition[$offset] = false;
191     }
192
193     /**
194      * toArray
195      *
196      * @return array
197      */
198     public function toArray() 
199     {
200         return $this->definition;
201     }
202
203     /**
204      * getAlias
205      * returns the relation alias
206      *
207      * @return string
208      */
209     final public function getAlias()
210     {
211         return $this->definition['alias'];
212     }
213
214     /**
215      * getType
216      * returns the relation type, either 0 or 1
217      *
218      * @see Doctrine_Relation MANY_* and ONE_* constants
219      * @return integer
220      */
221     final public function getType()
222     {
223         return $this->definition['type'];
224     }
225
226     /**
227      * getTable
228      * returns the foreign table object
229      *
230      * @return object Doctrine_Table
231      */
232     final public function getTable()
233     {
234         return Doctrine_Manager::getInstance()
235                ->getConnectionForComponent($this->definition['class'])
236                ->getTable($this->definition['class']);
237     }
238
239     /**
240      * getLocal
241      * returns the name of the local column
242      *
243      * @return string
244      */
245     final public function getLocal()
246     {
247         return $this->definition['local'];
248     }
249
250     /**
251      * getForeign
252      * returns the name of the foreignkey column where
253      * the localkey column is pointing at
254      *
255      * @return string
256      */
257     final public function getForeign()
258     {
259         return $this->definition['foreign'];
260     }
261
262     /**
263      * isComposite
264      * returns whether or not this relation is a composite relation
265      *
266      * @return boolean
267      */
268     final public function isComposite()
269     {
270         return ($this->definition['type'] == Doctrine_Relation::ONE_COMPOSITE ||
271                 $this->definition['type'] == Doctrine_Relation::MANY_COMPOSITE);
272     }
273
274     /**
275      * isOneToOne
276      * returns whether or not this relation is a one-to-one relation
277      *
278      * @return boolean
279      */
280     final public function isOneToOne()
281     {
282         return ($this->definition['type'] == Doctrine_Relation::ONE_AGGREGATE ||
283                 $this->definition['type'] == Doctrine_Relation::ONE_COMPOSITE);
284     }
285
286     /**
287      * getRelationDql
288      *
289      * @param integer $count
290      * @return string
291      */
292     public function getRelationDql($count)
293     {
294         $component = $this->getTable()->getComponentName();
295
296         $dql  = 'FROM ' . $component
297               . ' WHERE ' . $component . '.' . $this->definition['foreign']
298               . ' IN (' . substr(str_repeat('?, ', $count), 0, -2) . ')';
299
300         return $dql;
301     }
302
303     /**
304      * fetchRelatedFor
305      *
306      * fetches a component related to given record
307      *
308      * @param Doctrine_Record $record
309      * @return Doctrine_Record|Doctrine_Collection
310      */
311     abstract public function fetchRelatedFor(Doctrine_Record $record);
312
313     /**
314      * __toString
315      *
316      * @return string
317      */
318     public function __toString()
319     {
320         $r[] = "<pre>";
321         foreach ($this->definition as $k => $v) {
322             if (is_object($v)) {
323                 $v = 'Object(' . get_class($v) . ')';
324             }
325             $r[] = $k . ' : ' . $v;
326         }
327         $r[] = "</pre>";
328         return implode("\n", $r);
329     }
330 }