AbstractRelation::getConnection()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 15
rs 9.4285
cc 2
eloc 9
nc 2
nop 0
1
<?php
2
/**
3
 * Fwk
4
 *
5
 * Copyright (c) 2011-2014, Julien Ballestracci <[email protected]>.
6
 * All rights reserved.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
15
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
16
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
17
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
21
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
 * POSSIBILITY OF SUCH DAMAGE.
23
 *
24
 * PHP Version 5.3
25
 *
26
 * @category   Database
27
 * @package    Fwk
28
 * @subpackage Db
29
 * @author     Julien Ballestracci <[email protected]>
30
 * @copyright  2011-2014 Julien Ballestracci <[email protected]>
31
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
32
 * @link       http://www.nitronet.org/fwk
33
 */
34
namespace Fwk\Db\Relations;
35
36
use Fwk\Db\Registry\RegistryState;
37
use Fwk\Db\RelationInterface,
38
    Fwk\Db\Registry\Registry,
39
    Fwk\Db\Exception,
40
    Fwk\Db\Connection,
41
    Fwk\Events\Dispatcher,
42
    \IteratorAggregate;
43
use Fwk\Db\Workers\DeleteEntityWorker;
44
use Fwk\Db\Workers\SaveEntityWorker;
45
46
/**
47
 * Abstract utility class for Relations
48
 *
49
 * @category Relations
50
 * @package  Fwk\Db
51
 * @author   Julien Ballestracci <[email protected]>
52
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
53
 * @link     http://www.nitronet.org/fwk
54
 */
55
abstract class AbstractRelation implements IteratorAggregate
56
{
57
    /**
58
     * Local column name
59
     *
60
     * @var string
61
     */
62
    protected $local;
63
64
    /**
65
     * Foreign column name
66
     *
67
     * @var string
68
     */
69
    protected $foreign;
70
71
    /**
72
     * Fetch mode
73
     * {@see RelationInterface::FETCH_LAZY} and {@see RelationInterface::FETCH_EAGER}
74
     *
75
     * @var integer
76
     */
77
    protected $fetchMode = RelationInterface::FETCH_LAZY;
78
79
    /**
80
     * Entity classname for this relation
81
     *
82
     * @var string
83
     */
84
    protected $entity;
85
86
    /**
87
     * Column name in parent entity for this relation
88
     *
89
     * @var string
90
     */
91
    protected $columnName;
92
93
    /**
94
     * Connection
95
     *
96
     * @var \Fwk\Db\Connection
97
     */
98
    protected $connection;
99
100
    /**
101
     * Is the relation fetched ?
102
     *
103
     * @var boolean
104
     */
105
    protected $fetched = false;
106
107
    /**
108
     * Parent references
109
     *
110
     * @var mixed
111
     */
112
    protected $parentRefs;
113
114
    /**
115
     * Parent entity (if any)
116
     *
117
     * @var mixed
118
     */
119
    protected $parent;
120
121
    /**
122
     * RelationInterface's own registry
123
     *
124
     * @var Registry
125
     */
126
    protected $registry;
127
128
    /**
129
     * Referenced table name
130
     *
131
     * @var string
132
     */
133
    protected $tableName;
134
135
    /**
136
     * List of entity listeners
137
     *
138
     * @var array
139
     */
140
    protected $listeners = array();
141
142
    /**
143
     * Constructor
144
     *
145
     * @param string $local     The local column's name
146
     * @param string $foreign   The foreign column's name
147
     * @param string $table     The foreign table name
148
     * @param string $entity    The entity's class name
0 ignored issues
show
Documentation introduced by
Should the type for parameter $entity not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
149
     * @param array  $listeners List of entity listeners
150
     *
151
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
152
     */
153
    public function __construct($local, $foreign, $table, $entity = null,
154
        array $listeners = array()
155
    ) {
156
        $this->tableName    = $table;
157
        $this->registry     = new Registry($table);
158
        $this->local        = $local;
159
        $this->foreign      = $foreign;
160
        $this->entity       = ($entity === null ? '\stdClass' : $entity);
161
        $this->listeners    = $listeners;
162
    }
163
164
    /**
165
     * FETCH_EAGER -or- FETCH_LAZY
166
     *
167
     * @param integer $mode The fetch mode (@see constants)
168
     *
169
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
170
     */
171
    public function setFetchMode($mode)
172
    {
173
        $this->fetchMode = $mode;
174
175
        return $this;
176
    }
177
178
    /**
179
     * Changes the fetched state of this relation
180
     *
181
     * @param boolean $bool Is the data fetched yet?
182
     *
183
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
184
     */
185
    public function setFetched($bool)
186
    {
187
        $this->fetched = (bool)$bool;
188
        if ($this->fetched === true) {
189
            $table  = $this->connection->table($this->tableName);
190
            $objs   = $this->getRegistry()->toArray();
191
            foreach ($objs as $object) {
192
                $this->getRegistry()->defineInitialValues(
193
                    $object,
194
                    $this->connection,
195
                    $table
196
                );
197
            }
198
        }
199
200
        return $this;
201
    }
202
203
     /**
204
     * Returns the connection defined for this relation
205
     *
206
     * @return Connection
207
     */
208
    public function getConnection()
209
    {
210
        if (!isset($this->connection)) {
211
            throw new Exception(
212
                sprintf(
213
                    'No connection defined for this relation (%s: %s<->%s)',
214
                    $this->tableName,
215
                    $this->local,
216
                    $this->foreign
217
                )
218
            );
219
        }
220
221
        return $this->connection;
222
    }
223
224
    /**
225
     * Sets a connection for this relation (used for lazy loading)
226
     *
227
     * @param Connection $connection The database connection instance
228
     *
229
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
230
     */
231
    public function setConnection(Connection $connection)
232
    {
233
        $this->connection   = $connection;
234
235
        return $this;
236
    }
237
238
    /**
239
     * Tells if an entity managed by this relation has changed
240
     *
241
     * @return boolean
242
     */
243
    public function hasChanged()
244
    {
245
        foreach ($this->getRegistry()->getStore() as $entry) {
246
            // trigger changedValues to ensure we have latest state
247
            $entry->getChangedValues();
248
249
            if (!$entry->isState(RegistryState::FRESH) || $entry->hasAction()) {
250
                return true;
251
            }
252
        }
253
254
        return false;
255
    }
256
257
    /**
258
     * Tells if this relation is active (parents references have been defined)
259
     *
260
     * @return boolean
261
     */
262
    public function isActive()
263
    {
264
        return isset($this->parentRefs);
265
    }
266
267
    /**
268
     * Tells if the specified object is in the relation
269
     *
270
     * @param object $object The object to test
271
     *
272
     * @return boolean
273
     */
274
    public function has($object)
275
    {
276
        return $this->getRegistry()->contains($object);
277
    }
278
279
    /**
280
     * Defines parent references
281
     *
282
     * @param array $refs Defines parent's references (eg. Primary Keys)
283
     *
284
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
285
     */
286
    public function setParentRefs($refs)
287
    {
288
        $this->parentRefs   = $refs;
289
290
        return $this;
291
    }
292
293
    /**
294
     * Sets the parent entity of this relation
295
     *
296
     * @param object     $object The parent entity
297
     * @param Dispatcher $evd    The Event Dispatcher for the parent entity.
298
     *
299
     * @return boolean true if parent has been changed/defined
300
     */
301
    public function setParent($object, Dispatcher $evd)
0 ignored issues
show
Coding Style introduced by
function setParent() does not seem to conform to the naming convention (^(?:is|has|should|may|su...ster|unregister|exists)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
302
    {
303
        if ($this->parent === $object) {
304
            return false;
305
        }
306
307
        $this->parent = $object;
308
309
        return true;
310
    }
311
312
    /**
313
     * Tells if this relation has been fetched
314
     *
315
     * @return boolean
316
     */
317
    public function isFetched()
318
    {
319
        return $this->fetched;
320
    }
321
322
    /**
323
     * Tells if this relation is in LAZY fetch mode
324
     *
325
     * @return boolean
326
     */
327
    public function isLazy()
328
    {
329
        return ($this->fetchMode === RelationInterface::FETCH_LAZY);
330
    }
331
332
    /**
333
     * Tells if this relation is in EAGER fetch mode
334
     *
335
     * @return boolean
336
     */
337
    public function isEager()
338
    {
339
        return ($this->fetchMode === RelationInterface::FETCH_EAGER);
340
    }
341
342
    /**
343
     * Return the defined entity for this relation
344
     *
345
     * @return string
346
     */
347
    public function getEntity()
348
    {
349
        return $this->entity;
350
    }
351
352
    /**
353
     * Return the foreign column for this relation
354
     *
355
     * @return string
356
     */
357
    public function getForeign()
358
    {
359
        return $this->foreign;
360
    }
361
362
    /**
363
     * Return the local column for this relation
364
     *
365
     * @return string
366
     */
367
    public function getLocal()
368
    {
369
        return $this->local;
370
    }
371
372
    /**
373
     * Removes all objects
374
     *
375
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
376
     */
377
    public function clear()
378
    {
379
        $this->getRegistry()->clear();
380
        $this->fetched = false;
381
382
        return $this;
383
    }
384
385
    /**
386
     * Returns this relation's registry
387
     *
388
     * @return Registry
389
     */
390
    public function getRegistry()
391
    {
392
        return $this->registry;
393
    }
394
395
    /**
396
     * Defines a Registry for this relation
397
     *
398
     * @param Registry $registry The registry
399
     *
400
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
401
     */
402
    public function setRegistry(Registry $registry)
403
    {
404
        $this->registry = $registry;
405
406
        return $this;
407
    }
408
409
    /**
410
     * Return this relation's table name
411
     *
412
     * @return string
413
     */
414
    public function getTableName()
415
    {
416
        return $this->tableName;
417
    }
418
419
    /**
420
     * Add an entity to this relation
421
     *
422
     * @param object $object      The entity to add
423
     * @param array  $identifiers Identifiers (PK) of this entity if any
424
     *
425
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
426
     */
427
    public function add($object, array $identifiers = array())
428
    {
429
        if ($this->has($object)) {
430
            return $this;
431
        }
432
433
        $this->getRegistry()->store($object, $identifiers, RegistryState::REGISTERED);
434
435
        return $this;
436
    }
437
438
    /**
439
     * Removes an entity from this relation
440
     *
441
     * @param object $object The entity to be removed
442
     *
443
     * @return RelationInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be AbstractRelation?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
444
     */
445
    public function remove($object)
446
    {
447
        if ($this->has($object)) {
448
            $this->getRegistry()->markForAction($object, Registry::ACTION_DELETE);
449
        }
450
451
        return $this;
452
    }
453
454
    /**
455
     * Fetches data from database
456
     *
457
     * @return RelationInterface
458
     */
459
    abstract public function fetch();
460
461
    /**
462
     * Returns a list of all entities in this relations.
463
     * Triggers a fetch() when fetchMode = FETCH_LAZY
464
     *
465
     * @return array
466
     */
467
    abstract public function toArray();
468
469
    /**
470
     * Return this relation data within an Iterator (foreach ...)
471
     * {@see \Traversable}
472
     *
473
     * @return \ArrayIterator
474
     */
475
    public function getIterator()
476
    {
477
        $this->fetch();
478
479
        return new \ArrayIterator($this->toArray());
480
    }
481
482
    /**
483
     * Returns all entity-listeners for this relation
484
     *
485
     * @return array
486
     */
487
    public function getListeners()
488
    {
489
        return $this->listeners;
490
    }
491
492
    /**
493
     * Returns to-be-executed workers queue
494
     *
495
     * @return \SplPriorityQueue
496
     */
497
    protected function getWorkersQueue()
498
    {
499
        $queue  = new \SplPriorityQueue();
500
501
        foreach ($this->getRegistry()->getStore() as $entry) {
502
            $entry->getChangedValues();
503
            $action = $entry->getAction();
504
            $state  = $entry->getState();
505
506
            if ($state === RegistryState::REGISTERED
507
                || ($state === RegistryState::CHANGED && $action !== Registry::ACTION_DELETE)
508
            ) {
509
                $action = Registry::ACTION_SAVE;
510
            }
511
512
            if ($action === Registry::ACTION_DELETE) {
513
                $queue->insert(new DeleteEntityWorker($entry->getObject()), $entry->getActionPriority());
514
            } elseif ($action === Registry::ACTION_SAVE) {
515
                $queue->insert(new SaveEntityWorker($entry->getObject()), $entry->getActionPriority());
516
            }
517
        }
518
519
        return $queue;
520
    }
521
}
522