Completed
Pull Request — master (#6110)
by Steevan
90:40 queued 75:55
created

PersistentCollection::setInitialized()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
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\ORM;
21
22
use Doctrine\Common\Collections\AbstractLazyCollection;
23
use Doctrine\Common\Collections\Collection;
24
use Doctrine\Common\Collections\ArrayCollection;
25
use Doctrine\Common\Collections\Selectable;
26
use Doctrine\Common\Collections\Criteria;
27
use Doctrine\ORM\Mapping\ClassMetadata;
28
29
/**
30
 * A PersistentCollection represents a collection of elements that have persistent state.
31
 *
32
 * Collections of entities represent only the associations (links) to those entities.
33
 * That means, if the collection is part of a many-many mapping and you remove
34
 * entities from the collection, only the links in the relation table are removed (on flush).
35
 * Similarly, if you remove entities from a collection that is part of a one-many
36
 * mapping this will only result in the nulling out of the foreign keys on flush.
37
 *
38
 * @since     2.0
39
 * @author    Konsta Vesterinen <[email protected]>
40
 * @author    Roman Borschel <[email protected]>
41
 * @author    Giorgio Sironi <[email protected]>
42
 * @author    Stefano Rodriguez <[email protected]>
43
 */
44
final class PersistentCollection extends AbstractLazyCollection implements Selectable
45
{
46
    /**
47
     * A snapshot of the collection at the moment it was fetched from the database.
48
     * This is used to create a diff of the collection at commit time.
49
     *
50
     * @var array
51
     */
52
    private $snapshot = array();
53
54
    /**
55
     * The entity that owns this collection.
56
     *
57
     * @var object
58
     */
59
    private $owner;
60
61
    /**
62
     * The association mapping the collection belongs to.
63
     * This is currently either a OneToManyMapping or a ManyToManyMapping.
64
     *
65
     * @var array
66
     */
67
    private $association;
68
69
    /**
70
     * The EntityManager that manages the persistence of the collection.
71
     *
72
     * @var \Doctrine\ORM\EntityManagerInterface
73
     */
74
    private $em;
75
76
    /**
77
     * The name of the field on the target entities that points to the owner
78
     * of the collection. This is only set if the association is bi-directional.
79
     *
80
     * @var string
81
     */
82
    private $backRefFieldName;
83
84
    /**
85
     * The class descriptor of the collection's entity type.
86
     *
87
     * @var ClassMetadata
88
     */
89
    private $typeClass;
90
91
    /**
92
     * Whether the collection is dirty and needs to be synchronized with the database
93
     * when the UnitOfWork that manages its persistent state commits.
94
     *
95
     * @var boolean
96
     */
97
    private $isDirty = false;
98
99
    /**
100
     * Creates a new persistent collection.
101
     *
102
     * @param EntityManagerInterface $em         The EntityManager the collection will be associated with.
103
     * @param ClassMetadata          $class      The class descriptor of the entity type of this collection.
104
     * @param Collection             $collection The collection elements.
105
     */
106 871
    public function __construct(EntityManagerInterface $em, $class, Collection $collection)
107
    {
108 871
        $this->collection  = $collection;
109 871
        $this->em          = $em;
110 871
        $this->typeClass   = $class;
111 871
        $this->initialized = true;
112 871
    }
113
114
    /**
115
     * INTERNAL:
116
     * Sets the collection's owning entity together with the AssociationMapping that
117
     * describes the association between the owner and the elements of the collection.
118
     *
119
     * @param object $entity
120
     * @param array  $assoc
121
     *
122
     * @return void
123
     */
124 864
    public function setOwner($entity, array $assoc)
125
    {
126 864
        $this->owner            = $entity;
127 864
        $this->association      = $assoc;
128 864
        $this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy'];
129 864
    }
130
131
    /**
132
     * INTERNAL:
133
     * Gets the collection owner.
134
     *
135
     * @return object
136
     */
137 522
    public function getOwner()
138
    {
139 522
        return $this->owner;
140
    }
141
142
    /**
143
     * @return Mapping\ClassMetadata
144
     */
145 21
    public function getTypeClass()
146
    {
147 21
        return $this->typeClass;
148
    }
149
150
    /**
151
     * INTERNAL:
152
     * Adds an element to a collection during hydration. This will automatically
153
     * complete bidirectional associations in the case of a one-to-many association.
154
     *
155
     * @param mixed $element The element to add.
156
     *
157
     * @return void
158
     */
159 154
    public function hydrateAdd($element)
160
    {
161 154
        $this->collection->add($element);
162
163
        // If _backRefFieldName is set and its a one-to-many association,
164
        // we need to set the back reference.
165 154
        if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
166
            // Set back reference to owner
167 98
            $this->typeClass->reflFields[$this->backRefFieldName]->setValue(
168 98
                $element, $this->owner
169
            );
170
171 98
            $this->em->getUnitOfWork()->setOriginalEntityProperty(
172 98
                spl_object_hash($element), $this->backRefFieldName, $this->owner
173
            );
174
        }
175 154
    }
176
177
    /**
178
     * INTERNAL:
179
     * Sets a keyed element in the collection during hydration.
180
     *
181
     * @param mixed $key     The key to set.
182
     * @param mixed $element The element to set.
183
     *
184
     * @return void
185
     */
186 38
    public function hydrateSet($key, $element)
187
    {
188 38
        $this->collection->set($key, $element);
189
190
        // If _backRefFieldName is set, then the association is bidirectional
191
        // and we need to set the back reference.
192 38
        if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
193
            // Set back reference to owner
194 22
            $this->typeClass->reflFields[$this->backRefFieldName]->setValue(
195 22
                $element, $this->owner
196
            );
197
        }
198 38
    }
199
200
    /**
201
     * Initializes the collection by loading its contents from the database
202
     * if the collection is not yet initialized.
203
     *
204
     * @return void
205
     */
206 749
    public function initialize()
207
    {
208 749
        if ($this->initialized || ! $this->association) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->association 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...
209 727
            return;
210
        }
211
212 140
        $this->doInitialize();
213
214 140
        $this->initialized = true;
215 140
    }
216
217
    /**
218
     * INTERNAL:
219
     * Tells this collection to take a snapshot of its current state.
220
     *
221
     * @return void
222
     */
223 577
    public function takeSnapshot()
224
    {
225 577
        $this->snapshot = $this->collection->toArray();
226 577
        $this->isDirty  = false;
227 577
    }
228
229
    /**
230
     * INTERNAL:
231
     * Returns the last snapshot of the elements in the collection.
232
     *
233
     * @return array The last snapshot of the elements.
234
     */
235 22
    public function getSnapshot()
236
    {
237 22
        return $this->snapshot;
238
    }
239
240
    /**
241
     * INTERNAL:
242
     * getDeleteDiff
243
     *
244
     * @return array
245
     */
246 328
    public function getDeleteDiff()
247
    {
248 328
        return array_udiff_assoc(
249 328
            $this->snapshot,
250 328
            $this->collection->toArray(),
251
            function($a, $b) { return $a === $b ? 0 : 1; }
252
        );
253
    }
254
255
    /**
256
     * INTERNAL:
257
     * getInsertDiff
258
     *
259
     * @return array
260
     */
261 328
    public function getInsertDiff()
262
    {
263 328
        return array_udiff_assoc(
264 328
            $this->collection->toArray(),
265 328
            $this->snapshot,
266
            function($a, $b) { return $a === $b ? 0 : 1; }
267
        );
268
    }
269
270
    /**
271
     * INTERNAL: Gets the association mapping of the collection.
272
     *
273
     * @return array
274
     */
275 548
    public function getMapping()
276
    {
277 548
        return $this->association;
278
    }
279
280
    /**
281
     * Marks this collection as changed/dirty.
282
     *
283
     * @return void
284
     */
285 146
    private function changed()
286
    {
287 146
        if ($this->isDirty) {
288 73
            return;
289
        }
290
291 146
        $this->isDirty = true;
292
293 146
        if ($this->association !== null &&
294 146
            $this->association['isOwningSide'] &&
295 146
            $this->association['type'] === ClassMetadata::MANY_TO_MANY &&
296 146
            $this->owner &&
297 146
            $this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
298 1
            $this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
299
        }
300 146
    }
301
302
    /**
303
     * Gets a boolean flag indicating whether this collection is dirty which means
304
     * its state needs to be synchronized with the database.
305
     *
306
     * @return boolean TRUE if the collection is dirty, FALSE otherwise.
307
     */
308 787
    public function isDirty()
309
    {
310 787
        return $this->isDirty;
311
    }
312
313
    /**
314
     * Sets a boolean flag, indicating whether this collection is dirty.
315
     *
316
     * @param boolean $dirty Whether the collection should be marked dirty or not.
317
     *
318
     * @return void
319
     */
320 778
    public function setDirty($dirty)
321
    {
322 778
        $this->isDirty = $dirty;
323 778
    }
324
325
    /**
326
     * Sets the initialized flag of the collection, forcing it into that state.
327
     *
328
     * @param boolean $bool
329
     *
330
     * @return void
331
     */
332 528
    public function setInitialized($bool)
333
    {
334 528
        $this->initialized = $bool;
335 528
    }
336
337
    /**
338
     * {@inheritdoc}
339
     */
340 16
    public function remove($key)
341
    {
342
        // TODO: If the keys are persistent as well (not yet implemented)
343
        //       and the collection is not initialized and orphanRemoval is
344
        //       not used we can issue a straight SQL delete/update on the
345
        //       association (table). Without initializing the collection.
346 16
        $removed = parent::remove($key);
347
348 16
        if ( ! $removed) {
349
            return $removed;
350
        }
351
352 16
        $this->changed();
353
354 16
        if ($this->association !== null &&
355 16
            $this->association['type'] & ClassMetadata::TO_MANY &&
356 16
            $this->owner &&
357 16
            $this->association['orphanRemoval']) {
358 4
            $this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
359
        }
360
361 16
        return $removed;
362
    }
363
364
    /**
365
     * {@inheritdoc}
366
     */
367 25
    public function removeElement($element)
368
    {
369 25
        if ( ! $this->initialized && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY) {
370 13
            if ($this->collection->contains($element)) {
371
                return $this->collection->removeElement($element);
372
            }
373
374 13
            $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
375
376 13
            if ($persister->removeElement($this, $element)) {
377 4
                return $element;
378
            }
379
380 11
            return null;
381
        }
382
383 12
        $removed = parent::removeElement($element);
384
385 12
        if ( ! $removed) {
386
            return $removed;
387
        }
388
389 12
        $this->changed();
390
391 12
        if ($this->association !== null &&
392 12
            $this->association['type'] & ClassMetadata::TO_MANY &&
393 12
            $this->owner &&
394 12
            $this->association['orphanRemoval']) {
395 4
            $this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
396
        }
397
398 12
        return $removed;
399
    }
400
401
    /**
402
     * {@inheritdoc}
403
     */
404 28
    public function containsKey($key)
405
    {
406 28
        if (! $this->initialized && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY
407 28
            && isset($this->association['indexBy'])) {
408 11
            $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
409
410 11
            return $this->collection->containsKey($key) || $persister->containsKey($this, $key);
411
        }
412
413 17
        return parent::containsKey($key);
414
    }
415
416
    /**
417
     * {@inheritdoc}
418
     */
419 33
    public function contains($element)
420
    {
421 33
        if ( ! $this->initialized && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY) {
422 17
            $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
423
424 17
            return $this->collection->contains($element) || $persister->contains($this, $element);
425
        }
426
427 16
        return parent::contains($element);
428
    }
429
430
    /**
431
     * {@inheritdoc}
432
     */
433 86
    public function get($key)
434
    {
435 86
        if ( ! $this->initialized
436 86
            && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY
437 86
            && isset($this->association['indexBy'])
438
        ) {
439 5
            if (!$this->typeClass->isIdentifierComposite && $this->typeClass->isIdentifier($this->association['indexBy'])) {
440 1
                return $this->em->find($this->typeClass->name, $key);
441
            }
442
443 4
            return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key);
444
        }
445
446 81
        return parent::get($key);
447
    }
448
449
    /**
450
     * {@inheritdoc}
451
     */
452 724
    public function count()
453
    {
454 724
        if ( ! $this->initialized && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY) {
455 32
            $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
456
457 32
            return $persister->count($this) + ($this->isDirty ? $this->collection->count() : 0);
458
        }
459
460 718
        return parent::count();
461
    }
462
463
    /**
464
     * {@inheritdoc}
465
     */
466 4
    public function set($key, $value)
467
    {
468 4
        parent::set($key, $value);
469
470 4
        $this->changed();
471
472 4
        if (is_object($value) && $this->em) {
473 4
            $this->em->getUnitOfWork()->cancelOrphanRemoval($value);
474
        }
475 4
    }
476
477
    /**
478
     * {@inheritdoc}
479
     */
480 110
    public function add($value)
481
    {
482 110
        $this->collection->add($value);
483
484 110
        $this->changed();
485
486 110
        if (is_object($value) && $this->em) {
487 108
            $this->em->getUnitOfWork()->cancelOrphanRemoval($value);
488
        }
489
490 110
        return true;
491
    }
492
493
    /* ArrayAccess implementation */
494
495
    /**
496
     * {@inheritdoc}
497
     */
498 17
    public function offsetExists($offset)
499
    {
500 17
        return $this->containsKey($offset);
501
    }
502
503
    /**
504
     * {@inheritdoc}
505
     */
506 62
    public function offsetGet($offset)
507
    {
508 62
        return $this->get($offset);
509
    }
510
511
    /**
512
     * {@inheritdoc}
513
     */
514 94
    public function offsetSet($offset, $value)
515
    {
516 94
        if ( ! isset($offset)) {
517 94
            return $this->add($value);
518
        }
519
520
        return $this->set($offset, $value);
521
    }
522
523
    /**
524
     * {@inheritdoc}
525
     */
526 6
    public function offsetUnset($offset)
527
    {
528 6
        return $this->remove($offset);
529
    }
530
531
    /**
532
     * {@inheritdoc}
533
     */
534 779
    public function isEmpty()
535
    {
536 779
        return $this->collection->isEmpty() && $this->count() === 0;
537
    }
538
539
    /**
540
     * {@inheritdoc}
541
     */
542 20
    public function clear()
543
    {
544 20
        if ($this->initialized && $this->isEmpty()) {
545 1
            $this->collection->clear();
546
            
547 1
            return;
548
        }
549
550 20
        $uow = $this->em->getUnitOfWork();
551
552 20
        if ($this->association['type'] & ClassMetadata::TO_MANY &&
553 20
            $this->association['orphanRemoval'] &&
554 20
            $this->owner) {
555
            // we need to initialize here, as orphan removal acts like implicit cascadeRemove,
556
            // hence for event listeners we need the objects in memory.
557 6
            $this->initialize();
558
559 6
            foreach ($this->collection as $element) {
560 6
                $uow->scheduleOrphanRemoval($element);
561
            }
562
        }
563
564 20
        $this->collection->clear();
565
566 20
        $this->initialized = true; // direct call, {@link initialize()} is too expensive
567
568 20
        if ($this->association['isOwningSide'] && $this->owner) {
569 14
            $this->changed();
570
571 14
            $uow->scheduleCollectionDeletion($this);
572
573 14
            $this->takeSnapshot();
574
        }
575 20
    }
576
577
    /**
578
     * Called by PHP when this collection is serialized. Ensures that only the
579
     * elements are properly serialized.
580
     *
581
     * Internal note: Tried to implement Serializable first but that did not work well
582
     *                with circular references. This solution seems simpler and works well.
583
     *
584
     * @return array
585
     */
586 2
    public function __sleep()
587
    {
588 2
        return array('collection', 'initialized');
589
    }
590
591
    /**
592
     * Extracts a slice of $length elements starting at position $offset from the Collection.
593
     *
594
     * If $length is null it returns all elements from $offset to the end of the Collection.
595
     * Keys have to be preserved by this method. Calling this method will only return the
596
     * selected slice and NOT change the elements contained in the collection slice is called on.
597
     *
598
     * @param int      $offset
599
     * @param int|null $length
600
     *
601
     * @return array
602
     */
603 15
    public function slice($offset, $length = null)
604
    {
605 15
        if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY) {
606 13
            $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
607
608 13
            return $persister->slice($this, $offset, $length);
609
        }
610
611 2
        return parent::slice($offset, $length);
612
    }
613
614
    /**
615
     * Cleans up internal state of cloned persistent collection.
616
     *
617
     * The following problems have to be prevented:
618
     * 1. Added entities are added to old PC
619
     * 2. New collection is not dirty, if reused on other entity nothing
620
     * changes.
621
     * 3. Snapshot leads to invalid diffs being generated.
622
     * 4. Lazy loading grabs entities from old owner object.
623
     * 5. New collection is connected to old owner and leads to duplicate keys.
624
     *
625
     * @return void
626
     */
627 11
    public function __clone()
628
    {
629 11
        if (is_object($this->collection)) {
630 11
            $this->collection = clone $this->collection;
631
        }
632
633 11
        $this->initialize();
634
635 11
        $this->owner    = null;
636 11
        $this->snapshot = array();
637
638 11
        $this->changed();
639 11
    }
640
641
    /**
642
     * Selects all elements from a selectable that match the expression and
643
     * return a new collection containing these elements.
644
     *
645
     * @param \Doctrine\Common\Collections\Criteria $criteria
646
     *
647
     * @return Collection
648
     *
649
     * @throws \RuntimeException
650
     */
651 15
    public function matching(Criteria $criteria)
652
    {
653 15
        if ($this->isDirty) {
654 3
            $this->initialize();
655
        }
656
657 15
        if ($this->initialized) {
658 3
            return $this->collection->matching($criteria);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Common\Collections\Collection as the method matching() does only exist in the following implementations of said interface: Doctrine\Common\Collections\ArrayCollection, Doctrine\ORM\LazyCriteriaCollection, Doctrine\ORM\PersistentCollection.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
659
        }
660
661 12
        if ($this->association['type'] === ClassMetadata::MANY_TO_MANY) {
662 7
            $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
663
664 7
            return new ArrayCollection($persister->loadCriteria($this, $criteria));
665
        }
666
667 5
        $builder         = Criteria::expr();
668 5
        $ownerExpression = $builder->eq($this->backRefFieldName, $this->owner);
669 5
        $expression      = $criteria->getWhereExpression();
670 5
        $expression      = $expression ? $builder->andX($expression, $ownerExpression) : $ownerExpression;
671
672 5
        $criteria = clone $criteria;
673 5
        $criteria->where($expression);
674
675 5
        $persister = $this->em->getUnitOfWork()->getEntityPersister($this->association['targetEntity']);
676
677 5
        return ($this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY)
678 2
            ? new LazyCriteriaCollection($persister, $criteria)
679 5
            : new ArrayCollection($persister->loadCriteria($criteria));
680
    }
681
682
    /**
683
     * Retrieves the wrapped Collection instance.
684
     *
685
     * @return \Doctrine\Common\Collections\Collection
686
     */
687 780
    public function unwrap()
688
    {
689 780
        return $this->collection;
690
    }
691
692
    /**
693
     * {@inheritdoc}
694
     */
695 140
    protected function doInitialize()
696
    {
697
        // Has NEW objects added through add(). Remember them.
698 140
        $newObjects = array();
699
700 140
        if ($this->isDirty) {
701 13
            $newObjects = $this->collection->toArray();
702
        }
703
704 140
        $this->collection->clear();
705 140
        $this->em->getUnitOfWork()->loadCollection($this);
706 140
        $this->takeSnapshot();
707
708
        // Reattach NEW objects added through add(), if any.
709 140
        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...
710 13
            foreach ($newObjects as $obj) {
711 13
                $this->collection->add($obj);
712
            }
713
714 13
            $this->isDirty = true;
715
        }
716 140
    }
717
}
718