Completed
Pull Request — master (#1331)
by Maciej
10:31
created

PersistentCollection::removeElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 13
Ratio 100 %

Code Coverage

Tests 6
CRAP Score 2.0117

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 13
loc 13
ccs 6
cts 7
cp 0.8571
rs 9.4286
cc 2
eloc 7
nc 2
nop 1
crap 2.0117
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;
21
22
use Doctrine\Common\Collections\Collection as BaseCollection;
23
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
24
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
25
26
/**
27
 * A PersistentCollection represents a collection of elements that have persistent state.
28
 *
29
 * @since       1.0
30
 * @author      Jonathan H. Wage <[email protected]>
31
 * @author      Roman Borschel <[email protected]>
32
 */
33
class PersistentCollection implements BaseCollection
34
{
35
    /**
36
     * A snapshot of the collection at the moment it was fetched from the database.
37
     * This is used to create a diff of the collection at commit time.
38
     *
39
     * @var array
40
     */
41
    private $snapshot = array();
42
43
    /**
44
     * Collection's owning entity
45
     *
46
     * @var object
47
     */
48
    private $owner;
49
50
    /**
51
     * @var array
52
     */
53
    private $mapping;
54
55
    /**
56
     * Whether the collection is dirty and needs to be synchronized with the database
57
     * when the UnitOfWork that manages its persistent state commits.
58
     *
59
     * @var boolean
60
     */
61
    private $isDirty = false;
62
63
    /**
64
     * Whether the collection has already been initialized.
65
     *
66
     * @var boolean
67
     */
68
    private $initialized = true;
69
70
    /**
71
     * The wrapped Collection instance.
72
     *
73
     * @var BaseCollection
74
     */
75
    private $coll;
76
77
    /**
78
     * The DocumentManager that manages the persistence of the collection.
79
     *
80
     * @var DocumentManager
81
     */
82
    private $dm;
83
84
    /**
85
     * The UnitOfWork that manages the persistence of the collection.
86
     *
87
     * @var UnitOfWork
88
     */
89
    private $uow;
90
91
    /**
92
     * The raw mongo data that will be used to initialize this collection.
93
     *
94
     * @var array
95
     */
96
    private $mongoData = array();
97
98
    /**
99
     * Any hints to account for during reconstitution/lookup of the documents.
100
     *
101
     * @var array
102
     */
103
    private $hints = array();
104
105
    /**
106
     * @var ClassMetadata
107
     */
108
    private $typeClass;
109
110
    /**
111
     * @param BaseCollection $coll
112
     * @param DocumentManager $dm
113
     * @param UnitOfWork $uow
114
     */
115 388
    public function __construct(BaseCollection $coll, DocumentManager $dm, UnitOfWork $uow)
116
    {
117 388
        $this->coll = $coll;
118 388
        $this->dm = $dm;
119 388
        $this->uow = $uow;
120 388
    }
121
122
    /**
123
     * Sets the document manager and unit of work (used during merge operations).
124
     *
125
     * @param DocumentManager $dm
126
     */
127
    public function setDocumentManager(DocumentManager $dm)
128
    {
129
        $this->dm = $dm;
130
        $this->uow = $dm->getUnitOfWork();
131
    }
132
133
    /**
134
     * Sets the array of raw mongo data that will be used to initialize this collection.
135
     *
136
     * @param array $mongoData
137
     */
138 145
    public function setMongoData(array $mongoData)
139
    {
140 145
        $this->mongoData = $mongoData;
141 145
    }
142
143
    /**
144
     * Gets the array of raw mongo data that will be used to initialize this collection.
145
     *
146
     * @return array $mongoData
147
     */
148 111
    public function getMongoData()
149
    {
150 111
        return $this->mongoData;
151
    }
152
153
    /**
154
     * Set hints to account for during reconstitution/lookup of the documents.
155
     *
156
     * @param array $hints
157
     */
158 224
    public function setHints(array $hints)
159
    {
160 224
        $this->hints = $hints;
161 224
    }
162
163
    /**
164
     * Get hints to account for during reconstitution/lookup of the documents.
165
     *
166
     * @return array $hints
167
     */
168 70
    public function getHints()
169
    {
170 70
        return $this->hints;
171
    }
172
173
    /**
174
     * Initializes the collection by loading its contents from the database
175
     * if the collection is not yet initialized.
176
     */
177 350
    public function initialize()
178
    {
179 350
        if ($this->initialized || ! $this->mapping) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->mapping of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
180 343
            return;
181
        }
182
183 123
        $newObjects = array();
184
185 123
        if ($this->isDirty) {
186
            // Remember any NEW objects added through add()
187 12
            $newObjects = $this->coll->toArray();
188 12
        }
189
190 123
        $this->initialized = true;
191
192 123
        $this->coll->clear();
193 123
        $this->uow->loadCollection($this);
194 123
        $this->takeSnapshot();
195
196 123
        $this->mongoData = array();
197
198
        // Reattach any NEW objects added through add()
199 123
        if ($newObjects) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $newObjects of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
200 12
            foreach ($newObjects as $key => $obj) {
201 12
                if (CollectionHelper::isHash($this->mapping['strategy'])) {
202
                    $this->coll->set($key, $obj);
203
                } else {
204 12
                    $this->coll->add($obj);
205
                }
206 12
            }
207
208 12
            $this->isDirty = true;
209 12
        }
210 123
    }
211
212
    /**
213
     * Marks this collection as changed/dirty.
214
     */
215 168
    private function changed()
216
    {
217 168
        if ($this->isDirty) {
218 90
            return;
219
        }
220
221 168
        $this->isDirty = true;
222
223 168
        if ($this->dm &&
224 168
            $this->mapping !== null &&
225 168
            $this->mapping['isOwningSide'] &&
226 168
            $this->owner &&
227 168
            $this->dm->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
228 1
            $this->uow->scheduleForDirtyCheck($this->owner);
229 1
        }
230 168
    }
231
232
    /**
233
     * Gets a boolean flag indicating whether this collection is dirty which means
234
     * its state needs to be synchronized with the database.
235
     *
236
     * @return boolean TRUE if the collection is dirty, FALSE otherwise.
237
     */
238 373
    public function isDirty()
239
    {
240 373
        return $this->isDirty;
241
    }
242
243
    /**
244
     * Sets a boolean flag, indicating whether this collection is dirty.
245
     *
246
     * @param boolean $dirty Whether the collection should be marked dirty or not.
247
     */
248 366
    public function setDirty($dirty)
249
    {
250 366
        $this->isDirty = $dirty;
251 366
    }
252
253
    /**
254
     * INTERNAL:
255
     * Sets the collection's owning entity together with the AssociationMapping that
256
     * describes the association between the owner and the elements of the collection.
257
     *
258
     * @param object $document
259
     * @param array $mapping
260
     */
261 382
    public function setOwner($document, array $mapping)
262
    {
263 382
        $this->owner = $document;
264 382
        $this->mapping = $mapping;
265
266 382
        if ( ! empty($this->mapping['targetDocument'])) {
267 368
            $this->typeClass = $this->dm->getClassMetadata($this->mapping['targetDocument']);
268 368
        }
269 382
    }
270
271
    /**
272
     * INTERNAL:
273
     * Tells this collection to take a snapshot of its current state reindexing
274
     * itself numerically if using save strategy that is enforcing BSON array.
275
     * Reindexing is safe as snapshot is taken only after synchronizing collection
276
     * with database or clearing it.
277
     */
278 228
    public function takeSnapshot()
279
    {
280 228
        if (CollectionHelper::isList($this->mapping['strategy'])) {
281 205
            $array = $this->coll->toArray();
282 205
            $this->coll->clear();
283 205
            foreach ($array as $document) {
284 198
                $this->coll->add($document);
285 205
            }
286 205
        }
287 228
        $this->snapshot = $this->coll->toArray();
288 228
        $this->isDirty = false;
289 228
    }
290
291
    /**
292
     * INTERNAL:
293
     * Clears the internal snapshot information and sets isDirty to true if the collection
294
     * has elements.
295
     */
296 6
    public function clearSnapshot()
297
    {
298 6
        $this->snapshot = array();
299 6
        $this->isDirty = $this->coll->count() ? true : false;
300 6
    }
301
302
    /**
303
     * INTERNAL:
304
     * Returns the last snapshot of the elements in the collection.
305
     *
306
     * @return array The last snapshot of the elements.
307
     */
308
    public function getSnapshot()
309
    {
310
        return $this->snapshot;
311
    }
312
313
    /**
314
     * INTERNAL:
315
     * getDeleteDiff
316
     *
317
     * @return array
318
     */
319 15 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...
320
    {
321 15
        return array_udiff_assoc(
322 15
            $this->snapshot,
323 15
            $this->coll->toArray(),
324
            function ($a, $b) { return $a === $b ? 0 : 1; }
325 15
        );
326
    }
327
328
    /**
329
     * INTERNAL: get objects that were removed, unlike getDeleteDiff this doesn't care about indices.
330
     *
331
     * @return array
332
     */
333 136
    public function getDeletedDocuments()
334
    {
335
        $compare = function ($a, $b) {
336 92
            $compareA = is_object($a) ? spl_object_hash($a) : $a;
337 92
            $compareb = is_object($b) ? spl_object_hash($b) : $b;
338 92
            return $compareA === $compareb ? 0 : ($compareA > $compareb ? 1 : -1);
339 136
        };
340
341 136
        return array_udiff(
342 136
            $this->snapshot,
343 136
            $this->coll->toArray(),
344
            $compare
345 136
        );
346
    }
347
348
    /**
349
     * INTERNAL:
350
     * getInsertDiff
351
     *
352
     * @return array
353
     */
354 16 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...
355
    {
356 16
        return array_udiff_assoc(
357 16
            $this->coll->toArray(),
358 16
            $this->snapshot,
359
            function ($a, $b) { return $a === $b ? 0 : 1; }
360 16
        );
361
    }
362
363
    /**
364
     * INTERNAL:
365
     * Gets the collection owner.
366
     *
367
     * @return object
368
     */
369 369
    public function getOwner()
370
    {
371 369
        return $this->owner;
372
    }
373
374
    /**
375
     * @return array
376
     */
377 240
    public function getMapping()
378
    {
379 240
        return $this->mapping;
380
    }
381
382
    /**
383
     * @return ClassMetadata
384
     * @throws MongoDBException
385
     */
386 2
    public function getTypeClass()
387
    {
388 2
        if (empty($this->typeClass)) {
389 1
            throw new MongoDBException('Specifying targetDocument is required for the ClassMetadata to be obtained.');
390
        }
391
392 1
        return $this->typeClass;
393
    }
394
395
    /**
396
     * Sets the initialized flag of the collection, forcing it into that state.
397
     *
398
     * @param boolean $bool
399
     */
400 225
    public function setInitialized($bool)
401
    {
402 225
        $this->initialized = $bool;
403 225
    }
404
405
    /**
406
     * Checks whether this collection has been initialized.
407
     *
408
     * @return boolean
409
     */
410 12
    public function isInitialized()
411
    {
412 12
        return $this->initialized;
413
    }
414
415
    /** {@inheritdoc} */
416 9
    public function first()
417
    {
418 9
        $this->initialize();
419 9
        return $this->coll->first();
420
    }
421
422
    /** {@inheritdoc} */
423
    public function last()
424
    {
425
        $this->initialize();
426
        return $this->coll->last();
427
    }
428
429
    /**
430
     * {@inheritdoc}
431
     */
432 16 View Code Duplication
    public function remove($key)
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...
433
    {
434 16
        $this->initialize();
435 16
        $removed = $this->coll->remove($key);
436
437 16
        if ( ! $removed) {
438
            return $removed;
439
        }
440
441 16
        $this->changed();
442
443 16
        return $removed;
444
    }
445
446
    /**
447
     * {@inheritdoc}
448
     */
449 12 View Code Duplication
    public function removeElement($element)
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...
450
    {
451 12
        $this->initialize();
452 12
        $removed = $this->coll->removeElement($element);
453
454 12
        if ( ! $removed) {
455
            return $removed;
456
        }
457
458 12
        $this->changed();
459
460 12
        return $removed;
461
    }
462
463
    /**
464
     * {@inheritdoc}
465
     */
466
    public function containsKey($key)
467
    {
468
        $this->initialize();
469
        return $this->coll->containsKey($key);
470
    }
471
472
    /**
473
     * {@inheritdoc}
474
     */
475
    public function contains($element)
476
    {
477
        $this->initialize();
478
        return $this->coll->contains($element);
479
    }
480
481
    /**
482
     * {@inheritdoc}
483
     */
484
    public function exists(\Closure $p)
485
    {
486
        $this->initialize();
487
        return $this->coll->exists($p);
488
    }
489
490
    /**
491
     * {@inheritdoc}
492
     */
493 2
    public function indexOf($element)
494
    {
495 2
        $this->initialize();
496 2
        return $this->coll->indexOf($element);
497
    }
498
499
    /**
500
     * {@inheritdoc}
501
     */
502 66
    public function get($key)
503
    {
504 66
        $this->initialize();
505 66
        return $this->coll->get($key);
506
    }
507
508
    /**
509
     * {@inheritdoc}
510
     */
511
    public function getKeys()
512
    {
513
        $this->initialize();
514
        return $this->coll->getKeys();
515
    }
516
517
    /**
518
     * {@inheritdoc}
519
     */
520
    public function getValues()
521
    {
522
        $this->initialize();
523
        return $this->coll->getValues();
524
    }
525
526
    /**
527
     * {@inheritdoc}
528
     */
529 353
    public function count()
530
    {
531 353
        $count = $this->coll->count();
532
533
        // If this collection is inversed and not initialized, add the count returned from the database
534 353
        if ($this->mapping['isInverseSide'] && ! $this->initialized) {
535 10
            $documentPersister = $this->uow->getDocumentPersister(get_class($this->owner));
536 10
            $count += empty($this->mapping['repositoryMethod'])
537 10
                ? $documentPersister->createReferenceManyInverseSideQuery($this)->count()
538 10
                : $documentPersister->createReferenceManyWithRepositoryMethodCursor($this)->count();
539 10
        }
540
541 353
        return count($this->mongoData) + $count;
542
    }
543
544
    /**
545
     * {@inheritdoc}
546
     */
547 31
    public function set($key, $value)
548
    {
549 31
        $this->coll->set($key, $value);
550
551
        // Handle orphanRemoval
552 31 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...
553 30
            $this->uow->unscheduleOrphanRemoval($value);
554 30
        }
555
556 31
        $this->changed();
557 31
    }
558
559
    /**
560
     * {@inheritdoc}
561
     */
562 143
    public function add($value)
563
    {
564
        /* Initialize the collection before calling add() so this append operation
565
         * uses the appropriate key. Otherwise, we risk overwriting original data
566
         * when $newObjects are re-added in a later call to initialize().
567
         */
568 143
        if (isset($this->mapping['strategy']) && CollectionHelper::isHash($this->mapping['strategy'])) {
569 11
            $this->initialize();
570 11
        }
571 143
        $this->coll->add($value);
572 143
        $this->changed();
573
574 143 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...
575 81
            $this->uow->unscheduleOrphanRemoval($value);
576 81
        }
577
578 143
        return true;
579
    }
580
581
    /**
582
     * {@inheritdoc}
583
     */
584 345
    public function isEmpty()
585
    {
586 345
        return $this->count() === 0;
587
    }
588
589
    /**
590
     * {@inheritdoc}
591
     */
592 300
    public function getIterator()
593
    {
594 300
        $this->initialize();
595 300
        return $this->coll->getIterator();
596
    }
597
598
    /**
599
     * {@inheritdoc}
600
     */
601 199
    public function map(\Closure $func)
602
    {
603 199
        $this->initialize();
604 199
        return $this->coll->map($func);
605
    }
606
607
    /**
608
     * {@inheritdoc}
609
     */
610
    public function filter(\Closure $p)
611
    {
612
        $this->initialize();
613
        return $this->coll->filter($p);
614
    }
615
616
    /**
617
     * {@inheritdoc}
618
     */
619
    public function forAll(\Closure $p)
620
    {
621
        $this->initialize();
622
        return $this->coll->forAll($p);
623
    }
624
625
    /**
626
     * {@inheritdoc}
627
     */
628
    public function partition(\Closure $p)
629
    {
630
        $this->initialize();
631
        return $this->coll->partition($p);
632
    }
633
634
    /**
635
     * {@inheritdoc}
636
     */
637 18
    public function toArray()
638
    {
639 18
        $this->initialize();
640 18
        return $this->coll->toArray();
641
    }
642
643
    /**
644
     * {@inheritdoc}
645
     */
646 16
    public function clear()
647
    {
648 16
        if ($this->initialized && $this->isEmpty()) {
649
            return;
650
        }
651
652 16
        if ($this->isOrphanRemovalEnabled()) {
653 16
            foreach ($this->coll as $element) {
654 15
                $this->uow->scheduleOrphanRemoval($element);
655 16
            }
656 16
        }
657
658 16
        $this->mongoData = array();
659 16
        $this->coll->clear();
660
661
        // Nothing to do for inverse-side collections
662 16
        if ( ! $this->mapping['isOwningSide']) {
663
            return;
664
        }
665
666
        // Nothing to do if the collection was initialized but contained no data
667 16
        if ($this->initialized && empty($this->snapshot)) {
668 2
            return;
669
        }
670
671 14
        $this->changed();
672 14
        $this->uow->scheduleCollectionDeletion($this);
673 14
        $this->takeSnapshot();
674 14
    }
675
676
    /**
677
     * {@inheritdoc}
678
     */
679 1
    public function slice($offset, $length = null)
680
    {
681 1
        $this->initialize();
682 1
        return $this->coll->slice($offset, $length);
683
    }
684
685
    /**
686
     * Called by PHP when this collection is serialized. Ensures that only the
687
     * elements are properly serialized.
688
     *
689
     * @internal Tried to implement Serializable first but that did not work well
690
     *           with circular references. This solution seems simpler and works well.
691
     */
692 1
    public function __sleep()
693
    {
694 1
        return array('coll', 'initialized');
695
    }
696
697
    /* ArrayAccess implementation */
698
699
    /**
700
     * @see containsKey()
701
     */
702
    public function offsetExists($offset)
703
    {
704
        return $this->containsKey($offset);
705
    }
706
707
    /**
708
     * @see get()
709
     */
710 57
    public function offsetGet($offset)
711
    {
712 57
        return $this->get($offset);
713
    }
714
715
    /**
716
     * @see add()
717
     * @see set()
718
     */
719 35
    public function offsetSet($offset, $value)
720
    {
721 35
        if ( ! isset($offset)) {
722 34
            return $this->add($value);
723
        }
724
725 1
        return $this->set($offset, $value);
726
    }
727
728
    /**
729
     * @see remove()
730
     */
731 13
    public function offsetUnset($offset)
732
    {
733 13
        return $this->remove($offset);
734
    }
735
736
    public function key()
737
    {
738
        return $this->coll->key();
739
    }
740
741
    /**
742
     * Gets the element of the collection at the current iterator position.
743
     */
744 1
    public function current()
745
    {
746 1
        return $this->coll->current();
747
    }
748
749
    /**
750
     * Moves the internal iterator position to the next element.
751
     */
752
    public function next()
753
    {
754
        return $this->coll->next();
755
    }
756
757
    /**
758
     * Retrieves the wrapped Collection instance.
759
     */
760 373
    public function unwrap()
761
    {
762 373
        return $this->coll;
763
    }
764
765
    /**
766
     * Cleanup internal state of cloned persistent collection.
767
     *
768
     * The following problems have to be prevented:
769
     * 1. Added documents are added to old PersistentCollection
770
     * 2. New collection is not dirty, if reused on other document nothing
771
     * changes.
772
     * 3. Snapshot leads to invalid diffs being generated.
773
     * 4. Lazy loading grabs entities from old owner object.
774
     * 5. New collection is connected to old owner and leads to duplicate keys.
775
     */
776 8
    public function __clone()
777
    {
778 8
        if (is_object($this->coll)) {
779 8
            $this->coll = clone $this->coll;
780 8
        }
781
782 8
        $this->initialize();
783
784 8
        $this->owner = null;
785 8
        $this->snapshot = array();
786
787 8
        $this->changed();
788 8
    }
789
790
    /**
791
     * Returns whether or not this collection has orphan removal enabled.
792
     *
793
     * Embedded documents are automatically considered as "orphan removal enabled" because they might have references
794
     * that require to trigger cascade remove operations.
795
     *
796
     * @return boolean
797
     */
798 161
    private function isOrphanRemovalEnabled()
799
    {
800 161
        if ($this->mapping === null) {
801 5
            return false;
802
        }
803
804 156
        if (isset($this->mapping['embedded'])) {
805 91
            return true;
806
        }
807
808 69
        if (isset($this->mapping['reference']) && $this->mapping['isOwningSide'] && $this->mapping['orphanRemoval']) {
809 7
            return true;
810
        }
811
812 62
        return false;
813
    }
814
}
815