Completed
Push — master ( 11f27c...4713a5 )
by Andreas
08:33
created

PersistentCollectionTrait   D

Complexity

Total Complexity 120

Size/Duplication

Total Lines 745
Duplicated Lines 6.44 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 87.16%

Importance

Changes 0
Metric Value
wmc 120
lcom 1
cbo 3
dl 48
loc 745
ccs 224
cts 257
cp 0.8716
rs 4.4444
c 0
b 0
f 0

60 Methods

Rating   Name   Duplication   Size   Complexity  
A setMongoData() 0 4 1
A getMongoData() 0 4 1
A setHints() 0 4 1
A getHints() 0 4 1
C initialize() 0 34 7
A setDirty() 0 4 1
A setOwner() 0 5 1
A clearSnapshot() 0 5 2
A getSnapshot() 0 4 1
A getDeleteDiff() 8 8 2
A getInsertDiff() 8 8 2
A getOwner() 0 4 1
A getMapping() 0 4 1
A isInitialized() 0 4 1
A first() 0 5 1
A last() 0 5 1
A containsKey() 0 5 1
A contains() 0 5 1
A exists() 0 5 1
A indexOf() 0 5 1
A get() 0 5 1
A getKeys() 0 5 1
A getValues() 0 5 1
A changed() 0 12 3
B isDirty() 0 15 5
A setDocumentManager() 0 5 1
A takeSnapshot() 0 12 3
A setInitialized() 0 4 1
A remove() 0 4 1
A removeElement() 0 13 2
B getDeletedDocuments() 13 13 5
B getInsertedDocuments() 13 13 5
A getTypeClass() 0 13 4
A count() 0 7 1
A set() 0 4 1
A add() 0 4 1
A isEmpty() 0 4 2
A getIterator() 0 5 1
A map() 0 5 1
A filter() 0 5 1
A forAll() 0 5 1
A partition() 0 5 1
A toArray() 0 5 1
C clear() 0 30 8
A slice() 0 5 1
A __sleep() 0 4 1
A offsetExists() 0 5 1
A offsetGet() 0 5 1
A offsetSet() 0 8 2
A offsetUnset() 0 4 1
A key() 0 4 1
A current() 0 4 1
A next() 0 4 1
A unwrap() 0 4 1
A __clone() 0 13 2
B doAdd() 3 18 7
A doRemove() 0 13 4
B doSet() 3 11 5
B isOrphanRemovalEnabled() 0 16 6
A needsSchedulingForDirtyCheck() 0 5 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PersistentCollectionTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PersistentCollectionTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB\PersistentCollection;
21
22
use Doctrine\Common\Collections\Collection as BaseCollection;
23
use Doctrine\ODM\MongoDB\DocumentManager;
24
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
25
use Doctrine\ODM\MongoDB\MongoDBException;
26
use Doctrine\ODM\MongoDB\UnitOfWork;
27
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
28
29
/**
30
 * Trait with methods needed to implement PersistentCollectionInterface.
31
 *
32
 * @since 1.1
33
 */
34
trait PersistentCollectionTrait
35
{
36
    /**
37
     * A snapshot of the collection at the moment it was fetched from the database.
38
     * This is used to create a diff of the collection at commit time.
39
     *
40
     * @var array
41
     */
42
    private $snapshot = array();
43
44
    /**
45
     * Collection's owning entity
46
     *
47
     * @var object
48
     */
49
    private $owner;
50
51
    /**
52
     * @var array
53
     */
54
    private $mapping;
55
56
    /**
57
     * Whether the collection is dirty and needs to be synchronized with the database
58
     * when the UnitOfWork that manages its persistent state commits.
59
     *
60
     * @var boolean
61
     */
62
    private $isDirty = false;
63
64
    /**
65
     * Whether the collection has already been initialized.
66
     *
67
     * @var boolean
68
     */
69
    private $initialized = true;
70
71
    /**
72
     * The wrapped Collection instance.
73
     *
74
     * @var BaseCollection
75
     */
76
    private $coll;
77
78
    /**
79
     * The DocumentManager that manages the persistence of the collection.
80
     *
81
     * @var DocumentManager
82
     */
83
    private $dm;
84
85
    /**
86
     * The UnitOfWork that manages the persistence of the collection.
87
     *
88
     * @var UnitOfWork
89
     */
90
    private $uow;
91
92
    /**
93
     * The raw mongo data that will be used to initialize this collection.
94
     *
95
     * @var array
96
     */
97
    private $mongoData = array();
98
99
    /**
100
     * Any hints to account for during reconstitution/lookup of the documents.
101
     *
102
     * @var array
103
     */
104
    private $hints = array();
105
106
    /** {@inheritdoc} */
107 2
    public function setDocumentManager(DocumentManager $dm)
108
    {
109 2
        $this->dm = $dm;
110 2
        $this->uow = $dm->getUnitOfWork();
111 2
    }
112
113
    /** {@inheritdoc} */
114 151
    public function setMongoData(array $mongoData)
115
    {
116 151
        $this->mongoData = $mongoData;
117 151
    }
118
119
    /** {@inheritdoc} */
120 148
    public function getMongoData()
121
    {
122 148
        return $this->mongoData;
123
    }
124
125
    /** {@inheritdoc} */
126 240
    public function setHints(array $hints)
127
    {
128 240
        $this->hints = $hints;
129 240
    }
130
131
    /** {@inheritdoc} */
132 150
    public function getHints()
133
    {
134 150
        return $this->hints;
135
    }
136
137
    /** {@inheritdoc} */
138 372
    public function initialize()
139
    {
140 372
        if ($this->initialized || ! $this->mapping) {
141 364
            return;
142
        }
143
144 163
        $newObjects = array();
145
146 163
        if ($this->isDirty) {
147
            // Remember any NEW objects added through add()
148 15
            $newObjects = $this->coll->toArray();
149
        }
150
151 163
        $this->initialized = true;
152
153 163
        $this->coll->clear();
154 163
        $this->uow->loadCollection($this);
155 163
        $this->takeSnapshot();
156
157 163
        $this->mongoData = array();
158
159
        // Reattach any NEW objects added through add()
160 163
        if ($newObjects) {
161 15
            foreach ($newObjects as $key => $obj) {
162 15
                if (CollectionHelper::isHash($this->mapping['strategy'])) {
163
                    $this->coll->set($key, $obj);
164
                } else {
165 15
                    $this->coll->add($obj);
166
                }
167
            }
168
169 15
            $this->isDirty = true;
170
        }
171 163
    }
172
173
    /**
174
     * Marks this collection as changed/dirty.
175
     */
176 188
    private function changed()
177
    {
178 188
        if ($this->isDirty) {
179 124
            return;
180
        }
181
182 188
        $this->isDirty = true;
183
184 188
        if ($this->needsSchedulingForDirtyCheck()) {
185 2
            $this->uow->scheduleForDirtyCheck($this->owner);
186
        }
187 188
    }
188
189
    /** {@inheritdoc} */
190 382
    public function isDirty()
191
    {
192 382
        if ($this->isDirty) {
193 245
            return true;
194
        }
195 332
        if (! $this->initialized && count($this->coll)) {
196
            // not initialized collection with added elements
197
            return true;
198
        }
199 332
        if ($this->initialized) {
200
            // if initialized let's check with last known snapshot
201 326
            return $this->coll->toArray() !== $this->snapshot;
202
        }
203 78
        return false;
204
    }
205
206
    /** {@inheritdoc} */
207 371
    public function setDirty($dirty)
208
    {
209 371
        $this->isDirty = $dirty;
210 371
    }
211
212
    /** {@inheritdoc} */
213 392
    public function setOwner($document, array $mapping)
214
    {
215 392
        $this->owner = $document;
216 392
        $this->mapping = $mapping;
217 392
    }
218
219
    /** {@inheritdoc} */
220 269
    public function takeSnapshot()
221
    {
222 269
        if (CollectionHelper::isList($this->mapping['strategy'])) {
223 257
            $array = $this->coll->toArray();
224 257
            $this->coll->clear();
225 257
            foreach ($array as $document) {
226 241
                $this->coll->add($document);
227
            }
228
        }
229 269
        $this->snapshot = $this->coll->toArray();
230 269
        $this->isDirty = false;
231 269
    }
232
233
    /** {@inheritdoc} */
234 20
    public function clearSnapshot()
235
    {
236 20
        $this->snapshot = array();
237 20
        $this->isDirty = $this->coll->count() ? true : false;
238 20
    }
239
240
    /** {@inheritdoc} */
241
    public function getSnapshot()
242
    {
243
        return $this->snapshot;
244
    }
245
246
    /** {@inheritdoc} */
247 88 View Code Duplication
    public function getDeleteDiff()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
248
    {
249 88
        return array_udiff_assoc(
250 88
            $this->snapshot,
251 88
            $this->coll->toArray(),
252
            function ($a, $b) { return $a === $b ? 0 : 1; }
253
        );
254
    }
255
256
    /** {@inheritdoc} */
257 View Code Duplication
    public function getDeletedDocuments()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
    {
259 128
        $compare = function ($a, $b) {
260 89
            $compareA = is_object($a) ? spl_object_hash($a) : $a;
261 89
            $compareb = is_object($b) ? spl_object_hash($b) : $b;
262 89
            return $compareA === $compareb ? 0 : ($compareA > $compareb ? 1 : -1);
263 128
        };
264 128
        return array_values(array_udiff(
265 128
            $this->snapshot,
266 128
            $this->coll->toArray(),
267 128
            $compare
268
        ));
269
    }
270
271
    /** {@inheritdoc} */
272 88 View Code Duplication
    public function getInsertDiff()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
273
    {
274 88
        return array_udiff_assoc(
275 88
            $this->coll->toArray(),
276 88
            $this->snapshot,
277
            function ($a, $b) { return $a === $b ? 0 : 1; }
278
        );
279
    }
280
281
    /** {@inheritdoc} */
282 View Code Duplication
    public function getInsertedDocuments()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
    {
284 4
        $compare = function ($a, $b) {
285 4
            $compareA = is_object($a) ? spl_object_hash($a) : $a;
286 4
            $compareb = is_object($b) ? spl_object_hash($b) : $b;
287 4
            return $compareA === $compareb ? 0 : ($compareA > $compareb ? 1 : -1);
288 4
        };
289 4
        return array_values(array_udiff(
290 4
            $this->coll->toArray(),
291 4
            $this->snapshot,
292 4
            $compare
293
        ));
294
    }
295
296
    /** {@inheritdoc} */
297 381
    public function getOwner()
298
    {
299 381
        return $this->owner;
300
    }
301
302
    /** {@inheritdoc} */
303 260
    public function getMapping()
304
    {
305 260
        return $this->mapping;
306
    }
307
308
    /** {@inheritdoc} */
309 5
    public function getTypeClass()
310
    {
311
        switch (true) {
312 5
            case ($this->dm === null):
313 1
                throw new MongoDBException('No DocumentManager is associated with this PersistentCollection, please set one using setDocumentManager method.');
314 4
            case (empty($this->mapping)):
315 1
                throw new MongoDBException('No mapping is associated with this PersistentCollection, please set one using setOwner method.');
316 3
            case (empty($this->mapping['targetDocument'])):
317 1
                throw new MongoDBException('Specifying targetDocument is required for the ClassMetadata to be obtained.');
318
            default:
319 2
                return $this->dm->getClassMetadata($this->mapping['targetDocument']);
320
        }
321
    }
322
323
    /** {@inheritdoc} */
324 243
    public function setInitialized($bool)
325
    {
326 243
        $this->initialized = $bool;
327 243
    }
328
329
    /** {@inheritdoc} */
330 18
    public function isInitialized()
331
    {
332 18
        return $this->initialized;
333
    }
334
335
    /** {@inheritdoc} */
336 9
    public function first()
337
    {
338 9
        $this->initialize();
339 9
        return $this->coll->first();
340
    }
341
342
    /** {@inheritdoc} */
343 2
    public function last()
344
    {
345 2
        $this->initialize();
346 2
        return $this->coll->last();
347
    }
348
349
    /**
350
     * {@inheritdoc}
351
     */
352 4
    public function remove($key)
353
    {
354 4
        return $this->doRemove($key, false);
355
    }
356
357
    /**
358
     * {@inheritdoc}
359
     */
360 17
    public function removeElement($element)
361
    {
362 17
        $this->initialize();
363 17
        $removed = $this->coll->removeElement($element);
364
365 17
        if ( ! $removed) {
366
            return $removed;
367
        }
368
369 17
        $this->changed();
370
371 17
        return $removed;
372
    }
373
374
    /**
375
     * {@inheritdoc}
376
     */
377
    public function containsKey($key)
378
    {
379
        $this->initialize();
380
        return $this->coll->containsKey($key);
381
    }
382
383
    /**
384
     * {@inheritdoc}
385
     */
386 2
    public function contains($element)
387
    {
388 2
        $this->initialize();
389 2
        return $this->coll->contains($element);
390
    }
391
392
    /**
393
     * {@inheritdoc}
394
     */
395
    public function exists(\Closure $p)
396
    {
397
        $this->initialize();
398
        return $this->coll->exists($p);
399
    }
400
401
    /**
402
     * {@inheritdoc}
403
     */
404 2
    public function indexOf($element)
405
    {
406 2
        $this->initialize();
407 2
        return $this->coll->indexOf($element);
408
    }
409
410
    /**
411
     * {@inheritdoc}
412
     */
413 18
    public function get($key)
414
    {
415 18
        $this->initialize();
416 18
        return $this->coll->get($key);
417
    }
418
419
    /**
420
     * {@inheritdoc}
421
     */
422
    public function getKeys()
423
    {
424
        $this->initialize();
425
        return $this->coll->getKeys();
426
    }
427
428
    /**
429
     * {@inheritdoc}
430
     */
431
    public function getValues()
432
    {
433
        $this->initialize();
434
        return $this->coll->getValues();
435
    }
436
437
    /**
438
     * {@inheritdoc}
439
     */
440 101
    public function count()
441
    {
442
        // Workaround around not being able to directly count inverse collections anymore
443 101
        $this->initialize();
444
445 101
        return $this->coll->count();
446
    }
447
448
    /**
449
     * {@inheritdoc}
450
     */
451 20
    public function set($key, $value)
452
    {
453 20
        return $this->doSet($key, $value, false);
454
    }
455
456
    /**
457
     * {@inheritdoc}
458
     */
459 159
    public function add($value)
460
    {
461 159
        return $this->doAdd($value, false);
462
    }
463
464
    /**
465
     * {@inheritdoc}
466
     */
467 355
    public function isEmpty()
468
    {
469 355
        return $this->initialized ? $this->coll->isEmpty() : $this->count() === 0;
470
    }
471
472
    /**
473
     * {@inheritdoc}
474
     */
475 302
    public function getIterator()
476
    {
477 302
        $this->initialize();
478 302
        return $this->coll->getIterator();
479
    }
480
481
    /**
482
     * {@inheritdoc}
483
     */
484 202
    public function map(\Closure $func)
485
    {
486 202
        $this->initialize();
487 202
        return $this->coll->map($func);
488
    }
489
490
    /**
491
     * {@inheritdoc}
492
     */
493
    public function filter(\Closure $p)
494
    {
495
        $this->initialize();
496
        return $this->coll->filter($p);
497
    }
498
499
    /**
500
     * {@inheritdoc}
501
     */
502
    public function forAll(\Closure $p)
503
    {
504
        $this->initialize();
505
        return $this->coll->forAll($p);
506
    }
507
508
    /**
509
     * {@inheritdoc}
510
     */
511
    public function partition(\Closure $p)
512
    {
513
        $this->initialize();
514
        return $this->coll->partition($p);
515
    }
516
517
    /**
518
     * {@inheritdoc}
519
     */
520 23
    public function toArray()
521
    {
522 23
        $this->initialize();
523 23
        return $this->coll->toArray();
524
    }
525
526
    /**
527
     * {@inheritdoc}
528
     */
529 24
    public function clear()
530
    {
531 24
        if ($this->initialized && $this->isEmpty()) {
532
            return;
533
        }
534
535 24
        if ($this->isOrphanRemovalEnabled()) {
536 24
            $this->initialize();
537 24
            foreach ($this->coll as $element) {
538 24
                $this->uow->scheduleOrphanRemoval($element);
539
            }
540
        }
541
542 24
        $this->mongoData = array();
543 24
        $this->coll->clear();
544
545
        // Nothing to do for inverse-side collections
546 24
        if ( ! $this->mapping['isOwningSide']) {
547
            return;
548
        }
549
550
        // Nothing to do if the collection was initialized but contained no data
551 24
        if ($this->initialized && empty($this->snapshot)) {
552 2
            return;
553
        }
554
555 22
        $this->changed();
556 22
        $this->uow->scheduleCollectionDeletion($this);
557 22
        $this->takeSnapshot();
558 22
    }
559
560
    /**
561
     * {@inheritdoc}
562
     */
563 1
    public function slice($offset, $length = null)
564
    {
565 1
        $this->initialize();
566 1
        return $this->coll->slice($offset, $length);
567
    }
568
569
    /**
570
     * Called by PHP when this collection is serialized. Ensures that only the
571
     * elements are properly serialized.
572
     *
573
     * @internal Tried to implement Serializable first but that did not work well
574
     *           with circular references. This solution seems simpler and works well.
575
     */
576 4
    public function __sleep()
577
    {
578 4
        return array('coll', 'initialized');
579
    }
580
581
    /* ArrayAccess implementation */
582
583
    /**
584
     * @see containsKey()
585
     */
586 1
    public function offsetExists($offset)
587
    {
588 1
        $this->initialize();
589 1
        return $this->coll->offsetExists($offset);
590
    }
591
592
    /**
593
     * @see get()
594
     */
595 66
    public function offsetGet($offset)
596
    {
597 66
        $this->initialize();
598 66
        return $this->coll->offsetGet($offset);
599
    }
600
601
    /**
602
     * @see add()
603
     * @see set()
604
     */
605 34
    public function offsetSet($offset, $value)
606
    {
607 34
        if ( ! isset($offset)) {
608 34
            return $this->doAdd($value, true);
609
        }
610
611 2
        return $this->doSet($offset, $value, true);
612
    }
613
614
    /**
615
     * @see remove()
616
     */
617 17
    public function offsetUnset($offset)
618
    {
619 17
        return $this->doRemove($offset, true);
620
    }
621
622
    public function key()
623
    {
624
        return $this->coll->key();
625
    }
626
627
    /**
628
     * Gets the element of the collection at the current iterator position.
629
     */
630 1
    public function current()
631
    {
632 1
        return $this->coll->current();
633
    }
634
635
    /**
636
     * Moves the internal iterator position to the next element.
637
     */
638
    public function next()
639
    {
640
        return $this->coll->next();
641
    }
642
643
    /**
644
     * {@inheritdoc}
645
     */
646 381
    public function unwrap()
647
    {
648 381
        return $this->coll;
649
    }
650
651
    /**
652
     * Cleanup internal state of cloned persistent collection.
653
     *
654
     * The following problems have to be prevented:
655
     * 1. Added documents are added to old PersistentCollection
656
     * 2. New collection is not dirty, if reused on other document nothing
657
     * changes.
658
     * 3. Snapshot leads to invalid diffs being generated.
659
     * 4. Lazy loading grabs entities from old owner object.
660
     * 5. New collection is connected to old owner and leads to duplicate keys.
661
     */
662 8
    public function __clone()
663
    {
664 8
        if (is_object($this->coll)) {
665 8
            $this->coll = clone $this->coll;
666
        }
667
668 8
        $this->initialize();
669
670 8
        $this->owner = null;
671 8
        $this->snapshot = array();
672
673 8
        $this->changed();
674 8
    }
675
676
    /**
677
     * Actual logic for adding an element to the collection.
678
     *
679
     * @param mixed $value
680
     * @param bool $arrayAccess
681
     * @return bool
682
     */
683 171
    private function doAdd($value, $arrayAccess)
684
    {
685
        /* Initialize the collection before calling add() so this append operation
686
         * uses the appropriate key. Otherwise, we risk overwriting original data
687
         * when $newObjects are re-added in a later call to initialize().
688
         */
689 171
        if (isset($this->mapping['strategy']) && CollectionHelper::isHash($this->mapping['strategy'])) {
690 9
            $this->initialize();
691
        }
692 171
        $arrayAccess ? $this->coll->offsetSet(null, $value) : $this->coll->add($value);
693 171
        $this->changed();
694
695 171 View Code Duplication
        if ($this->uow !== null && $this->isOrphanRemovalEnabled() && $value !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
696 93
            $this->uow->unscheduleOrphanRemoval($value);
697
        }
698
699 171
        return true;
700
    }
701
702
    /**
703
     * Actual logic for removing element by its key.
704
     *
705
     * @param mixed $offset
706
     * @param bool $arrayAccess
707
     * @return mixed|void
708
     */
709 21
    private function doRemove($offset, $arrayAccess)
710
    {
711 21
        $this->initialize();
712 21
        $removed = $arrayAccess ? $this->coll->offsetUnset($offset) : $this->coll->remove($offset);
713
714 21
        if ( ! $removed && ! $arrayAccess) {
715
            return $removed;
716
        }
717
718 21
        $this->changed();
719
720 21
        return $removed;
721
    }
722
723
    /**
724
     * Actual logic for setting an element in the collection.
725
     *
726
     * @param mixed $offset
727
     * @param mixed $value
728
     * @param bool $arrayAccess
729
     * @return bool
730
     */
731 21
    private function doSet($offset, $value, $arrayAccess)
732
    {
733 21
        $arrayAccess ? $this->coll->offsetSet($offset, $value) : $this->coll->set($offset, $value);
734
735
        // Handle orphanRemoval
736 21 View Code Duplication
        if ($this->uow !== null && $this->isOrphanRemovalEnabled() && $value !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
737 19
            $this->uow->unscheduleOrphanRemoval($value);
738
        }
739
740 21
        $this->changed();
741 21
    }
742
743
    /**
744
     * Returns whether or not this collection has orphan removal enabled.
745
     *
746
     * Embedded documents are automatically considered as "orphan removal enabled" because they might have references
747
     * that require to trigger cascade remove operations.
748
     *
749
     * @return boolean
750
     */
751 181
    private function isOrphanRemovalEnabled()
752
    {
753 181
        if ($this->mapping === null) {
754 11
            return false;
755
        }
756
757 170
        if (isset($this->mapping['embedded'])) {
758 94
            return true;
759
        }
760
761 86
        if (isset($this->mapping['reference']) && $this->mapping['isOwningSide'] && $this->mapping['orphanRemoval']) {
762 9
            return true;
763
        }
764
765 77
        return false;
766
    }
767
768
    /**
769
     * Checks whether collection owner needs to be scheduled for dirty change in case the collection is modified.
770
     *
771
     * @return bool
772
     */
773 188
    private function needsSchedulingForDirtyCheck()
774
    {
775 188
        return $this->owner && $this->dm && ! empty($this->mapping['isOwningSide'])
776 188
            && $this->dm->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify();
777
    }
778
}
779