# 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 | }