Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/*
3
 *  $Id: Relation.php 7490 2010-03-29 19:53:27Z jwage $
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.doctrine-project.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.doctrine-project.org
30
 * @since       1.0
31
 * @version     $Revision: 7490 $
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 relationships
42
     */
43
    const ONE   = 0;
44
 
45
    /**
46
     * constant for MANY_TO_MANY and ONE_TO_MANY relationships
47
     */
48
    const MANY  = 1;
49
 
50
    // TRUE => mandatory, everything else is just a default value. this should be refactored
51
    // since TRUE can bot be used as a default value this way. All values should be default values.
52
    /**
53
     * @var array $definition   @see __construct()
54
     */
55
    protected $definition = array('alias'       => true,
56
                                  'foreign'     => true,
57
                                  'local'       => true,
58
                                  'class'       => true,
59
                                  'type'        => true,
60
                                  'table'       => true,
61
                                  'localTable'  => true,
62
                                  'name'        => null,
63
                                  'refTable'    => null,
64
                                  'onDelete'    => null,
65
                                  'onUpdate'    => null,
66
                                  'deferred'    => null,
67
                                  'deferrable'  => null,
68
                                  'constraint'  => null,
69
                                  'equal'       => false,
70
                                  'cascade'     => array(), // application-level cascades
71
                                  'owningSide'  => false, // whether this is the owning side
72
                                  'refClassRelationAlias' => null,
73
                                  'foreignKeyName' => null,
74
                                  'orderBy' => null
75
                                  );
76
 
77
    protected $_isRefClass = null;
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
     *          localTable              the local table object
92
     *
93
     *          refTable                the reference table object (if any)
94
     *
95
     *          onDelete                referential delete action
96
     *
97
     *          onUpdate                referential update action
98
     *
99
     *          deferred                deferred constraint checking
100
     *
101
     *          alias                   relation alias
102
     *
103
     *          type                    the relation type, either Doctrine_Relation::ONE or Doctrine_Relation::MANY
104
     *
105
     *          constraint              boolean value, true if the relation has an explicit referential integrity constraint
106
     *
107
     *          foreignKeyName          the name of the dbms foreign key to create. Optional, if left blank Doctrine will generate one for you
108
     *
109
     * The onDelete and onUpdate keys accept the following values:
110
     *
111
     * CASCADE: Delete or update the row from the parent table and automatically delete or
112
     *          update the matching rows in the child table. Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
113
     *          Between two tables, you should not define several ON UPDATE CASCADE clauses that act on the same column
114
     *          in the parent table or in the child table.
115
     *
116
     * SET NULL: Delete or update the row from the parent table and set the foreign key column or columns in the
117
     *          child table to NULL. This is valid only if the foreign key columns do not have the NOT NULL qualifier
118
     *          specified. Both ON DELETE SET NULL and ON UPDATE SET NULL clauses are supported.
119
     *
120
     * NO ACTION: In standard SQL, NO ACTION means no action in the sense that an attempt to delete or update a primary
121
     *           key value is not allowed to proceed if there is a related foreign key value in the referenced table.
122
     *
123
     * RESTRICT: Rejects the delete or update operation for the parent table. NO ACTION and RESTRICT are the same as
124
     *           omitting the ON DELETE or ON UPDATE clause.
125
     *
126
     * SET DEFAULT
127
     */
128
    public function __construct(array $definition)
129
    {
130
        $def = array();
131
        foreach ($this->definition as $key => $val) {
132
            if ( ! isset($definition[$key]) && $val) {
133
                throw new Doctrine_Exception($key . ' is required!');
134
            }
135
            if (isset($definition[$key])) {
136
                $def[$key] = $definition[$key];
137
            } else {
138
                $def[$key] = $this->definition[$key];
139
            }
140
        }
141
        $this->definition = $def;
142
    }
143
 
144
    /**
145
     * hasConstraint
146
     * whether or not this relation has an explicit constraint
147
     *
148
     * @return boolean
149
     */
150
    public function hasConstraint()
151
    {
152
        return ($this->definition['constraint'] ||
153
                ($this->definition['onUpdate']) ||
154
                ($this->definition['onDelete']));
155
    }
156
 
157
    public function isDeferred()
158
    {
159
        return $this->definition['deferred'];
160
    }
161
 
162
    public function isDeferrable()
163
    {
164
        return $this->definition['deferrable'];
165
    }
166
 
167
    public function isEqual()
168
    {
169
        return $this->definition['equal'];
170
    }
171
 
172
    public function offsetExists($offset)
173
    {
174
        return isset($this->definition[$offset]);
175
    }
176
 
177
    public function offsetGet($offset)
178
    {
179
        if (isset($this->definition[$offset])) {
180
            return $this->definition[$offset];
181
        }
182
 
183
        return null;
184
    }
185
 
186
    public function offsetSet($offset, $value)
187
    {
188
        if (isset($this->definition[$offset])) {
189
            $this->definition[$offset] = $value;
190
        }
191
    }
192
 
193
    public function offsetUnset($offset)
194
    {
195
        $this->definition[$offset] = false;
196
    }
197
 
198
    /**
199
     * toArray
200
     *
201
     * @return array
202
     */
203
    public function toArray()
204
    {
205
        return $this->definition;
206
    }
207
 
208
    /**
209
     * getAlias
210
     * returns the relation alias
211
     *
212
     * @return string
213
     */
214
    final public function getAlias()
215
    {
216
        return $this->definition['alias'];
217
    }
218
 
219
    /**
220
     * getType
221
     * returns the relation type, either 0 or 1
222
     *
223
     * @see Doctrine_Relation MANY_* and ONE_* constants
224
     * @return integer
225
     */
226
    final public function getType()
227
    {
228
        return $this->definition['type'];
229
    }
230
 
231
    /**
232
     * Checks whether this relation cascades deletions to the related objects
233
     * on the application level.
234
     *
235
     * @return boolean
236
     */
237
    public function isCascadeDelete()
238
    {
239
        return in_array('delete', $this->definition['cascade']);
240
    }
241
 
242
    /**
243
     * getTable
244
     * returns the foreign table object
245
     *
246
     * @return Doctrine_Table
247
     */
248
    final public function getTable()
249
    {
250
        return Doctrine_Manager::getInstance()
251
               ->getConnectionForComponent($this->definition['class'])
252
               ->getTable($this->definition['class']);
253
    }
254
 
255
    /**
256
     * getClass
257
     * returns the name of the related class
258
     *
259
     * @return string
260
     */
261
    final public function getClass()
262
    {
263
        return $this->definition['class'];
264
    }
265
 
266
    /**
267
     * getLocal
268
     * returns the name of the local column
269
     *
270
     * @return string
271
     */
272
    final public function getLocal()
273
    {
274
        return $this->definition['local'];
275
    }
276
 
277
    /**
278
     * getLocalFieldName
279
     * returns the field name of the local column
280
     */
281
    final public function getLocalFieldName()
282
    {
283
        return $this->definition['localTable']->getFieldName($this->definition['local']);
284
    }
285
 
286
    /**
287
     * getLocalColumnName
288
     * returns the column name of the local column
289
     *
290
     * @return string $columnName
291
     */
292
    final public function getLocalColumnName()
293
    {
294
        return $this->definition['localTable']->getColumnName($this->definition['local']);
295
    }
296
 
297
    /**
298
     * getForeign
299
     * returns the name of the foreignkey column where
300
     * the localkey column is pointing at
301
     *
302
     * @return string
303
     */
304
    final public function getForeign()
305
    {
306
        return $this->definition['foreign'];
307
    }
308
 
309
    /**
310
     * getLocalFieldName
311
     * returns the field name of the foreign column
312
     */
313
    final public function getForeignFieldName()
314
    {
315
        return $this->definition['table']->getFieldName($this->definition['foreign']);
316
    }
317
 
318
    /**
319
     * getForeignColumnName
320
     * returns the column name of the foreign column
321
     *
322
     * @return string $columnName
323
     */
324
    final public function getForeignColumnName()
325
    {
326
       return $this->definition['table']->getColumnName($this->definition['foreign']);
327
    }
328
 
329
    /**
330
     * isOneToOne
331
     * returns whether or not this relation is a one-to-one relation
332
     *
333
     * @return boolean
334
     */
335
    final public function isOneToOne()
336
    {
337
        return ($this->definition['type'] == Doctrine_Relation::ONE);
338
    }
339
 
340
    /**
341
     * getRelationDql
342
     *
343
     * @param integer $count
344
     * @return string
345
     */
346
    public function getRelationDql($count)
347
    {
348
        $component = $this->getTable()->getComponentName();
349
 
350
        $dql  = 'FROM ' . $component
351
              . ' WHERE ' . $component . '.' . $this->definition['foreign']
352
              . ' IN (' . substr(str_repeat('?, ', $count), 0, -2) . ')'
353
              . $this->getOrderBy($component);
354
 
355
        return $dql;
356
    }
357
 
358
    /**
359
     * fetchRelatedFor
360
     *
361
     * fetches a component related to given record
362
     *
363
     * @param Doctrine_Record $record
364
     * @return Doctrine_Record|Doctrine_Collection
365
     */
366
    abstract public function fetchRelatedFor(Doctrine_Record $record);
367
 
368
    /**
369
     * Get the name of the foreign key for this relationship
370
     *
371
     * @return string $foreignKeyName
372
     */
373
    public function getForeignKeyName()
374
    {
375
        if (isset($this->definition['foreignKeyName'])) {
376
            return $this->definition['foreignKeyName'];
377
        }
378
        return $this['localTable']->getConnection()->generateUniqueRelationForeignKeyName($this);
379
    }
380
 
381
    /**
382
     * Get the relationship orderby SQL/DQL
383
     *
384
     * @param string $alias        The alias to use
385
     * @param boolean $columnNames Whether or not to use column names instead of field names
386
     * @return string $orderBy
387
     */
388
    public function getOrderBy($alias = null, $columnNames = false)
389
    {
390
        if ( ! $alias) {
391
           $alias = $this->getTable()->getComponentName();
392
        }
393
 
394
        if ($orderBy = $this->getOrderByStatement($alias, $columnNames)) {
395
            return ' ORDER BY ' . $orderBy;
396
        }
397
    }
398
 
399
    /**
400
     * Get the relationship orderby statement
401
     *
402
     * @param string $alias        The alias to use
403
     * @param boolean $columnNames Whether or not to use column names instead of field names
404
     * @return string $orderByStatement
405
     */
406
    public function getOrderByStatement($alias = null, $columnNames = false)
407
    {
408
        $table = $this->getTable();
409
 
410
        if ( ! $alias) {
411
           $alias = $table->getComponentName();
412
        }
413
 
414
        if (isset($this->definition['orderBy'])) {
415
            return $table->processOrderBy($alias, $this->definition['orderBy'], $columnNames);
416
        } else {
417
            return $table->getOrderByStatement($alias, $columnNames);
418
        }
419
    }
420
 
421
    public function isRefClass()
422
    {
423
        if ($this->_isRefClass === null) {
424
            $this->_isRefClass = false;
425
            $table = $this->getTable();
426
            foreach ($table->getRelations() as $name => $relation) {
427
                foreach ($relation['table']->getRelations() as $relation) {
428
                    if (isset($relation['refTable']) && $relation['refTable'] === $table) {
429
                        $this->_isRefClass = true;
430
                        break(2);
431
                    }
432
                }
433
            }
434
        }
435
 
436
        return $this->_isRefClass;
437
    }
438
 
439
    /**
440
     * __toString
441
     *
442
     * @return string
443
     */
444
    public function __toString()
445
    {
446
        $r[] = "<pre>";
447
        foreach ($this->definition as $k => $v) {
448
            if (is_object($v)) {
449
                $v = 'Object(' . get_class($v) . ')';
450
            }
451
            $r[] = $k . ' : ' . $v;
452
        }
453
        $r[] = "</pre>";
454
        return implode("\n", $r);
455
    }
456
}