Completed
Pull Request — master (#6152)
by Luís
10:24
created

UnitOfWork::getScheduledCollectionDeletions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
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\ArrayCollection;
23
use Doctrine\Common\Collections\Collection;
24
use Doctrine\Common\NotifyPropertyChanged;
25
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
26
use Doctrine\Common\Persistence\ObjectManagerAware;
27
use Doctrine\Common\PropertyChangedListener;
28
use Doctrine\DBAL\LockMode;
29
use Doctrine\ORM\Cache\Persister\CachedPersister;
30
use Doctrine\ORM\Event\LifecycleEventArgs;
31
use Doctrine\ORM\Event\ListenersInvoker;
32
use Doctrine\ORM\Event\OnFlushEventArgs;
33
use Doctrine\ORM\Event\PostFlushEventArgs;
34
use Doctrine\ORM\Event\PreFlushEventArgs;
35
use Doctrine\ORM\Event\PreUpdateEventArgs;
36
use Doctrine\ORM\Internal\HydrationCompleteHandler;
37
use Doctrine\ORM\Mapping\ClassMetadata;
38
use Doctrine\ORM\Mapping\Reflection\ReflectionPropertiesGetter;
39
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
40
use Doctrine\ORM\Persisters\Collection\OneToManyPersister;
41
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
42
use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
43
use Doctrine\ORM\Persisters\Entity\SingleTablePersister;
44
use Doctrine\ORM\Proxy\Proxy;
45
use Doctrine\ORM\Utility\IdentifierFlattener;
46
use Exception;
47
use InvalidArgumentException;
48
use UnexpectedValueException;
49
50
/**
51
 * The UnitOfWork is responsible for tracking changes to objects during an
52
 * "object-level" transaction and for writing out changes to the database
53
 * in the correct order.
54
 *
55
 * Internal note: This class contains highly performance-sensitive code.
56
 *
57
 * @since       2.0
58
 * @author      Benjamin Eberlei <[email protected]>
59
 * @author      Guilherme Blanco <[email protected]>
60
 * @author      Jonathan Wage <[email protected]>
61
 * @author      Roman Borschel <[email protected]>
62
 * @author      Rob Caiger <[email protected]>
63
 */
64
class UnitOfWork implements PropertyChangedListener
65
{
66
    /**
67
     * An entity is in MANAGED state when its persistence is managed by an EntityManager.
68
     */
69
    const STATE_MANAGED = 1;
70
71
    /**
72
     * An entity is new if it has just been instantiated (i.e. using the "new" operator)
73
     * and is not (yet) managed by an EntityManager.
74
     */
75
    const STATE_NEW = 2;
76
77
    /**
78
     * A detached entity is an instance with persistent state and identity that is not
79
     * (or no longer) associated with an EntityManager (and a UnitOfWork).
80
     */
81
    const STATE_DETACHED = 3;
82
83
    /**
84
     * A removed entity instance is an instance with a persistent identity,
85
     * associated with an EntityManager, whose persistent state will be deleted
86
     * on commit.
87
     */
88
    const STATE_REMOVED = 4;
89
90
    /**
91
     * Hint used to collect all primary keys of associated entities during hydration
92
     * and execute it in a dedicated query afterwards
93
     * @see https://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html?highlight=eager#temporarily-change-fetch-mode-in-dql
94
     */
95
    const HINT_DEFEREAGERLOAD = 'deferEagerLoad';
96
97
    /**
98
     * The identity map that holds references to all managed entities that have
99
     * an identity. The entities are grouped by their class name.
100
     * Since all classes in a hierarchy must share the same identifier set,
101
     * we always take the root class name of the hierarchy.
102
     *
103
     * @var array
104
     */
105
    private $identityMap = array();
106
107
    /**
108
     * Map of all identifiers of managed entities.
109
     * Keys are object ids (spl_object_hash).
110
     *
111
     * @var array
112
     */
113
    private $entityIdentifiers = array();
114
115
    /**
116
     * Map of the original entity data of managed entities.
117
     * Keys are object ids (spl_object_hash). This is used for calculating changesets
118
     * at commit time.
119
     *
120
     * Internal note: Note that PHPs "copy-on-write" behavior helps a lot with memory usage.
121
     *                A value will only really be copied if the value in the entity is modified
122
     *                by the user.
123
     *
124
     * @var array
125
     */
126
    private $originalEntityData = array();
127
128
    /**
129
     * Map of entity changes. Keys are object ids (spl_object_hash).
130
     * Filled at the beginning of a commit of the UnitOfWork and cleaned at the end.
131
     *
132
     * @var array
133
     */
134
    private $entityChangeSets = array();
135
136
    /**
137
     * The (cached) states of any known entities.
138
     * Keys are object ids (spl_object_hash).
139
     *
140
     * @var array
141
     */
142
    private $entityStates = array();
143
144
    /**
145
     * Map of entities that are scheduled for dirty checking at commit time.
146
     * This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT.
147
     * Keys are object ids (spl_object_hash).
148
     *
149
     * @var array
150
     */
151
    private $scheduledForSynchronization = array();
152
153
    /**
154
     * A list of all pending entity insertions.
155
     *
156
     * @var array
157
     */
158
    private $entityInsertions = array();
159
160
    /**
161
     * A list of all pending entity updates.
162
     *
163
     * @var array
164
     */
165
    private $entityUpdates = array();
166
167
    /**
168
     * Any pending extra updates that have been scheduled by persisters.
169
     *
170
     * @var array
171
     */
172
    private $extraUpdates = array();
173
174
    /**
175
     * A list of all pending entity deletions.
176
     *
177
     * @var array
178
     */
179
    private $entityDeletions = array();
180
181
    /**
182
     * All pending collection deletions.
183
     *
184
     * @var array
185
     */
186
    private $collectionDeletions = array();
187
188
    /**
189
     * All pending collection updates.
190
     *
191
     * @var array
192
     */
193
    private $collectionUpdates = array();
194
195
    /**
196
     * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork.
197
     * At the end of the UnitOfWork all these collections will make new snapshots
198
     * of their data.
199
     *
200
     * @var array
201
     */
202
    private $visitedCollections = array();
203
204
    /**
205
     * The EntityManager that "owns" this UnitOfWork instance.
206
     *
207
     * @var EntityManagerInterface
208
     */
209
    private $em;
210
211
    /**
212
     * The entity persister instances used to persist entity instances.
213
     *
214
     * @var array
215
     */
216
    private $persisters = array();
217
218
    /**
219
     * The collection persister instances used to persist collections.
220
     *
221
     * @var array
222
     */
223
    private $collectionPersisters = array();
224
225
    /**
226
     * The EventManager used for dispatching events.
227
     *
228
     * @var \Doctrine\Common\EventManager
229
     */
230
    private $evm;
231
232
    /**
233
     * The ListenersInvoker used for dispatching events.
234
     *
235
     * @var \Doctrine\ORM\Event\ListenersInvoker
236
     */
237
    private $listenersInvoker;
238
239
    /**
240
     * The IdentifierFlattener used for manipulating identifiers
241
     *
242
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
243
     */
244
    private $identifierFlattener;
245
246
    /**
247
     * Orphaned entities that are scheduled for removal.
248
     *
249
     * @var array
250
     */
251
    private $orphanRemovals = array();
252
253
    /**
254
     * Read-Only objects are never evaluated
255
     *
256
     * @var array
257
     */
258
    private $readOnlyObjects = array();
259
260
    /**
261
     * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
262
     *
263
     * @var array
264
     */
265
    private $eagerLoadingEntities = array();
266
267
    /**
268
     * @var boolean
269
     */
270
    protected $hasCache = false;
271
272
    /**
273
     * Helper for handling completion of hydration
274
     *
275
     * @var HydrationCompleteHandler
276
     */
277
    private $hydrationCompleteHandler;
278
279
    /**
280
     * @var ReflectionPropertiesGetter
281
     */
282
    private $reflectionPropertiesGetter;
283
284
    /**
285
     * Initializes a new UnitOfWork instance, bound to the given EntityManager.
286
     *
287
     * @param EntityManagerInterface $em
288
     */
289 2356
    public function __construct(EntityManagerInterface $em)
290
    {
291 2356
        $this->em                         = $em;
292 2356
        $this->evm                        = $em->getEventManager();
293 2356
        $this->listenersInvoker           = new ListenersInvoker($em);
294 2356
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
295 2356
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
296 2356
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
297 2356
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
298 2356
    }
299
300
    /**
301
     * Commits the UnitOfWork, executing all operations that have been postponed
302
     * up to this point. The state of all managed entities will be synchronized with
303
     * the database.
304
     *
305
     * The operations are executed in the following order:
306
     *
307
     * 1) All entity insertions
308
     * 2) All entity updates
309
     * 3) All collection deletions
310
     * 4) All collection updates
311
     * 5) All entity deletions
312
     *
313
     * @param null|object|array $entity
314
     *
315
     * @return void
316
     *
317
     * @throws \Exception
318
     */
319 1024
    public function commit($entity = null)
320
    {
321
        // Raise preFlush
322 1024
        if ($this->evm->hasListeners(Events::preFlush)) {
323 2
            $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em));
324
        }
325
326
        // Compute changes done since last commit.
327 1024
        if ($entity === null) {
328 1016
            $this->computeChangeSets();
329 16
        } elseif (is_object($entity)) {
330 15
            $this->computeSingleEntityChangeSet($entity);
331 1
        } elseif (is_array($entity)) {
332 1
            foreach ($entity as $object) {
333 1
                $this->computeSingleEntityChangeSet($object);
334
            }
335
        }
336
337 1021
        if ( ! ($this->entityInsertions ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityInsertions 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...
338 166
                $this->entityDeletions ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityDeletions 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...
339 130
                $this->entityUpdates ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityUpdates 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...
340 40
                $this->collectionUpdates ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->collectionUpdates 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...
341 37
                $this->collectionDeletions ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->collectionDeletions 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...
342 1021
                $this->orphanRemovals)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->orphanRemovals 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...
343 25
            $this->dispatchOnFlushEvent();
344 25
            $this->dispatchPostFlushEvent();
345
346 25
            return; // Nothing to do.
347
        }
348
349 1017
        if ($this->orphanRemovals) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->orphanRemovals 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...
350 16
            foreach ($this->orphanRemovals as $orphan) {
351 16
                $this->remove($orphan);
352
            }
353
        }
354
355 1017
        $this->dispatchOnFlushEvent();
356
357
        // Now we need a commit order to maintain referential integrity
358 1017
        $commitOrder = $this->getCommitOrder();
359
360 1017
        $conn = $this->em->getConnection();
361 1017
        $conn->beginTransaction();
362
363
        try {
364
            // Collection deletions (deletions of complete collections)
365 1017
            foreach ($this->collectionDeletions as $collectionToDelete) {
366 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
367
            }
368
369 1017
            if ($this->entityInsertions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityInsertions 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...
370 1013
                foreach ($commitOrder as $class) {
371 1013
                    $this->executeInserts($class);
372
                }
373
            }
374
375 1016
            if ($this->entityUpdates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityUpdates 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...
376 116
                foreach ($commitOrder as $class) {
377 116
                    $this->executeUpdates($class);
378
                }
379
            }
380
381
            // Extra updates that were requested by persisters.
382 1012
            if ($this->extraUpdates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->extraUpdates 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...
383 40
                $this->executeExtraUpdates();
384
            }
385
386
            // Collection updates (deleteRows, updateRows, insertRows)
387 1012
            foreach ($this->collectionUpdates as $collectionToUpdate) {
388 533
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
389
            }
390
391
            // Entity deletions come last and need to be in reverse commit order
392 1012
            if ($this->entityDeletions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityDeletions 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...
393 63
                for ($count = count($commitOrder), $i = $count - 1; $i >= 0 && $this->entityDeletions; --$i) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityDeletions 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...
394 63
                    $this->executeDeletions($commitOrder[$i]);
395
                }
396
            }
397
398 1012
            $conn->commit();
399 11
        } catch (Exception $e) {
400 11
            $this->em->close();
401 11
            $conn->rollBack();
402
403 11
            $this->afterTransactionRolledBack();
404
405 11
            throw $e;
406
        }
407
408 1012
        $this->afterTransactionComplete();
409
410
        // Take new snapshots from visited collections
411 1012
        foreach ($this->visitedCollections as $coll) {
412 532
            $coll->takeSnapshot();
413
        }
414
415 1012
        $this->dispatchPostFlushEvent();
416
417
        // Clear up
418 1011
        $this->entityInsertions =
419 1011
        $this->entityUpdates =
420 1011
        $this->entityDeletions =
421 1011
        $this->extraUpdates =
422 1011
        $this->entityChangeSets =
423 1011
        $this->collectionUpdates =
424 1011
        $this->collectionDeletions =
425 1011
        $this->visitedCollections =
426 1011
        $this->scheduledForSynchronization =
427 1011
        $this->orphanRemovals = array();
428 1011
    }
429
430
    /**
431
     * Computes the changesets of all entities scheduled for insertion.
432
     *
433
     * @return void
434
     */
435 1023
    private function computeScheduleInsertsChangeSets()
436
    {
437 1023
        foreach ($this->entityInsertions as $entity) {
438 1015
            $class = $this->em->getClassMetadata(get_class($entity));
439
440 1015
            $this->computeChangeSet($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
441
        }
442 1021
    }
443
444
    /**
445
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
446
     *
447
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
448
     * 2. Read Only entities are skipped.
449
     * 3. Proxies are skipped.
450
     * 4. Only if entity is properly managed.
451
     *
452
     * @param object $entity
453
     *
454
     * @return void
455
     *
456
     * @throws \InvalidArgumentException
457
     */
458 16
    private function computeSingleEntityChangeSet($entity)
459
    {
460 16
        $state = $this->getEntityState($entity);
461
462 16
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
463 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
464
        }
465
466 15
        $class = $this->em->getClassMetadata(get_class($entity));
467
468 15
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
469 14
            $this->persist($entity);
470
        }
471
472
        // Compute changes for INSERTed entities first. This must always happen even in this case.
473 15
        $this->computeScheduleInsertsChangeSets();
474
475 15
        if ($class->isReadOnly) {
0 ignored issues
show
Bug introduced by
Accessing isReadOnly on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
476
            return;
477
        }
478
479
        // Ignore uninitialized proxy objects
480 15
        if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
481 2
            return;
482
        }
483
484
        // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
485 13
        $oid = spl_object_hash($entity);
486
487 13
        if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
488 6
            $this->computeChangeSet($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
489
        }
490 12
    }
491
492
    /**
493
     * Executes any extra updates that have been scheduled.
494
     */
495 40
    private function executeExtraUpdates()
496
    {
497 40
        foreach ($this->extraUpdates as $oid => $update) {
498 40
            list ($entity, $changeset) = $update;
499
500 40
            $this->entityChangeSets[$oid] = $changeset;
501 40
            $this->getEntityPersister(get_class($entity))->update($entity);
502
        }
503
504 40
        $this->extraUpdates = array();
505 40
    }
506
507
    /**
508
     * Gets the changeset for an entity.
509
     *
510
     * @param object $entity
511
     *
512
     * @return array
513
     */
514 1015
    public function & getEntityChangeSet($entity)
515
    {
516 1015
        $oid  = spl_object_hash($entity);
517 1015
        $data = array();
518
519 1015
        if (!isset($this->entityChangeSets[$oid])) {
520 1
            return $data;
521
        }
522
523 1015
        return $this->entityChangeSets[$oid];
524
    }
525
526
    /**
527
     * Computes the changes that happened to a single entity.
528
     *
529
     * Modifies/populates the following properties:
530
     *
531
     * {@link _originalEntityData}
532
     * If the entity is NEW or MANAGED but not yet fully persisted (only has an id)
533
     * then it was not fetched from the database and therefore we have no original
534
     * entity data yet. All of the current entity data is stored as the original entity data.
535
     *
536
     * {@link _entityChangeSets}
537
     * The changes detected on all properties of the entity are stored there.
538
     * A change is a tuple array where the first entry is the old value and the second
539
     * entry is the new value of the property. Changesets are used by persisters
540
     * to INSERT/UPDATE the persistent entity state.
541
     *
542
     * {@link _entityUpdates}
543
     * If the entity is already fully MANAGED (has been fetched from the database before)
544
     * and any changes to its properties are detected, then a reference to the entity is stored
545
     * there to mark it for an update.
546
     *
547
     * {@link _collectionDeletions}
548
     * If a PersistentCollection has been de-referenced in a fully MANAGED entity,
549
     * then this collection is marked for deletion.
550
     *
551
     * @ignore
552
     *
553
     * @internal Don't call from the outside.
554
     *
555
     * @param ClassMetadata $class  The class descriptor of the entity.
556
     * @param object        $entity The entity for which to compute the changes.
557
     *
558
     * @return void
559
     */
560 1025
    public function computeChangeSet(ClassMetadata $class, $entity)
561
    {
562 1025
        $oid = spl_object_hash($entity);
563
564 1025
        if (isset($this->readOnlyObjects[$oid])) {
565 2
            return;
566
        }
567
568 1025
        if ( ! $class->isInheritanceTypeNone()) {
569 311
            $class = $this->em->getClassMetadata(get_class($entity));
570
        }
571
572 1025
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preFlush) & ~ListenersInvoker::INVOKE_MANAGER;
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
573
574 1025
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
575 137
            $this->listenersInvoker->invoke($class, Events::preFlush, $entity, new PreFlushEventArgs($this->em), $invoke);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
576
        }
577
578 1025
        $actualData = array();
579
580 1025
        foreach ($class->reflFields as $name => $refProp) {
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
581 1025
            $value = $refProp->getValue($entity);
582
583 1025
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
584 781
                if ($value instanceof PersistentCollection) {
585 201
                    if ($value->getOwner() === $entity) {
586 201
                        continue;
587
                    }
588
589 5
                    $value = new ArrayCollection($value->getValues());
590
                }
591
592
                // If $value is not a Collection then use an ArrayCollection.
593 776
                if ( ! $value instanceof Collection) {
594 242
                    $value = new ArrayCollection($value);
595
                }
596
597 776
                $assoc = $class->associationMappings[$name];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
598
599
                // Inject PersistentCollection
600 776
                $value = new PersistentCollection(
601 776
                    $this->em, $this->em->getClassMetadata($assoc['targetEntity']), $value
0 ignored issues
show
Compatibility introduced by
$this->em->getClassMetad...$assoc['targetEntity']) of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
602
                );
603 776
                $value->setOwner($entity, $assoc);
604 776
                $value->setDirty( ! $value->isEmpty());
605
606 776
                $class->reflFields[$name]->setValue($entity, $value);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
607
608 776
                $actualData[$name] = $value;
609
610 776
                continue;
611
            }
612
613 1025
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) && ($name !== $class->versionField)) {
0 ignored issues
show
Bug introduced by
Accessing versionField on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
614 1025
                $actualData[$name] = $value;
615
            }
616
        }
617
618 1025
        if ( ! isset($this->originalEntityData[$oid])) {
619
            // Entity is either NEW or MANAGED but not yet fully persisted (only has an id).
620
            // These result in an INSERT.
621 1021
            $this->originalEntityData[$oid] = $actualData;
622 1021
            $changeSet = array();
623
624 1021
            foreach ($actualData as $propName => $actualValue) {
625 1004
                if ( ! isset($class->associationMappings[$propName])) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
626 953
                    $changeSet[$propName] = array(null, $actualValue);
627
628 953
                    continue;
629
                }
630
631 898
                $assoc = $class->associationMappings[$propName];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
632
633 898
                if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
634 898
                    $changeSet[$propName] = array(null, $actualValue);
635
                }
636
            }
637
638 1021
            $this->entityChangeSets[$oid] = $changeSet;
639
        } else {
640
            // Entity is "fully" MANAGED: it was already fully persisted before
641
            // and we have a copy of the original data
642 266
            $originalData           = $this->originalEntityData[$oid];
643 266
            $isChangeTrackingNotify = $class->isChangeTrackingNotify();
644 266
            $changeSet              = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid]))
645
                ? $this->entityChangeSets[$oid]
646 266
                : array();
647
648 266
            foreach ($actualData as $propName => $actualValue) {
649
                // skip field, its a partially omitted one!
650 251
                if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) {
651 8
                    continue;
652
                }
653
654 251
                $orgValue = $originalData[$propName];
655
656
                // skip if value haven't changed
657 251
                if ($orgValue === $actualValue) {
658 235
                    continue;
659
                }
660
661
                // if regular field
662 112
                if ( ! isset($class->associationMappings[$propName])) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
663 58
                    if ($isChangeTrackingNotify) {
664
                        continue;
665
                    }
666
667 58
                    $changeSet[$propName] = array($orgValue, $actualValue);
668
669 58
                    continue;
670
                }
671
672 58
                $assoc = $class->associationMappings[$propName];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
673
674
                // Persistent collection was exchanged with the "originally"
675
                // created one. This can only mean it was cloned and replaced
676
                // on another entity.
677 58
                if ($actualValue instanceof PersistentCollection) {
678 8
                    $owner = $actualValue->getOwner();
679 8
                    if ($owner === null) { // cloned
680
                        $actualValue->setOwner($entity, $assoc);
681 8
                    } else if ($owner !== $entity) { // no clone, we have to fix
682
                        if (!$actualValue->isInitialized()) {
683
                            $actualValue->initialize(); // we have to do this otherwise the cols share state
684
                        }
685
                        $newValue = clone $actualValue;
686
                        $newValue->setOwner($entity, $assoc);
687
                        $class->reflFields[$propName]->setValue($entity, $newValue);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
688
                    }
689
                }
690
691 58
                if ($orgValue instanceof PersistentCollection) {
692
                    // A PersistentCollection was de-referenced, so delete it.
693 8
                    $coid = spl_object_hash($orgValue);
694
695 8
                    if (isset($this->collectionDeletions[$coid])) {
696
                        continue;
697
                    }
698
699 8
                    $this->collectionDeletions[$coid] = $orgValue;
700 8
                    $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored.
701
702 8
                    continue;
703
                }
704
705 50
                if ($assoc['type'] & ClassMetadata::TO_ONE) {
706 49
                    if ($assoc['isOwningSide']) {
707 21
                        $changeSet[$propName] = array($orgValue, $actualValue);
708
                    }
709
710 49
                    if ($orgValue !== null && $assoc['orphanRemoval']) {
711 50
                        $this->scheduleOrphanRemoval($orgValue);
712
                    }
713
                }
714
            }
715
716 266
            if ($changeSet) {
717 85
                $this->entityChangeSets[$oid]   = $changeSet;
718 85
                $this->originalEntityData[$oid] = $actualData;
719 85
                $this->entityUpdates[$oid]      = $entity;
720
            }
721
        }
722
723
        // Look for changes in associations of the entity
724 1025
        foreach ($class->associationMappings as $field => $assoc) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
725 898
            if (($val = $class->reflFields[$field]->getValue($entity)) === null) {
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
726 640
                continue;
727
            }
728
729 869
            $this->computeAssociationChanges($assoc, $val);
730
731 861
            if ( ! isset($this->entityChangeSets[$oid]) &&
732 861
                $assoc['isOwningSide'] &&
733 861
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
734 861
                $val instanceof PersistentCollection &&
735 861
                $val->isDirty()) {
736
737 35
                $this->entityChangeSets[$oid]   = array();
738 35
                $this->originalEntityData[$oid] = $actualData;
739 861
                $this->entityUpdates[$oid]      = $entity;
740
            }
741
        }
742 1017
    }
743
744
    /**
745
     * Computes all the changes that have been done to entities and collections
746
     * since the last commit and stores these changes in the _entityChangeSet map
747
     * temporarily for access by the persisters, until the UoW commit is finished.
748
     *
749
     * @return void
750
     */
751 1016
    public function computeChangeSets()
752
    {
753
        // Compute changes for INSERTed entities first. This must always happen.
754 1016
        $this->computeScheduleInsertsChangeSets();
755
756
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
757 1014
        foreach ($this->identityMap as $className => $entities) {
758 451
            $class = $this->em->getClassMetadata($className);
759
760
            // Skip class if instances are read-only
761 451
            if ($class->isReadOnly) {
0 ignored issues
show
Bug introduced by
Accessing isReadOnly on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
762 1
                continue;
763
            }
764
765
            // If change tracking is explicit or happens through notification, then only compute
766
            // changes on entities of that type that are explicitly marked for synchronization.
767
            switch (true) {
768 450
                case ($class->isChangeTrackingDeferredImplicit()):
769 448
                    $entitiesToProcess = $entities;
770 448
                    break;
771
772 3
                case (isset($this->scheduledForSynchronization[$className])):
773 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
774 3
                    break;
775
776
                default:
777 1
                    $entitiesToProcess = array();
778
779
            }
780
781 450
            foreach ($entitiesToProcess as $entity) {
782
                // Ignore uninitialized proxy objects
783 430
                if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
784 36
                    continue;
785
                }
786
787
                // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
788 429
                $oid = spl_object_hash($entity);
789
790 429
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
791 450
                    $this->computeChangeSet($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
792
                }
793
            }
794
        }
795 1014
    }
796
797
    /**
798
     * Computes the changes of an association.
799
     *
800
     * @param array $assoc The association mapping.
801
     * @param mixed $value The value of the association.
802
     *
803
     * @throws ORMInvalidArgumentException
804
     * @throws ORMException
805
     *
806
     * @return void
807
     */
808 869
    private function computeAssociationChanges($assoc, $value)
809
    {
810 869
        if ($value instanceof Proxy && ! $value->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
811 29
            return;
812
        }
813
814 868
        if ($value instanceof PersistentCollection && $value->isDirty()) {
815 535
            $coid = spl_object_hash($value);
816
817 535
            $this->collectionUpdates[$coid] = $value;
818 535
            $this->visitedCollections[$coid] = $value;
819
        }
820
821
        // Look through the entities, and in any of their associations,
822
        // for transient (new) entities, recursively. ("Persistence by reachability")
823
        // Unwrap. Uninitialized collections will simply be empty.
824 868
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
825 868
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
826
827 868
        foreach ($unwrappedValue as $key => $entry) {
828 724
            if (! ($entry instanceof $targetClass->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
829 6
                throw ORMInvalidArgumentException::invalidAssociation($targetClass, $assoc, $entry);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
830
            }
831
832 718
            $state = $this->getEntityState($entry, self::STATE_NEW);
833
834 718
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
835
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
836
            }
837
838
            switch ($state) {
839 718
                case self::STATE_NEW:
840 39
                    if ( ! $assoc['isCascadePersist']) {
841 4
                        throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
842
                    }
843
844 35
                    $this->persistNew($targetClass, $entry);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
845 35
                    $this->computeChangeSet($targetClass, $entry);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
846 35
                    break;
847
848 712
                case self::STATE_REMOVED:
849
                    // Consume the $value as array (it's either an array or an ArrayAccess)
850
                    // and remove the element from Collection.
851 4
                    if ($assoc['type'] & ClassMetadata::TO_MANY) {
852 3
                        unset($value[$key]);
853
                    }
854 4
                    break;
855
856 712
                case self::STATE_DETACHED:
857
                    // Can actually not happen right now as we assume STATE_NEW,
858
                    // so the exception will be raised from the DBAL layer (constraint violation).
859
                    throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
860
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
861
862 715
                default:
863
                    // MANAGED associated entities are already taken into account
864
                    // during changeset calculation anyway, since they are in the identity map.
865
            }
866
        }
867 860
    }
868
869
    /**
870
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
871
     * @param object                              $entity
872
     *
873
     * @return void
874
     */
875 1041
    private function persistNew($class, $entity)
876
    {
877 1041
        $oid    = spl_object_hash($entity);
878 1041
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
879
880 1041
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
881 139
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
882
        }
883
884 1041
        $idGen = $class->idGenerator;
885
886 1041
        if ( ! $idGen->isPostInsertGenerator()) {
887 269
            $idValue = $idGen->generate($this->em, $entity);
0 ignored issues
show
Compatibility introduced by
$this->em of type object<Doctrine\ORM\EntityManagerInterface> is not a sub-type of object<Doctrine\ORM\EntityManager>. It seems like you assume a concrete implementation of the interface Doctrine\ORM\EntityManagerInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
888
889 269
            if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
890 1
                $idField = $class->identifier[0];
891
892
                $idValue = [
893 1
                    $idField => $this->em->getConnection()->convertToPHPValue(
894
                        $idValue,
895 1
                        $class->getTypeOfField($idField)
0 ignored issues
show
Bug introduced by
It seems like $class->getTypeOfField($idField) targeting Doctrine\ORM\Mapping\Cla...aInfo::getTypeOfField() can also be of type null or object<Doctrine\DBAL\Types\Type>; however, Doctrine\DBAL\Connection::convertToPHPValue() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
896
                    )
897
                ];
898
899 1
                $class->setIdentifierValues($entity, $idValue);
900
            }
901
902 269
            $this->entityIdentifiers[$oid] = $idValue;
903
        }
904
905 1041
        $this->entityStates[$oid] = self::STATE_MANAGED;
906
907 1041
        $this->scheduleForInsert($entity);
908 1041
    }
909
910
    /**
911
     * INTERNAL:
912
     * Computes the changeset of an individual entity, independently of the
913
     * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
914
     *
915
     * The passed entity must be a managed entity. If the entity already has a change set
916
     * because this method is invoked during a commit cycle then the change sets are added.
917
     * whereby changes detected in this method prevail.
918
     *
919
     * @ignore
920
     *
921
     * @param ClassMetadata $class  The class descriptor of the entity.
922
     * @param object        $entity The entity for which to (re)calculate the change set.
923
     *
924
     * @return void
925
     *
926
     * @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
927
     */
928 16
    public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
929
    {
930 16
        $oid = spl_object_hash($entity);
931
932 16
        if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
933
            throw ORMInvalidArgumentException::entityNotManaged($entity);
934
        }
935
936
        // skip if change tracking is "NOTIFY"
937 16
        if ($class->isChangeTrackingNotify()) {
938
            return;
939
        }
940
941 16
        if ( ! $class->isInheritanceTypeNone()) {
942 3
            $class = $this->em->getClassMetadata(get_class($entity));
943
        }
944
945 16
        $actualData = array();
946
947 16
        foreach ($class->reflFields as $name => $refProp) {
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
948 16
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
949 16
                && ($name !== $class->versionField)
0 ignored issues
show
Bug introduced by
Accessing versionField on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
950 16
                && ! $class->isCollectionValuedAssociation($name)) {
951 16
                $actualData[$name] = $refProp->getValue($entity);
952
            }
953
        }
954
955 16
        if ( ! isset($this->originalEntityData[$oid])) {
956
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
957
        }
958
959 16
        $originalData = $this->originalEntityData[$oid];
960 16
        $changeSet = array();
961
962 16
        foreach ($actualData as $propName => $actualValue) {
963 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
964
965 16
            if ($orgValue !== $actualValue) {
966 16
                $changeSet[$propName] = array($orgValue, $actualValue);
967
            }
968
        }
969
970 16
        if ($changeSet) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $changeSet 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...
971 7
            if (isset($this->entityChangeSets[$oid])) {
972 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
973 1
            } else if ( ! isset($this->entityInsertions[$oid])) {
974 1
                $this->entityChangeSets[$oid] = $changeSet;
975 1
                $this->entityUpdates[$oid]    = $entity;
976
            }
977 7
            $this->originalEntityData[$oid] = $actualData;
978
        }
979 16
    }
980
981
    /**
982
     * Executes all entity insertions for entities of the specified type.
983
     *
984
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
985
     *
986
     * @return void
987
     */
988 1013
    private function executeInserts($class)
989
    {
990 1013
        $entities   = array();
991 1013
        $className  = $class->name;
992 1013
        $persister  = $this->getEntityPersister($className);
993 1013
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
994
995 1013
        foreach ($this->entityInsertions as $oid => $entity) {
996
997 1013
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
998 861
                continue;
999
            }
1000
1001 1013
            $persister->addInsert($entity);
1002
1003 1013
            unset($this->entityInsertions[$oid]);
1004
1005 1013
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1006 1013
                $entities[] = $entity;
1007
            }
1008
        }
1009
1010 1013
        $postInsertIds = $persister->executeInserts();
1011
1012 1013
        if ($postInsertIds) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $postInsertIds 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...
1013
            // Persister returned post-insert IDs
1014 926
            foreach ($postInsertIds as $postInsertId) {
1015 926
                $idField = $class->identifier[0];
1016 926
                $idValue = $this->em->getConnection()->convertToPHPValue(
1017 926
                    $postInsertId['generatedId'],
1018 926
                    $class->getTypeOfField($idField)
0 ignored issues
show
Bug introduced by
It seems like $class->getTypeOfField($idField) targeting Doctrine\ORM\Mapping\Cla...aInfo::getTypeOfField() can also be of type null or object<Doctrine\DBAL\Types\Type>; however, Doctrine\DBAL\Connection::convertToPHPValue() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1019
                );
1020
1021 926
                $entity  = $postInsertId['entity'];
1022 926
                $oid     = spl_object_hash($entity);
1023
1024 926
                $class->reflFields[$idField]->setValue($entity, $idValue);
1025
1026 926
                $this->entityIdentifiers[$oid] = array($idField => $idValue);
1027 926
                $this->entityStates[$oid] = self::STATE_MANAGED;
1028 926
                $this->originalEntityData[$oid][$idField] = $idValue;
1029
1030 926
                $this->addToIdentityMap($entity);
1031
            }
1032
        }
1033
1034 1013
        foreach ($entities as $entity) {
1035 135
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1036
        }
1037 1013
    }
1038
1039
    /**
1040
     * Executes all entity updates for entities of the specified type.
1041
     *
1042
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1043
     *
1044
     * @return void
1045
     */
1046 116
    private function executeUpdates($class)
1047
    {
1048 116
        $className          = $class->name;
1049 116
        $persister          = $this->getEntityPersister($className);
1050 116
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1051 116
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1052
1053 116
        foreach ($this->entityUpdates as $oid => $entity) {
1054 116
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1055 74
                continue;
1056
            }
1057
1058 116
            if ($preUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1059 13
                $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->getEntityChangeSet($entity)), $preUpdateInvoke);
1060
1061 13
                $this->recomputeSingleEntityChangeSet($class, $entity);
1062
            }
1063
1064 116
            if ( ! empty($this->entityChangeSets[$oid])) {
1065 82
                $persister->update($entity);
1066
            }
1067
1068 112
            unset($this->entityUpdates[$oid]);
1069
1070 112
            if ($postUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1071 112
                $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new LifecycleEventArgs($entity, $this->em), $postUpdateInvoke);
1072
            }
1073
        }
1074 112
    }
1075
1076
    /**
1077
     * Executes all entity deletions for entities of the specified type.
1078
     *
1079
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1080
     *
1081
     * @return void
1082
     */
1083 63
    private function executeDeletions($class)
1084
    {
1085 63
        $className  = $class->name;
1086 63
        $persister  = $this->getEntityPersister($className);
1087 63
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove);
1088
1089 63
        foreach ($this->entityDeletions as $oid => $entity) {
1090 63
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1091 26
                continue;
1092
            }
1093
1094 63
            $persister->delete($entity);
1095
1096
            unset(
1097 63
                $this->entityDeletions[$oid],
1098 63
                $this->entityIdentifiers[$oid],
1099 63
                $this->originalEntityData[$oid],
1100 63
                $this->entityStates[$oid]
1101
            );
1102
1103
            // Entity with this $oid after deletion treated as NEW, even if the $oid
1104
            // is obtained by a new entity because the old one went out of scope.
1105
            //$this->entityStates[$oid] = self::STATE_NEW;
1106 63
            if ( ! $class->isIdentifierNatural()) {
1107 53
                $class->reflFields[$class->identifier[0]]->setValue($entity, null);
1108
            }
1109
1110 63
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1111 63
                $this->listenersInvoker->invoke($class, Events::postRemove, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1112
            }
1113
        }
1114 62
    }
1115
1116
    /**
1117
     * Gets the commit order.
1118
     *
1119
     * @param array|null $entityChangeSet
1120
     *
1121
     * @return array
1122
     */
1123 1017
    private function getCommitOrder(array $entityChangeSet = null)
1124
    {
1125 1017
        if ($entityChangeSet === null) {
1126 1017
            $entityChangeSet = array_merge($this->entityInsertions, $this->entityUpdates, $this->entityDeletions);
1127
        }
1128
1129 1017
        $calc = $this->getCommitOrderCalculator();
1130
1131
        // See if there are any new classes in the changeset, that are not in the
1132
        // commit order graph yet (don't have a node).
1133
        // We have to inspect changeSet to be able to correctly build dependencies.
1134
        // It is not possible to use IdentityMap here because post inserted ids
1135
        // are not yet available.
1136 1017
        $newNodes = array();
1137
1138 1017
        foreach ($entityChangeSet as $entity) {
1139 1017
            $class = $this->em->getClassMetadata(get_class($entity));
1140
1141 1017
            if ($calc->hasNode($class->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1142 630
                continue;
1143
            }
1144
1145 1017
            $calc->addNode($class->name, $class);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1146
1147 1017
            $newNodes[] = $class;
1148
        }
1149
1150
        // Calculate dependencies for new nodes
1151 1017
        while ($class = array_pop($newNodes)) {
1152 1017
            foreach ($class->associationMappings as $assoc) {
1153 890
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1154 850
                    continue;
1155
                }
1156
1157 843
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1158
1159 843
                if ( ! $calc->hasNode($targetClass->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1160 653
                    $calc->addNode($targetClass->name, $targetClass);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1161
1162 653
                    $newNodes[] = $targetClass;
1163
                }
1164
1165 843
                $joinColumns = reset($assoc['joinColumns']);
1166
1167 843
                $calc->addDependency($targetClass->name, $class->name, (int)empty($joinColumns['nullable']));
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1168
1169
                // If the target class has mapped subclasses, these share the same dependency.
1170 843
                if ( ! $targetClass->subClasses) {
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1171 836
                    continue;
1172
                }
1173
1174 218
                foreach ($targetClass->subClasses as $subClassName) {
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1175 218
                    $targetSubClass = $this->em->getClassMetadata($subClassName);
1176
1177 218
                    if ( ! $calc->hasNode($subClassName)) {
1178 190
                        $calc->addNode($targetSubClass->name, $targetSubClass);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1179
1180 190
                        $newNodes[] = $targetSubClass;
1181
                    }
1182
1183 218
                    $calc->addDependency($targetSubClass->name, $class->name, 1);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1184
                }
1185
            }
1186
        }
1187
1188 1017
        return $calc->sort();
1189
    }
1190
1191
    /**
1192
     * Schedules an entity for insertion into the database.
1193
     * If the entity already has an identifier, it will be added to the identity map.
1194
     *
1195
     * @param object $entity The entity to schedule for insertion.
1196
     *
1197
     * @return void
1198
     *
1199
     * @throws ORMInvalidArgumentException
1200
     * @throws \InvalidArgumentException
1201
     */
1202 1042
    public function scheduleForInsert($entity)
1203
    {
1204 1042
        $oid = spl_object_hash($entity);
1205
1206 1042
        if (isset($this->entityUpdates[$oid])) {
1207
            throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion.");
1208
        }
1209
1210 1042
        if (isset($this->entityDeletions[$oid])) {
1211 1
            throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
1212
        }
1213 1042
        if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) {
1214 1
            throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
1215
        }
1216
1217 1042
        if (isset($this->entityInsertions[$oid])) {
1218 1
            throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
1219
        }
1220
1221 1042
        $this->entityInsertions[$oid] = $entity;
1222
1223 1042
        if (isset($this->entityIdentifiers[$oid])) {
1224 269
            $this->addToIdentityMap($entity);
1225
        }
1226
1227 1042
        if ($entity instanceof NotifyPropertyChanged) {
1228 5
            $entity->addPropertyChangedListener($this);
1229
        }
1230 1042
    }
1231
1232
    /**
1233
     * Checks whether an entity is scheduled for insertion.
1234
     *
1235
     * @param object $entity
1236
     *
1237
     * @return boolean
1238
     */
1239 633
    public function isScheduledForInsert($entity)
1240
    {
1241 633
        return isset($this->entityInsertions[spl_object_hash($entity)]);
1242
    }
1243
1244
    /**
1245
     * Schedules an entity for being updated.
1246
     *
1247
     * @param object $entity The entity to schedule for being updated.
1248
     *
1249
     * @return void
1250
     *
1251
     * @throws ORMInvalidArgumentException
1252
     */
1253 1
    public function scheduleForUpdate($entity)
1254
    {
1255 1
        $oid = spl_object_hash($entity);
1256
1257 1
        if ( ! isset($this->entityIdentifiers[$oid])) {
1258
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update");
1259
        }
1260
1261 1
        if (isset($this->entityDeletions[$oid])) {
1262
            throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update");
1263
        }
1264
1265 1
        if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) {
1266 1
            $this->entityUpdates[$oid] = $entity;
1267
        }
1268 1
    }
1269
1270
    /**
1271
     * INTERNAL:
1272
     * Schedules an extra update that will be executed immediately after the
1273
     * regular entity updates within the currently running commit cycle.
1274
     *
1275
     * Extra updates for entities are stored as (entity, changeset) tuples.
1276
     *
1277
     * @ignore
1278
     *
1279
     * @param object $entity    The entity for which to schedule an extra update.
1280
     * @param array  $changeset The changeset of the entity (what to update).
1281
     *
1282
     * @return void
1283
     */
1284 40
    public function scheduleExtraUpdate($entity, array $changeset)
1285
    {
1286 40
        $oid         = spl_object_hash($entity);
1287 40
        $extraUpdate = array($entity, $changeset);
1288
1289 40
        if (isset($this->extraUpdates[$oid])) {
1290 1
            list(, $changeset2) = $this->extraUpdates[$oid];
1291
1292 1
            $extraUpdate = array($entity, $changeset + $changeset2);
1293
        }
1294
1295 40
        $this->extraUpdates[$oid] = $extraUpdate;
1296 40
    }
1297
1298
    /**
1299
     * Checks whether an entity is registered as dirty in the unit of work.
1300
     * Note: Is not very useful currently as dirty entities are only registered
1301
     * at commit time.
1302
     *
1303
     * @param object $entity
1304
     *
1305
     * @return boolean
1306
     */
1307
    public function isScheduledForUpdate($entity)
1308
    {
1309
        return isset($this->entityUpdates[spl_object_hash($entity)]);
1310
    }
1311
1312
    /**
1313
     * Checks whether an entity is registered to be checked in the unit of work.
1314
     *
1315
     * @param object $entity
1316
     *
1317
     * @return boolean
1318
     */
1319 1
    public function isScheduledForDirtyCheck($entity)
1320
    {
1321 1
        $rootEntityName = $this->em->getClassMetadata(get_class($entity))->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1322
1323 1
        return isset($this->scheduledForSynchronization[$rootEntityName][spl_object_hash($entity)]);
1324
    }
1325
1326
    /**
1327
     * INTERNAL:
1328
     * Schedules an entity for deletion.
1329
     *
1330
     * @param object $entity
1331
     *
1332
     * @return void
1333
     */
1334 66
    public function scheduleForDelete($entity)
1335
    {
1336 66
        $oid = spl_object_hash($entity);
1337
1338 66
        if (isset($this->entityInsertions[$oid])) {
1339 1
            if ($this->isInIdentityMap($entity)) {
1340
                $this->removeFromIdentityMap($entity);
1341
            }
1342
1343 1
            unset($this->entityInsertions[$oid], $this->entityStates[$oid]);
1344
1345 1
            return; // entity has not been persisted yet, so nothing more to do.
1346
        }
1347
1348 66
        if ( ! $this->isInIdentityMap($entity)) {
1349 1
            return;
1350
        }
1351
1352 65
        $this->removeFromIdentityMap($entity);
1353
1354 65
        unset($this->entityUpdates[$oid]);
1355
1356 65
        if ( ! isset($this->entityDeletions[$oid])) {
1357 65
            $this->entityDeletions[$oid] = $entity;
1358 65
            $this->entityStates[$oid]    = self::STATE_REMOVED;
1359
        }
1360 65
    }
1361
1362
    /**
1363
     * Checks whether an entity is registered as removed/deleted with the unit
1364
     * of work.
1365
     *
1366
     * @param object $entity
1367
     *
1368
     * @return boolean
1369
     */
1370 17
    public function isScheduledForDelete($entity)
1371
    {
1372 17
        return isset($this->entityDeletions[spl_object_hash($entity)]);
1373
    }
1374
1375
    /**
1376
     * Checks whether an entity is scheduled for insertion, update or deletion.
1377
     *
1378
     * @param object $entity
1379
     *
1380
     * @return boolean
1381
     */
1382
    public function isEntityScheduled($entity)
1383
    {
1384
        $oid = spl_object_hash($entity);
1385
1386
        return isset($this->entityInsertions[$oid])
1387
            || isset($this->entityUpdates[$oid])
1388
            || isset($this->entityDeletions[$oid]);
1389
    }
1390
1391
    /**
1392
     * INTERNAL:
1393
     * Registers an entity in the identity map.
1394
     * Note that entities in a hierarchy are registered with the class name of
1395
     * the root entity.
1396
     *
1397
     * @ignore
1398
     *
1399
     * @param object $entity The entity to register.
1400
     *
1401
     * @return boolean TRUE if the registration was successful, FALSE if the identity of
1402
     *                 the entity in question is already managed.
1403
     *
1404
     * @throws ORMInvalidArgumentException
1405
     */
1406 1107
    public function addToIdentityMap($entity)
1407
    {
1408 1107
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1409 1107
        $identifier    = $this->entityIdentifiers[spl_object_hash($entity)];
1410
1411 1107
        if (empty($identifier) || in_array(null, $identifier, true)) {
1412 6
            throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1413
        }
1414
1415 1101
        $idHash    = implode(' ', $identifier);
1416 1101
        $className = $classMetadata->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1417
1418 1101
        if (isset($this->identityMap[$className][$idHash])) {
1419 83
            return false;
1420
        }
1421
1422 1101
        $this->identityMap[$className][$idHash] = $entity;
1423
1424 1101
        return true;
1425
    }
1426
1427
    /**
1428
     * Gets the state of an entity with regard to the current unit of work.
1429
     *
1430
     * @param object   $entity
1431
     * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED).
1432
     *                         This parameter can be set to improve performance of entity state detection
1433
     *                         by potentially avoiding a database lookup if the distinction between NEW and DETACHED
1434
     *                         is either known or does not matter for the caller of the method.
1435
     *
1436
     * @return int The entity state.
1437
     */
1438 1055
    public function getEntityState($entity, $assume = null)
1439
    {
1440 1055
        $oid = spl_object_hash($entity);
1441
1442 1055
        if (isset($this->entityStates[$oid])) {
1443 786
            return $this->entityStates[$oid];
1444
        }
1445
1446 1049
        if ($assume !== null) {
1447 1045
            return $assume;
1448
        }
1449
1450
        // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known.
1451
        // Note that you can not remember the NEW or DETACHED state in _entityStates since
1452
        // the UoW does not hold references to such objects and the object hash can be reused.
1453
        // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it.
1454 13
        $class = $this->em->getClassMetadata(get_class($entity));
1455 13
        $id    = $class->getIdentifierValues($entity);
1456
1457 13
        if ( ! $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id 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...
1458 5
            return self::STATE_NEW;
1459
        }
1460
1461 10
        if ($class->containsForeignIdentifier) {
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1462 1
            $id = $this->identifierFlattener->flattenIdentifier($class, $id);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1463
        }
1464
1465
        switch (true) {
1466 10
            case ($class->isIdentifierNatural()):
0 ignored issues
show
Bug introduced by
The method isIdentifierNatural() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. Did you maybe mean isIdentifier()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1467
                // Check for a version field, if available, to avoid a db lookup.
1468 5
                if ($class->isVersioned) {
0 ignored issues
show
Bug introduced by
Accessing isVersioned on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1469 1
                    return ($class->getFieldValue($entity, $class->versionField))
0 ignored issues
show
Bug introduced by
Accessing versionField on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1470
                        ? self::STATE_DETACHED
1471 1
                        : self::STATE_NEW;
1472
                }
1473
1474
                // Last try before db lookup: check the identity map.
1475 4
                if ($this->tryGetById($id, $class->rootEntityName)) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1476 1
                    return self::STATE_DETACHED;
1477
                }
1478
1479
                // db lookup
1480 4
                if ($this->getEntityPersister($class->name)->exists($entity)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1481
                    return self::STATE_DETACHED;
1482
                }
1483
1484 4
                return self::STATE_NEW;
1485
1486 5
            case ( ! $class->idGenerator->isPostInsertGenerator()):
0 ignored issues
show
Bug introduced by
Accessing idGenerator on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1487
                // if we have a pre insert generator we can't be sure that having an id
1488
                // really means that the entity exists. We have to verify this through
1489
                // the last resort: a db lookup
1490
1491
                // Last try before db lookup: check the identity map.
1492
                if ($this->tryGetById($id, $class->rootEntityName)) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1493
                    return self::STATE_DETACHED;
1494
                }
1495
1496
                // db lookup
1497
                if ($this->getEntityPersister($class->name)->exists($entity)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1498
                    return self::STATE_DETACHED;
1499
                }
1500
1501
                return self::STATE_NEW;
1502
1503
            default:
1504 5
                return self::STATE_DETACHED;
1505
        }
1506
    }
1507
1508
    /**
1509
     * INTERNAL:
1510
     * Removes an entity from the identity map. This effectively detaches the
1511
     * entity from the persistence management of Doctrine.
1512
     *
1513
     * @ignore
1514
     *
1515
     * @param object $entity
1516
     *
1517
     * @return boolean
1518
     *
1519
     * @throws ORMInvalidArgumentException
1520
     */
1521 77
    public function removeFromIdentityMap($entity)
1522
    {
1523 77
        $oid           = spl_object_hash($entity);
1524 77
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1525 77
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1526
1527 77
        if ($idHash === '') {
1528
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
1529
        }
1530
1531 77
        $className = $classMetadata->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1532
1533 77
        if (isset($this->identityMap[$className][$idHash])) {
1534 77
            unset($this->identityMap[$className][$idHash]);
1535 77
            unset($this->readOnlyObjects[$oid]);
1536
1537
            //$this->entityStates[$oid] = self::STATE_DETACHED;
1538
1539 77
            return true;
1540
        }
1541
1542
        return false;
1543
    }
1544
1545
    /**
1546
     * INTERNAL:
1547
     * Gets an entity in the identity map by its identifier hash.
1548
     *
1549
     * @ignore
1550
     *
1551
     * @param string $idHash
1552
     * @param string $rootClassName
1553
     *
1554
     * @return object
1555
     */
1556 6
    public function getByIdHash($idHash, $rootClassName)
1557
    {
1558 6
        return $this->identityMap[$rootClassName][$idHash];
1559
    }
1560
1561
    /**
1562
     * INTERNAL:
1563
     * Tries to get an entity by its identifier hash. If no entity is found for
1564
     * the given hash, FALSE is returned.
1565
     *
1566
     * @ignore
1567
     *
1568
     * @param mixed  $idHash        (must be possible to cast it to string)
1569
     * @param string $rootClassName
1570
     *
1571
     * @return object|bool The found entity or FALSE.
1572
     */
1573 34
    public function tryGetByIdHash($idHash, $rootClassName)
1574
    {
1575 34
        $stringIdHash = (string) $idHash;
1576
1577 34
        return isset($this->identityMap[$rootClassName][$stringIdHash])
1578 34
            ? $this->identityMap[$rootClassName][$stringIdHash]
1579 34
            : false;
1580
    }
1581
1582
    /**
1583
     * Checks whether an entity is registered in the identity map of this UnitOfWork.
1584
     *
1585
     * @param object $entity
1586
     *
1587
     * @return boolean
1588
     */
1589 214
    public function isInIdentityMap($entity)
1590
    {
1591 214
        $oid = spl_object_hash($entity);
1592
1593 214
        if (empty($this->entityIdentifiers[$oid])) {
1594 31
            return false;
1595
        }
1596
1597 199
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1598 199
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1599
1600 199
        return isset($this->identityMap[$classMetadata->rootEntityName][$idHash]);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1601
    }
1602
1603
    /**
1604
     * INTERNAL:
1605
     * Checks whether an identifier hash exists in the identity map.
1606
     *
1607
     * @ignore
1608
     *
1609
     * @param string $idHash
1610
     * @param string $rootClassName
1611
     *
1612
     * @return boolean
1613
     */
1614
    public function containsIdHash($idHash, $rootClassName)
1615
    {
1616
        return isset($this->identityMap[$rootClassName][$idHash]);
1617
    }
1618
1619
    /**
1620
     * Persists an entity as part of the current unit of work.
1621
     *
1622
     * @param object $entity The entity to persist.
1623
     *
1624
     * @return void
1625
     */
1626 1038
    public function persist($entity)
1627
    {
1628 1038
        $visited = array();
1629
1630 1038
        $this->doPersist($entity, $visited);
1631 1031
    }
1632
1633
    /**
1634
     * Persists an entity as part of the current unit of work.
1635
     *
1636
     * This method is internally called during persist() cascades as it tracks
1637
     * the already visited entities to prevent infinite recursions.
1638
     *
1639
     * @param object $entity  The entity to persist.
1640
     * @param array  $visited The already visited entities.
1641
     *
1642
     * @return void
1643
     *
1644
     * @throws ORMInvalidArgumentException
1645
     * @throws UnexpectedValueException
1646
     */
1647 1038
    private function doPersist($entity, array &$visited)
1648
    {
1649 1038
        $oid = spl_object_hash($entity);
1650
1651 1038
        if (isset($visited[$oid])) {
1652 109
            return; // Prevent infinite recursion
1653
        }
1654
1655 1038
        $visited[$oid] = $entity; // Mark visited
1656
1657 1038
        $class = $this->em->getClassMetadata(get_class($entity));
1658
1659
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1660
        // If we would detect DETACHED here we would throw an exception anyway with the same
1661
        // consequences (not recoverable/programming error), so just assuming NEW here
1662
        // lets us avoid some database lookups for entities with natural identifiers.
1663 1038
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1664
1665
        switch ($entityState) {
1666 1038
            case self::STATE_MANAGED:
1667
                // Nothing to do, except if policy is "deferred explicit"
1668 234
                if ($class->isChangeTrackingDeferredExplicit()) {
1669 2
                    $this->scheduleForDirtyCheck($entity);
1670
                }
1671 234
                break;
1672
1673 1038
            case self::STATE_NEW:
1674 1037
                $this->persistNew($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1675 1037
                break;
1676
1677 1
            case self::STATE_REMOVED:
1678
                // Entity becomes managed again
1679 1
                unset($this->entityDeletions[$oid]);
1680 1
                $this->addToIdentityMap($entity);
1681
1682 1
                $this->entityStates[$oid] = self::STATE_MANAGED;
1683 1
                break;
1684
1685
            case self::STATE_DETACHED:
1686
                // Can actually not happen right now since we assume STATE_NEW.
1687
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
1688
1689
            default:
1690
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1691
        }
1692
1693 1038
        $this->cascadePersist($entity, $visited);
1694 1031
    }
1695
1696
    /**
1697
     * Deletes an entity as part of the current unit of work.
1698
     *
1699
     * @param object $entity The entity to remove.
1700
     *
1701
     * @return void
1702
     */
1703 65
    public function remove($entity)
1704
    {
1705 65
        $visited = array();
1706
1707 65
        $this->doRemove($entity, $visited);
1708 65
    }
1709
1710
    /**
1711
     * Deletes an entity as part of the current unit of work.
1712
     *
1713
     * This method is internally called during delete() cascades as it tracks
1714
     * the already visited entities to prevent infinite recursions.
1715
     *
1716
     * @param object $entity  The entity to delete.
1717
     * @param array  $visited The map of the already visited entities.
1718
     *
1719
     * @return void
1720
     *
1721
     * @throws ORMInvalidArgumentException If the instance is a detached entity.
1722
     * @throws UnexpectedValueException
1723
     */
1724 65
    private function doRemove($entity, array &$visited)
1725
    {
1726 65
        $oid = spl_object_hash($entity);
1727
1728 65
        if (isset($visited[$oid])) {
1729 1
            return; // Prevent infinite recursion
1730
        }
1731
1732 65
        $visited[$oid] = $entity; // mark visited
1733
1734
        // Cascade first, because scheduleForDelete() removes the entity from the identity map, which
1735
        // can cause problems when a lazy proxy has to be initialized for the cascade operation.
1736 65
        $this->cascadeRemove($entity, $visited);
1737
1738 65
        $class       = $this->em->getClassMetadata(get_class($entity));
1739 65
        $entityState = $this->getEntityState($entity);
1740
1741
        switch ($entityState) {
1742 65
            case self::STATE_NEW:
1743 65
            case self::STATE_REMOVED:
1744
                // nothing to do
1745 2
                break;
1746
1747 65
            case self::STATE_MANAGED:
1748 65
                $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preRemove);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1749
1750 65
                if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1751 8
                    $this->listenersInvoker->invoke($class, Events::preRemove, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1752
                }
1753
1754 65
                $this->scheduleForDelete($entity);
1755 65
                break;
1756
1757
            case self::STATE_DETACHED:
1758
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1759
            default:
1760
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1761
        }
1762
1763 65
    }
1764
1765
    /**
1766
     * Merges the state of the given detached entity into this UnitOfWork.
1767
     *
1768
     * @param object $entity
1769
     *
1770
     * @return object The managed copy of the entity.
1771
     *
1772
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1773
     *         attribute and the version check against the managed copy fails.
1774
     *
1775
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1776
     */
1777 41
    public function merge($entity)
1778
    {
1779 41
        $visited = array();
1780
1781 41
        return $this->doMerge($entity, $visited);
1782
    }
1783
1784
    /**
1785
     * Executes a merge operation on an entity.
1786
     *
1787
     * @param object      $entity
1788
     * @param array       $visited
1789
     * @param object|null $prevManagedCopy
1790
     * @param array|null  $assoc
1791
     *
1792
     * @return object The managed copy of the entity.
1793
     *
1794
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1795
     *         attribute and the version check against the managed copy fails.
1796
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1797
     * @throws EntityNotFoundException
1798
     */
1799 41
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, array $assoc = [])
1800
    {
1801 41
        $oid = spl_object_hash($entity);
1802
1803 41
        if (isset($visited[$oid])) {
1804 4
            $managedCopy = $visited[$oid];
1805
1806 4
            if ($prevManagedCopy !== null) {
1807 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
1808
            }
1809
1810 4
            return $managedCopy;
1811
        }
1812
1813 41
        $class = $this->em->getClassMetadata(get_class($entity));
1814
1815
        // First we assume DETACHED, although it can still be NEW but we can avoid
1816
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1817
        // we need to fetch it from the db anyway in order to merge.
1818
        // MANAGED entities are ignored by the merge operation.
1819 41
        $managedCopy = $entity;
1820
1821 41
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1822
            // Try to look the entity up in the identity map.
1823 40
            $id = $class->getIdentifierValues($entity);
1824
1825
            // If there is no ID, it is actually NEW.
1826 40
            if ( ! $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id 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...
1827 6
                $managedCopy = $this->newInstance($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1828
1829 6
                $this->persistNew($class, $managedCopy);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1830
            } else {
1831 35
                $flatId = ($class->containsForeignIdentifier)
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1832 3
                    ? $this->identifierFlattener->flattenIdentifier($class, $id)
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1833 35
                    : $id;
1834
1835 35
                $managedCopy = $this->tryGetById($flatId, $class->rootEntityName);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug Compatibility introduced by
The expression $this->tryGetById($flatI...class->rootEntityName); of type object|boolean adds the type boolean to the return on line 1899 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1836
1837 35
                if ($managedCopy) {
1838
                    // We have the entity in-memory already, just make sure its not removed.
1839 14
                    if ($this->getEntityState($managedCopy) == self::STATE_REMOVED) {
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1835 can also be of type boolean; however, Doctrine\ORM\UnitOfWork::getEntityState() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1840 14
                        throw ORMInvalidArgumentException::entityIsRemoved($managedCopy, "merge");
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1835 can also be of type boolean; however, Doctrine\ORM\ORMInvalidA...tion::entityIsRemoved() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1841
                    }
1842
                } else {
1843
                    // We need to fetch the managed copy in order to merge.
1844 24
                    $managedCopy = $this->em->find($class->name, $flatId);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1845
                }
1846
1847 35
                if ($managedCopy === null) {
1848
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1849
                    // since the managed entity was not found.
1850 2
                    if ( ! $class->isIdentifierNatural()) {
0 ignored issues
show
Bug introduced by
The method isIdentifierNatural() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. Did you maybe mean isIdentifier()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1851 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1852 1
                            $class->getName(),
1853 1
                            $this->identifierFlattener->flattenIdentifier($class, $id)
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1854
                        );
1855
                    }
1856
1857 1
                    $managedCopy = $this->newInstance($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1858 1
                    $class->setIdentifierValues($managedCopy, $id);
1859
1860 1
                    $this->persistNew($class, $managedCopy);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1861
                }
1862
            }
1863
1864 39
            if ($class->isVersioned && $this->isLoaded($managedCopy) && $this->isLoaded($entity)) {
0 ignored issues
show
Bug introduced by
Accessing isVersioned on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1835 can also be of type boolean; however, Doctrine\ORM\UnitOfWork::isLoaded() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1865 4
                $reflField          = $class->reflFields[$class->versionField];
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing versionField on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1866 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1867 4
                $entityVersion      = $reflField->getValue($entity);
1868
1869
                // Throw exception if versions don't match.
1870 4
                if ($managedCopyVersion != $entityVersion) {
1871 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1872
                }
1873
            }
1874
1875 38
            $visited[$oid] = $managedCopy; // mark visited
1876
1877 38
            if ($this->isLoaded($entity)) {
1878 31
                if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) {
1879 4
                    $managedCopy->__load();
1880
                }
1881
1882 31
                $this->mergeEntityStateIntoManagedCopy($entity, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1835 can also be of type boolean; however, Doctrine\ORM\UnitOfWork:...yStateIntoManagedCopy() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1883
            }
1884
1885 38
            if ($class->isChangeTrackingDeferredExplicit()) {
1886
                $this->scheduleForDirtyCheck($entity);
1887
            }
1888
        }
1889
1890 39
        if ($prevManagedCopy !== null) {
1891 6
            $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1835 can also be of type boolean; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1892
        }
1893
1894
        // Mark the managed copy visited as well
1895 39
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1896
1897 39
        $this->cascadeMerge($entity, $managedCopy, $visited);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1835 can also be of type boolean; however, Doctrine\ORM\UnitOfWork::cascadeMerge() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1898
1899 39
        return $managedCopy;
1900
    }
1901
1902
    /**
1903
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1904
     *
1905
     * @param object $entity
1906
     *
1907
     * @return bool
1908
     */
1909 39
    private function isLoaded($entity)
1910
    {
1911 39
        return !($entity instanceof Proxy) || $entity->__isInitialized();
1912
    }
1913
1914
    /**
1915
     * Sets/adds associated managed copies into the previous entity's association field
1916
     *
1917
     * @param object $entity
1918
     * @param array  $association
1919
     * @param object $previousManagedCopy
1920
     * @param object $managedCopy
1921
     *
1922
     * @return void
1923
     */
1924 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1925
    {
1926 6
        $assocField = $association['fieldName'];
1927 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1928
1929 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1930 6
            $prevClass->reflFields[$assocField]->setValue($previousManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1931
1932 6
            return;
1933
        }
1934
1935 1
        $value   = $prevClass->reflFields[$assocField]->getValue($previousManagedCopy);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1936 1
        $value[] = $managedCopy;
1937
1938 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1939 1
            $class = $this->em->getClassMetadata(get_class($entity));
1940
1941 1
            $class->reflFields[$association['mappedBy']]->setValue($managedCopy, $previousManagedCopy);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1942
        }
1943 1
    }
1944
1945
    /**
1946
     * Detaches an entity from the persistence management. It's persistence will
1947
     * no longer be managed by Doctrine.
1948
     *
1949
     * @param object $entity The entity to detach.
1950
     *
1951
     * @return void
1952
     */
1953 12
    public function detach($entity)
1954
    {
1955 12
        $visited = array();
1956
1957 12
        $this->doDetach($entity, $visited);
1958 12
    }
1959
1960
    /**
1961
     * Executes a detach operation on the given entity.
1962
     *
1963
     * @param object  $entity
1964
     * @param array   $visited
1965
     * @param boolean $noCascade if true, don't cascade detach operation.
1966
     *
1967
     * @return void
1968
     */
1969 15
    private function doDetach($entity, array &$visited, $noCascade = false)
1970
    {
1971 15
        $oid = spl_object_hash($entity);
1972
1973 15
        if (isset($visited[$oid])) {
1974
            return; // Prevent infinite recursion
1975
        }
1976
1977 15
        $visited[$oid] = $entity; // mark visited
1978
1979 15
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
1980 15
            case self::STATE_MANAGED:
1981 13
                if ($this->isInIdentityMap($entity)) {
1982 12
                    $this->removeFromIdentityMap($entity);
1983
                }
1984
1985
                unset(
1986 13
                    $this->entityInsertions[$oid],
1987 13
                    $this->entityUpdates[$oid],
1988 13
                    $this->entityDeletions[$oid],
1989 13
                    $this->entityIdentifiers[$oid],
1990 13
                    $this->entityStates[$oid],
1991 13
                    $this->originalEntityData[$oid]
1992
                );
1993 13
                break;
1994 3
            case self::STATE_NEW:
1995 3
            case self::STATE_DETACHED:
1996 3
                return;
1997
        }
1998
1999 13
        if ( ! $noCascade) {
2000 13
            $this->cascadeDetach($entity, $visited);
2001
        }
2002 13
    }
2003
2004
    /**
2005
     * Refreshes the state of the given entity from the database, overwriting
2006
     * any local, unpersisted changes.
2007
     *
2008
     * @param object $entity The entity to refresh.
2009
     *
2010
     * @return void
2011
     *
2012
     * @throws InvalidArgumentException If the entity is not MANAGED.
2013
     */
2014 17
    public function refresh($entity)
2015
    {
2016 17
        $visited = array();
2017
2018 17
        $this->doRefresh($entity, $visited);
2019 17
    }
2020
2021
    /**
2022
     * Executes a refresh operation on an entity.
2023
     *
2024
     * @param object $entity  The entity to refresh.
2025
     * @param array  $visited The already visited entities during cascades.
2026
     *
2027
     * @return void
2028
     *
2029
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2030
     */
2031 17
    private function doRefresh($entity, array &$visited)
2032
    {
2033 17
        $oid = spl_object_hash($entity);
2034
2035 17
        if (isset($visited[$oid])) {
2036
            return; // Prevent infinite recursion
2037
        }
2038
2039 17
        $visited[$oid] = $entity; // mark visited
2040
2041 17
        $class = $this->em->getClassMetadata(get_class($entity));
2042
2043 17
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2044
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2045
        }
2046
2047 17
        $this->getEntityPersister($class->name)->refresh(
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2048 17
            array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2049
            $entity
2050
        );
2051
2052 17
        $this->cascadeRefresh($entity, $visited);
2053 17
    }
2054
2055
    /**
2056
     * Cascades a refresh operation to associated entities.
2057
     *
2058
     * @param object $entity
2059
     * @param array  $visited
2060
     *
2061
     * @return void
2062
     */
2063 17
    private function cascadeRefresh($entity, array &$visited)
2064
    {
2065 17
        $class = $this->em->getClassMetadata(get_class($entity));
2066
2067 17
        $associationMappings = array_filter(
2068 17
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2069
            function ($assoc) { return $assoc['isCascadeRefresh']; }
2070
        );
2071
2072 17
        foreach ($associationMappings as $assoc) {
2073 5
            $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2074
2075
            switch (true) {
2076 5
                case ($relatedEntities instanceof PersistentCollection):
2077
                    // Unwrap so that foreach() does not initialize
2078 5
                    $relatedEntities = $relatedEntities->unwrap();
2079
                    // break; is commented intentionally!
2080
2081
                case ($relatedEntities instanceof Collection):
2082
                case (is_array($relatedEntities)):
2083 5
                    foreach ($relatedEntities as $relatedEntity) {
2084
                        $this->doRefresh($relatedEntity, $visited);
2085
                    }
2086 5
                    break;
2087
2088
                case ($relatedEntities !== null):
2089
                    $this->doRefresh($relatedEntities, $visited);
2090
                    break;
2091
2092 5
                default:
2093
                    // Do nothing
2094
            }
2095
        }
2096 17
    }
2097
2098
    /**
2099
     * Cascades a detach operation to associated entities.
2100
     *
2101
     * @param object $entity
2102
     * @param array  $visited
2103
     *
2104
     * @return void
2105
     */
2106 13
    private function cascadeDetach($entity, array &$visited)
2107
    {
2108 13
        $class = $this->em->getClassMetadata(get_class($entity));
2109
2110 13
        $associationMappings = array_filter(
2111 13
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2112
            function ($assoc) { return $assoc['isCascadeDetach']; }
2113
        );
2114
2115 13
        foreach ($associationMappings as $assoc) {
2116 3
            $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2117
2118
            switch (true) {
2119 3
                case ($relatedEntities instanceof PersistentCollection):
2120
                    // Unwrap so that foreach() does not initialize
2121 2
                    $relatedEntities = $relatedEntities->unwrap();
2122
                    // break; is commented intentionally!
2123
2124
                case ($relatedEntities instanceof Collection):
2125
                case (is_array($relatedEntities)):
2126 3
                    foreach ($relatedEntities as $relatedEntity) {
2127 1
                        $this->doDetach($relatedEntity, $visited);
2128
                    }
2129 3
                    break;
2130
2131
                case ($relatedEntities !== null):
2132
                    $this->doDetach($relatedEntities, $visited);
2133
                    break;
2134
2135 3
                default:
2136
                    // Do nothing
2137
            }
2138
        }
2139 13
    }
2140
2141
    /**
2142
     * Cascades a merge operation to associated entities.
2143
     *
2144
     * @param object $entity
2145
     * @param object $managedCopy
2146
     * @param array  $visited
2147
     *
2148
     * @return void
2149
     */
2150 39
    private function cascadeMerge($entity, $managedCopy, array &$visited)
2151
    {
2152 39
        $class = $this->em->getClassMetadata(get_class($entity));
2153
2154 39
        $associationMappings = array_filter(
2155 39
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2156
            function ($assoc) { return $assoc['isCascadeMerge']; }
2157
        );
2158
2159 39
        foreach ($associationMappings as $assoc) {
2160 16
            $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2161
2162 16
            if ($relatedEntities instanceof Collection) {
2163 10
                if ($relatedEntities === $class->reflFields[$assoc['fieldName']]->getValue($managedCopy)) {
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2164 1
                    continue;
2165
                }
2166
2167 9
                if ($relatedEntities instanceof PersistentCollection) {
2168
                    // Unwrap so that foreach() does not initialize
2169 5
                    $relatedEntities = $relatedEntities->unwrap();
2170
                }
2171
2172 9
                foreach ($relatedEntities as $relatedEntity) {
2173 9
                    $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
2174
                }
2175 7
            } else if ($relatedEntities !== null) {
2176 15
                $this->doMerge($relatedEntities, $visited, $managedCopy, $assoc);
2177
            }
2178
        }
2179 39
    }
2180
2181
    /**
2182
     * Cascades the save operation to associated entities.
2183
     *
2184
     * @param object $entity
2185
     * @param array  $visited
2186
     *
2187
     * @return void
2188
     */
2189 1038
    private function cascadePersist($entity, array &$visited)
2190
    {
2191 1038
        $class = $this->em->getClassMetadata(get_class($entity));
2192
2193 1038
        $associationMappings = array_filter(
2194 1038
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2195
            function ($assoc) { return $assoc['isCascadePersist']; }
2196
        );
2197
2198 1038
        foreach ($associationMappings as $assoc) {
2199 652
            $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2200
2201
            switch (true) {
2202 652
                case ($relatedEntities instanceof PersistentCollection):
2203
                    // Unwrap so that foreach() does not initialize
2204 21
                    $relatedEntities = $relatedEntities->unwrap();
2205
                    // break; is commented intentionally!
2206
2207
                case ($relatedEntities instanceof Collection):
2208 592
                case (is_array($relatedEntities)):
2209 556
                    if (($assoc['type'] & ClassMetadata::TO_MANY) <= 0) {
2210 3
                        throw ORMInvalidArgumentException::invalidAssociation(
2211 3
                            $this->em->getClassMetadata($assoc['targetEntity']),
0 ignored issues
show
Compatibility introduced by
$this->em->getClassMetad...$assoc['targetEntity']) of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
2212
                            $assoc,
2213
                            $relatedEntities
2214
                        );
2215
                    }
2216
2217 553
                    foreach ($relatedEntities as $relatedEntity) {
2218 282
                        $this->doPersist($relatedEntity, $visited);
2219
                    }
2220
2221 553
                    break;
2222
2223 582
                case ($relatedEntities !== null):
2224 246
                    if (! $relatedEntities instanceof $assoc['targetEntity']) {
2225 4
                        throw ORMInvalidArgumentException::invalidAssociation(
2226 4
                            $this->em->getClassMetadata($assoc['targetEntity']),
0 ignored issues
show
Compatibility introduced by
$this->em->getClassMetad...$assoc['targetEntity']) of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
2227
                            $assoc,
2228
                            $relatedEntities
2229
                        );
2230
                    }
2231
2232 242
                    $this->doPersist($relatedEntities, $visited);
2233 242
                    break;
2234
2235 646
                default:
2236
                    // Do nothing
2237
            }
2238
        }
2239 1031
    }
2240
2241
    /**
2242
     * Cascades the delete operation to associated entities.
2243
     *
2244
     * @param object $entity
2245
     * @param array  $visited
2246
     *
2247
     * @return void
2248
     */
2249 65
    private function cascadeRemove($entity, array &$visited)
2250
    {
2251 65
        $class = $this->em->getClassMetadata(get_class($entity));
2252
2253 65
        $associationMappings = array_filter(
2254 65
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2255
            function ($assoc) { return $assoc['isCascadeRemove']; }
2256
        );
2257
2258 65
        $entitiesToCascade = array();
2259
2260 65
        foreach ($associationMappings as $assoc) {
2261 26
            if ($entity instanceof Proxy && !$entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2262 6
                $entity->__load();
2263
            }
2264
2265 26
            $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2266
2267
            switch (true) {
2268 26
                case ($relatedEntities instanceof Collection):
2269 19
                case (is_array($relatedEntities)):
2270
                    // If its a PersistentCollection initialization is intended! No unwrap!
2271 20
                    foreach ($relatedEntities as $relatedEntity) {
2272 10
                        $entitiesToCascade[] = $relatedEntity;
2273
                    }
2274 20
                    break;
2275
2276 19
                case ($relatedEntities !== null):
2277 7
                    $entitiesToCascade[] = $relatedEntities;
2278 7
                    break;
2279
2280 26
                default:
2281
                    // Do nothing
2282
            }
2283
        }
2284
2285 65
        foreach ($entitiesToCascade as $relatedEntity) {
2286 16
            $this->doRemove($relatedEntity, $visited);
2287
        }
2288 65
    }
2289
2290
    /**
2291
     * Acquire a lock on the given entity.
2292
     *
2293
     * @param object $entity
2294
     * @param int    $lockMode
2295
     * @param int    $lockVersion
2296
     *
2297
     * @return void
2298
     *
2299
     * @throws ORMInvalidArgumentException
2300
     * @throws TransactionRequiredException
2301
     * @throws OptimisticLockException
2302
     */
2303 11
    public function lock($entity, $lockMode, $lockVersion = null)
2304
    {
2305 11
        if ($entity === null) {
2306 1
            throw new \InvalidArgumentException("No entity passed to UnitOfWork#lock().");
2307
        }
2308
2309 10
        if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
2310 1
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2311
        }
2312
2313 9
        $class = $this->em->getClassMetadata(get_class($entity));
2314
2315
        switch (true) {
2316 9
            case LockMode::OPTIMISTIC === $lockMode:
2317 6
                if ( ! $class->isVersioned) {
0 ignored issues
show
Bug introduced by
Accessing isVersioned on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2318 2
                    throw OptimisticLockException::notVersioned($class->name);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2319
                }
2320
2321 4
                if ($lockVersion === null) {
2322
                    return;
2323
                }
2324
2325 4
                if ($entity instanceof Proxy && !$entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2326 1
                    $entity->__load();
2327
                }
2328
2329 4
                $entityVersion = $class->reflFields[$class->versionField]->getValue($entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing versionField on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2330
2331 4
                if ($entityVersion != $lockVersion) {
2332 2
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion);
2333
                }
2334
2335 2
                break;
2336
2337 3
            case LockMode::NONE === $lockMode:
2338 3
            case LockMode::PESSIMISTIC_READ === $lockMode:
2339 1
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
2340 3
                if (!$this->em->getConnection()->isTransactionActive()) {
2341 2
                    throw TransactionRequiredException::transactionRequired();
2342
                }
2343
2344 1
                $oid = spl_object_hash($entity);
2345
2346 1
                $this->getEntityPersister($class->name)->lock(
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2347 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2348
                    $lockMode
2349
                );
2350 1
                break;
2351
2352
            default:
2353
                // Do nothing
2354
        }
2355 3
    }
2356
2357
    /**
2358
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2359
     *
2360
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2361
     */
2362 1017
    public function getCommitOrderCalculator()
2363
    {
2364 1017
        return new Internal\CommitOrderCalculator();
2365
    }
2366
2367
    /**
2368
     * Clears the UnitOfWork.
2369
     *
2370
     * @param string|null $entityName if given, only entities of this type will get detached.
2371
     *
2372
     * @return void
2373
     */
2374 1229
    public function clear($entityName = null)
2375
    {
2376 1229
        if ($entityName === null) {
2377 1228
            $this->identityMap =
2378 1228
            $this->entityIdentifiers =
2379 1228
            $this->originalEntityData =
2380 1228
            $this->entityChangeSets =
2381 1228
            $this->entityStates =
2382 1228
            $this->scheduledForSynchronization =
2383 1228
            $this->entityInsertions =
2384 1228
            $this->entityUpdates =
2385 1228
            $this->entityDeletions =
2386 1228
            $this->collectionDeletions =
2387 1228
            $this->collectionUpdates =
2388 1228
            $this->extraUpdates =
2389 1228
            $this->readOnlyObjects =
2390 1228
            $this->visitedCollections =
2391 1228
            $this->orphanRemovals = array();
2392
        } else {
2393 3
            $this->clearIdentityMapForEntityName($entityName);
2394 3
            $this->clearEntityInsertionsForEntityName($entityName);
2395
        }
2396
2397 1229
        if ($this->evm->hasListeners(Events::onClear)) {
2398 7
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2399
        }
2400 1229
    }
2401
2402
    /**
2403
     * INTERNAL:
2404
     * Schedules an orphaned entity for removal. The remove() operation will be
2405
     * invoked on that entity at the beginning of the next commit of this
2406
     * UnitOfWork.
2407
     *
2408
     * @ignore
2409
     *
2410
     * @param object $entity
2411
     *
2412
     * @return void
2413
     */
2414 17
    public function scheduleOrphanRemoval($entity)
2415
    {
2416 17
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2417 17
    }
2418
2419
    /**
2420
     * INTERNAL:
2421
     * Cancels a previously scheduled orphan removal.
2422
     *
2423
     * @ignore
2424
     *
2425
     * @param object $entity
2426
     *
2427
     * @return void
2428
     */
2429 114
    public function cancelOrphanRemoval($entity)
2430
    {
2431 114
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2432 114
    }
2433
2434
    /**
2435
     * INTERNAL:
2436
     * Schedules a complete collection for removal when this UnitOfWork commits.
2437
     *
2438
     * @param PersistentCollection $coll
2439
     *
2440
     * @return void
2441
     */
2442 14
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2443
    {
2444 14
        $coid = spl_object_hash($coll);
2445
2446
        // TODO: if $coll is already scheduled for recreation ... what to do?
2447
        // Just remove $coll from the scheduled recreations?
2448 14
        unset($this->collectionUpdates[$coid]);
2449
2450 14
        $this->collectionDeletions[$coid] = $coll;
2451 14
    }
2452
2453
    /**
2454
     * @param PersistentCollection $coll
2455
     *
2456
     * @return bool
2457
     */
2458
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2459
    {
2460
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2461
    }
2462
2463
    /**
2464
     * @param ClassMetadata $class
2465
     *
2466
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2467
     */
2468 678
    private function newInstance($class)
2469
    {
2470 678
        $entity = $class->newInstance();
2471
2472 678
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2473 4
            $entity->injectObjectManager($this->em, $class);
2474
        }
2475
2476 678
        return $entity;
2477
    }
2478
2479
    /**
2480
     * INTERNAL:
2481
     * Creates an entity. Used for reconstitution of persistent entities.
2482
     *
2483
     * Internal note: Highly performance-sensitive method.
2484
     *
2485
     * @ignore
2486
     *
2487
     * @param string $className The name of the entity class.
2488
     * @param array  $data      The data for the entity.
2489
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2490
     *
2491
     * @return object The managed entity instance.
2492
     *
2493
     * @todo Rename: getOrCreateEntity
2494
     */
2495 816
    public function createEntity($className, array $data, &$hints = array())
2496
    {
2497 816
        $class = $this->em->getClassMetadata($className);
2498
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2499
2500 816
        $id = $this->identifierFlattener->flattenIdentifier($class, $data);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
2501 816
        $idHash = implode(' ', $id);
2502
2503 816
        if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2504 312
            $entity = $this->identityMap[$class->rootEntityName][$idHash];
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2505 312
            $oid = spl_object_hash($entity);
2506
2507
            if (
2508 312
                isset($hints[Query::HINT_REFRESH])
2509 312
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2510 312
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2511 312
                && $unmanagedProxy instanceof Proxy
2512 312
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2513
            ) {
2514
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2515
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2516
                // refreshed object may be anything
2517
2518 2
                foreach ($class->identifier as $fieldName) {
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2519 2
                    $class->reflFields[$fieldName]->setValue($unmanagedProxy, null);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2520
                }
2521
2522 2
                return $unmanagedProxy;
2523
            }
2524
2525 310
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2526 22
                $entity->__setInitialized(true);
2527
2528 22
                $overrideLocalValues = true;
2529
2530 22
                if ($entity instanceof NotifyPropertyChanged) {
2531 22
                    $entity->addPropertyChangedListener($this);
2532
                }
2533
            } else {
2534 290
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2535
2536
                // If only a specific entity is set to refresh, check that it's the one
2537 290
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2538 71
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2539
                }
2540
            }
2541
2542 310
            if ($overrideLocalValues) {
2543
                // inject ObjectManager upon refresh.
2544 113
                if ($entity instanceof ObjectManagerAware) {
2545 3
                    $entity->injectObjectManager($this->em, $class);
2546
                }
2547
2548 310
                $this->originalEntityData[$oid] = $data;
2549
            }
2550
        } else {
2551 674
            $entity = $this->newInstance($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
2552 674
            $oid    = spl_object_hash($entity);
2553
2554 674
            $this->entityIdentifiers[$oid]  = $id;
2555 674
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2556 674
            $this->originalEntityData[$oid] = $data;
2557
2558 674
            $this->identityMap[$class->rootEntityName][$idHash] = $entity;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2559
2560 674
            if ($entity instanceof NotifyPropertyChanged) {
2561 2
                $entity->addPropertyChangedListener($this);
2562
            }
2563
2564 674
            $overrideLocalValues = true;
2565
        }
2566
2567 815
        if ( ! $overrideLocalValues) {
2568 220
            return $entity;
2569
        }
2570
2571 712
        foreach ($data as $field => $value) {
2572 712
            if (isset($class->fieldMappings[$field])) {
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2573 712
                $class->reflFields[$field]->setValue($entity, $value);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2574
            }
2575
        }
2576
2577
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2578 712
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2579
2580 712
        if (isset($this->eagerLoadingEntities[$class->rootEntityName]) && ! $this->eagerLoadingEntities[$class->rootEntityName]) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2581
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2582
        }
2583
2584
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2585 712
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2586 33
            return $entity;
2587
        }
2588
2589 679
        foreach ($class->associationMappings as $field => $assoc) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2590
            // Check if the association is not among the fetch-joined associations already.
2591 590
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2592 261
                continue;
2593
            }
2594
2595 568
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2596
2597
            switch (true) {
2598 568
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2599 488
                    if ( ! $assoc['isOwningSide']) {
2600
2601
                        // use the given entity association
2602 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2603
2604 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2605
2606 2
                            $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2607 2
                            $targetClass->reflFields[$assoc['mappedBy']]->setValue($data[$field], $entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2608
2609 2
                            continue 2;
2610
                        }
2611
2612
                        // Inverse side of x-to-one can never be lazy
2613 62
                        $class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity));
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2614
2615 62
                        continue 2;
2616
                    }
2617
2618
                    // use the entity association
2619 488
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2620 38
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2621 38
                        $this->originalEntityData[$oid][$field] = $data[$field];
2622
2623 38
                        continue;
2624
                    }
2625
2626 481
                    $associatedId = array();
2627
2628
                    // TODO: Is this even computed right in all cases of composite keys?
2629 481
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2630 481
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2631
2632 481
                        if ($joinColumnValue !== null) {
2633 286
                            if ($targetClass->containsForeignIdentifier) {
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2634 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2635
                            } else {
2636 286
                                $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
0 ignored issues
show
Bug introduced by
Accessing fieldNames on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2637
                            }
2638 287
                        } elseif ($targetClass->containsForeignIdentifier
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2639 287
                            && in_array($targetClass->getFieldForColumn($targetColumn), $targetClass->identifier, true)
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2640
                        ) {
2641
                            // the missing key is part of target's entity primary key
2642 7
                            $associatedId = array();
2643 481
                            break;
2644
                        }
2645
                    }
2646
2647 481
                    if ( ! $associatedId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $associatedId 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...
2648
                        // Foreign key is NULL
2649 287
                        $class->reflFields[$field]->setValue($entity, null);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2650 287
                        $this->originalEntityData[$oid][$field] = null;
2651
2652 287
                        continue;
2653
                    }
2654
2655 286
                    if ( ! isset($hints['fetchMode'][$class->name][$field])) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2656 283
                        $hints['fetchMode'][$class->name][$field] = $assoc['fetch'];
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2657
                    }
2658
2659
                    // Foreign key is set
2660
                    // Check identity map first
2661
                    // FIXME: Can break easily with composite keys if join column values are in
2662
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2663 286
                    $relatedIdHash = implode(' ', $associatedId);
2664
2665
                    switch (true) {
2666 286
                        case (isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash])):
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2667 168
                            $newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash];
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2668
2669
                            // If this is an uninitialized proxy, we are deferring eager loads,
2670
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2671
                            // then we can append this entity for eager loading!
2672 168
                            if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER &&
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2673 168
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2674 168
                                !$targetClass->isIdentifierComposite &&
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2675 168
                                $newValue instanceof Proxy &&
2676 168
                                $newValue->__isInitialized__ === false) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2677
2678
                                $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2679
                            }
2680
2681 168
                            break;
2682
2683 193
                        case ($targetClass->subClasses):
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2684
                            // If it might be a subtype, it can not be lazy. There isn't even
2685
                            // a way to solve this with deferred eager loading, which means putting
2686
                            // an entity with subclasses at a *-to-one location is really bad! (performance-wise)
2687 31
                            $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
2688 31
                            break;
2689
2690
                        default:
2691
                            switch (true) {
2692
                                // We are negating the condition here. Other cases will assume it is valid!
2693 164
                                case ($hints['fetchMode'][$class->name][$field] !== ClassMetadata::FETCH_EAGER):
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2694 157
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2695 157
                                    break;
2696
2697
                                // Deferred eager load only works for single identifier classes
2698 7
                                case (isset($hints[self::HINT_DEFEREAGERLOAD]) && ! $targetClass->isIdentifierComposite):
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2699
                                    // TODO: Is there a faster approach?
2700 7
                                    $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2701
2702 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2703 7
                                    break;
2704
2705
                                default:
2706
                                    // TODO: This is very imperformant, ignore it?
2707
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2708
                                    break;
2709
                            }
2710
2711
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2712 164
                            $newValueOid = spl_object_hash($newValue);
2713 164
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2714 164
                            $this->identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2715
2716
                            if (
2717 164
                                $newValue instanceof NotifyPropertyChanged &&
2718 164
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2719
                            ) {
2720
                                $newValue->addPropertyChangedListener($this);
2721
                            }
2722 164
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2723
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2724 164
                            break;
2725
                    }
2726
2727 286
                    $this->originalEntityData[$oid][$field] = $newValue;
2728 286
                    $class->reflFields[$field]->setValue($entity, $newValue);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2729
2730 286
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2731 50
                        $inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2732 50
                        $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2733
                    }
2734
2735 286
                    break;
2736
2737
                default:
2738
                    // Ignore if its a cached collection
2739 490
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2740
                        break;
2741
                    }
2742
2743
                    // use the given collection
2744 490
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2745
2746 3
                        $data[$field]->setOwner($entity, $assoc);
2747
2748 3
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2749 3
                        $this->originalEntityData[$oid][$field] = $data[$field];
2750
2751 3
                        break;
2752
                    }
2753
2754
                    // Inject collection
2755 490
                    $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
2756 490
                    $pColl->setOwner($entity, $assoc);
2757 490
                    $pColl->setInitialized(false);
2758
2759 490
                    $reflField = $class->reflFields[$field];
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2760 490
                    $reflField->setValue($entity, $pColl);
2761
2762 490
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2763 4
                        $this->loadCollection($pColl);
2764 4
                        $pColl->takeSnapshot();
2765
                    }
2766
2767 490
                    $this->originalEntityData[$oid][$field] = $pColl;
2768 568
                    break;
2769
            }
2770
        }
2771
2772 679
        if ($overrideLocalValues) {
2773
            // defer invoking of postLoad event to hydration complete step
2774 679
            $this->hydrationCompleteHandler->deferPostLoadInvoking($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
2775
        }
2776
2777 679
        return $entity;
2778
    }
2779
2780
    /**
2781
     * @return void
2782
     */
2783 874
    public function triggerEagerLoads()
2784
    {
2785 874
        if ( ! $this->eagerLoadingEntities) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->eagerLoadingEntities 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...
2786 874
            return;
2787
        }
2788
2789
        // avoid infinite recursion
2790 7
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2791 7
        $this->eagerLoadingEntities = array();
2792
2793 7
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2794 7
            if ( ! $ids) {
2795
                continue;
2796
            }
2797
2798 7
            $class = $this->em->getClassMetadata($entityName);
2799
2800 7
            $this->getEntityPersister($entityName)->loadAll(
2801 7
                array_combine($class->identifier, array(array_values($ids)))
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2802
            );
2803
        }
2804 7
    }
2805
2806
    /**
2807
     * Initializes (loads) an uninitialized persistent collection of an entity.
2808
     *
2809
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2810
     *
2811
     * @return void
2812
     *
2813
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2814
     */
2815 146
    public function loadCollection(PersistentCollection $collection)
2816
    {
2817 146
        $assoc     = $collection->getMapping();
2818 146
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2819
2820 146
        switch ($assoc['type']) {
2821 146
            case ClassMetadata::ONE_TO_MANY:
2822 77
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2823 77
                break;
2824
2825 83
            case ClassMetadata::MANY_TO_MANY:
2826 83
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2827 83
                break;
2828
        }
2829
2830 146
        $collection->setInitialized(true);
2831 146
    }
2832
2833
    /**
2834
     * Gets the identity map of the UnitOfWork.
2835
     *
2836
     * @return array
2837
     */
2838 2
    public function getIdentityMap()
2839
    {
2840 2
        return $this->identityMap;
2841
    }
2842
2843
    /**
2844
     * Gets the original data of an entity. The original data is the data that was
2845
     * present at the time the entity was reconstituted from the database.
2846
     *
2847
     * @param object $entity
2848
     *
2849
     * @return array
2850
     */
2851 119
    public function getOriginalEntityData($entity)
2852
    {
2853 119
        $oid = spl_object_hash($entity);
2854
2855 119
        return isset($this->originalEntityData[$oid])
2856 115
            ? $this->originalEntityData[$oid]
2857 119
            : [];
2858
    }
2859
2860
    /**
2861
     * @ignore
2862
     *
2863
     * @param object $entity
2864
     * @param array  $data
2865
     *
2866
     * @return void
2867
     */
2868
    public function setOriginalEntityData($entity, array $data)
2869
    {
2870
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2871
    }
2872
2873
    /**
2874
     * INTERNAL:
2875
     * Sets a property value of the original data array of an entity.
2876
     *
2877
     * @ignore
2878
     *
2879
     * @param string $oid
2880
     * @param string $property
2881
     * @param mixed  $value
2882
     *
2883
     * @return void
2884
     */
2885 314
    public function setOriginalEntityProperty($oid, $property, $value)
2886
    {
2887 314
        $this->originalEntityData[$oid][$property] = $value;
2888 314
    }
2889
2890
    /**
2891
     * Gets the identifier of an entity.
2892
     * The returned value is always an array of identifier values. If the entity
2893
     * has a composite identifier then the identifier values are in the same
2894
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2895
     *
2896
     * @param object $entity
2897
     *
2898
     * @return array The identifier values.
2899
     */
2900 847
    public function getEntityIdentifier($entity)
2901
    {
2902 847
        return $this->entityIdentifiers[spl_object_hash($entity)];
2903
    }
2904
2905
    /**
2906
     * Processes an entity instance to extract their identifier values.
2907
     *
2908
     * @param object $entity The entity instance.
2909
     *
2910
     * @return mixed A scalar value.
2911
     *
2912
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2913
     */
2914 127
    public function getSingleIdentifierValue($entity)
2915
    {
2916 127
        $class = $this->em->getClassMetadata(get_class($entity));
2917
2918 127
        if ($class->isIdentifierComposite) {
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2919
            throw ORMInvalidArgumentException::invalidCompositeIdentifier();
2920
        }
2921
2922 127
        $values = $this->isInIdentityMap($entity)
2923 114
            ? $this->getEntityIdentifier($entity)
2924 127
            : $class->getIdentifierValues($entity);
2925
2926 127
        return isset($values[$class->identifier[0]]) ? $values[$class->identifier[0]] : null;
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2927
    }
2928
2929
    /**
2930
     * Tries to find an entity with the given identifier in the identity map of
2931
     * this UnitOfWork.
2932
     *
2933
     * @param mixed  $id            The entity identifier to look for.
2934
     * @param string $rootClassName The name of the root class of the mapped entity hierarchy.
2935
     *
2936
     * @return object|bool Returns the entity with the specified identifier if it exists in
2937
     *                     this UnitOfWork, FALSE otherwise.
2938
     */
2939 526
    public function tryGetById($id, $rootClassName)
2940
    {
2941 526
        $idHash = implode(' ', (array) $id);
2942
2943 526
        return isset($this->identityMap[$rootClassName][$idHash])
2944 80
            ? $this->identityMap[$rootClassName][$idHash]
2945 526
            : false;
2946
    }
2947
2948
    /**
2949
     * Schedules an entity for dirty-checking at commit-time.
2950
     *
2951
     * @param object $entity The entity to schedule for dirty-checking.
2952
     *
2953
     * @return void
2954
     *
2955
     * @todo Rename: scheduleForSynchronization
2956
     */
2957 5
    public function scheduleForDirtyCheck($entity)
2958
    {
2959 5
        $rootClassName = $this->em->getClassMetadata(get_class($entity))->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2960
2961 5
        $this->scheduledForSynchronization[$rootClassName][spl_object_hash($entity)] = $entity;
2962 5
    }
2963
2964
    /**
2965
     * Checks whether the UnitOfWork has any pending insertions.
2966
     *
2967
     * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise.
2968
     */
2969
    public function hasPendingInsertions()
2970
    {
2971
        return ! empty($this->entityInsertions);
2972
    }
2973
2974
    /**
2975
     * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the
2976
     * number of entities in the identity map.
2977
     *
2978
     * @return integer
2979
     */
2980 1
    public function size()
2981
    {
2982 1
        $countArray = array_map('count', $this->identityMap);
2983
2984 1
        return array_sum($countArray);
2985
    }
2986
2987
    /**
2988
     * Gets the EntityPersister for an Entity.
2989
     *
2990
     * @param string $entityName The name of the Entity.
2991
     *
2992
     * @return \Doctrine\ORM\Persisters\Entity\EntityPersister
2993
     */
2994 1081
    public function getEntityPersister($entityName)
2995
    {
2996 1081
        if (isset($this->persisters[$entityName])) {
2997 853
            return $this->persisters[$entityName];
2998
        }
2999
3000 1081
        $class = $this->em->getClassMetadata($entityName);
3001
3002
        switch (true) {
3003 1081
            case ($class->isInheritanceTypeNone()):
3004 1042
                $persister = new BasicEntityPersister($this->em, $class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
3005 1042
                break;
3006
3007 363
            case ($class->isInheritanceTypeSingleTable()):
3008 215
                $persister = new SingleTablePersister($this->em, $class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
3009 215
                break;
3010
3011 341
            case ($class->isInheritanceTypeJoined()):
3012 341
                $persister = new JoinedSubclassPersister($this->em, $class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
3013 341
                break;
3014
3015
            default:
3016
                throw new \RuntimeException('No persister found for entity.');
3017
        }
3018
3019 1081
        if ($this->hasCache && $class->cache !== null) {
0 ignored issues
show
Bug introduced by
Accessing cache on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3020 122
            $persister = $this->em->getConfiguration()
3021 122
                ->getSecondLevelCacheConfiguration()
3022 122
                ->getCacheFactory()
3023 122
                ->buildCachedEntityPersister($this->em, $persister, $class);
3024
        }
3025
3026 1081
        $this->persisters[$entityName] = $persister;
3027
3028 1081
        return $this->persisters[$entityName];
3029
    }
3030
3031
    /**
3032
     * Gets a collection persister for a collection-valued association.
3033
     *
3034
     * @param array $association
3035
     *
3036
     * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister
3037
     */
3038 572
    public function getCollectionPersister(array $association)
3039
    {
3040 572
        $role = isset($association['cache'])
3041 78
            ? $association['sourceEntity'] . '::' . $association['fieldName']
3042 572
            : $association['type'];
3043
3044 572
        if (isset($this->collectionPersisters[$role])) {
3045 451
            return $this->collectionPersisters[$role];
3046
        }
3047
3048 572
        $persister = ClassMetadata::ONE_TO_MANY === $association['type']
3049 406
            ? new OneToManyPersister($this->em)
3050 572
            : new ManyToManyPersister($this->em);
3051
3052 572
        if ($this->hasCache && isset($association['cache'])) {
3053 77
            $persister = $this->em->getConfiguration()
3054 77
                ->getSecondLevelCacheConfiguration()
3055 77
                ->getCacheFactory()
3056 77
                ->buildCachedCollectionPersister($this->em, $persister, $association);
3057
        }
3058
3059 572
        $this->collectionPersisters[$role] = $persister;
3060
3061 572
        return $this->collectionPersisters[$role];
3062
    }
3063
3064
    /**
3065
     * INTERNAL:
3066
     * Registers an entity as managed.
3067
     *
3068
     * @param object $entity The entity.
3069
     * @param array  $id     The identifier values.
3070
     * @param array  $data   The original entity data.
3071
     *
3072
     * @return void
3073
     */
3074 206
    public function registerManaged($entity, array $id, array $data)
3075
    {
3076 206
        $oid = spl_object_hash($entity);
3077
3078 206
        $this->entityIdentifiers[$oid]  = $id;
3079 206
        $this->entityStates[$oid]       = self::STATE_MANAGED;
3080 206
        $this->originalEntityData[$oid] = $data;
3081
3082 206
        $this->addToIdentityMap($entity);
3083
3084 200
        if ($entity instanceof NotifyPropertyChanged && ( ! $entity instanceof Proxy || $entity->__isInitialized())) {
3085 2
            $entity->addPropertyChangedListener($this);
3086
        }
3087 200
    }
3088
3089
    /**
3090
     * INTERNAL:
3091
     * Clears the property changeset of the entity with the given OID.
3092
     *
3093
     * @param string $oid The entity's OID.
3094
     *
3095
     * @return void
3096
     */
3097
    public function clearEntityChangeSet($oid)
3098
    {
3099
        $this->entityChangeSets[$oid] = array();
3100
    }
3101
3102
    /* PropertyChangedListener implementation */
3103
3104
    /**
3105
     * Notifies this UnitOfWork of a property change in an entity.
3106
     *
3107
     * @param object $entity       The entity that owns the property.
3108
     * @param string $propertyName The name of the property that changed.
3109
     * @param mixed  $oldValue     The old value of the property.
3110
     * @param mixed  $newValue     The new value of the property.
3111
     *
3112
     * @return void
3113
     */
3114 3
    public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
3115
    {
3116 3
        $oid   = spl_object_hash($entity);
3117 3
        $class = $this->em->getClassMetadata(get_class($entity));
3118
3119 3
        $isAssocField = isset($class->associationMappings[$propertyName]);
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3120
3121 3
        if ( ! $isAssocField && ! isset($class->fieldMappings[$propertyName])) {
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3122 1
            return; // ignore non-persistent fields
3123
        }
3124
3125
        // Update changeset and mark entity for synchronization
3126 3
        $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
3127
3128 3
        if ( ! isset($this->scheduledForSynchronization[$class->rootEntityName][$oid])) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3129 3
            $this->scheduleForDirtyCheck($entity);
3130
        }
3131 3
    }
3132
3133
    /**
3134
     * Gets the currently scheduled entity insertions in this UnitOfWork.
3135
     *
3136
     * @return array
3137
     */
3138 2
    public function getScheduledEntityInsertions()
3139
    {
3140 2
        return $this->entityInsertions;
3141
    }
3142
3143
    /**
3144
     * Gets the currently scheduled entity updates in this UnitOfWork.
3145
     *
3146
     * @return array
3147
     */
3148 2
    public function getScheduledEntityUpdates()
3149
    {
3150 2
        return $this->entityUpdates;
3151
    }
3152
3153
    /**
3154
     * Gets the currently scheduled entity deletions in this UnitOfWork.
3155
     *
3156
     * @return array
3157
     */
3158 1
    public function getScheduledEntityDeletions()
3159
    {
3160 1
        return $this->entityDeletions;
3161
    }
3162
3163
    /**
3164
     * Gets the currently scheduled complete collection deletions
3165
     *
3166
     * @return array
3167
     */
3168 1
    public function getScheduledCollectionDeletions()
3169
    {
3170 1
        return $this->collectionDeletions;
3171
    }
3172
3173
    /**
3174
     * Gets the currently scheduled collection inserts, updates and deletes.
3175
     *
3176
     * @return array
3177
     */
3178
    public function getScheduledCollectionUpdates()
3179
    {
3180
        return $this->collectionUpdates;
3181
    }
3182
3183
    /**
3184
     * Helper method to initialize a lazy loading proxy or persistent collection.
3185
     *
3186
     * @param object $obj
3187
     *
3188
     * @return void
3189
     */
3190 2
    public function initializeObject($obj)
3191
    {
3192 2
        if ($obj instanceof Proxy) {
3193 1
            $obj->__load();
3194
3195 1
            return;
3196
        }
3197
3198 1
        if ($obj instanceof PersistentCollection) {
3199 1
            $obj->initialize();
3200
        }
3201 1
    }
3202
3203
    /**
3204
     * Helper method to show an object as string.
3205
     *
3206
     * @param object $obj
3207
     *
3208
     * @return string
3209
     */
3210 1
    private static function objToStr($obj)
3211
    {
3212 1
        return method_exists($obj, '__toString') ? (string) $obj : get_class($obj).'@'.spl_object_hash($obj);
3213
    }
3214
3215
    /**
3216
     * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit().
3217
     *
3218
     * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information
3219
     * on this object that might be necessary to perform a correct update.
3220
     *
3221
     * @param object $object
3222
     *
3223
     * @return void
3224
     *
3225
     * @throws ORMInvalidArgumentException
3226
     */
3227 6
    public function markReadOnly($object)
3228
    {
3229 6
        if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
3230 1
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3231
        }
3232
3233 5
        $this->readOnlyObjects[spl_object_hash($object)] = true;
3234 5
    }
3235
3236
    /**
3237
     * Is this entity read only?
3238
     *
3239
     * @param object $object
3240
     *
3241
     * @return bool
3242
     *
3243
     * @throws ORMInvalidArgumentException
3244
     */
3245 3
    public function isReadOnly($object)
3246
    {
3247 3
        if ( ! is_object($object)) {
3248
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3249
        }
3250
3251 3
        return isset($this->readOnlyObjects[spl_object_hash($object)]);
3252
    }
3253
3254
    /**
3255
     * Perform whatever processing is encapsulated here after completion of the transaction.
3256
     */
3257 1012
    private function afterTransactionComplete()
3258
    {
3259
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3260 92
            $persister->afterTransactionComplete();
3261 1012
        });
3262 1012
    }
3263
3264
    /**
3265
     * Perform whatever processing is encapsulated here after completion of the rolled-back.
3266
     */
3267
    private function afterTransactionRolledBack()
3268
    {
3269 11
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3270 3
            $persister->afterTransactionRolledBack();
3271 11
        });
3272 11
    }
3273
3274
    /**
3275
     * Performs an action after the transaction.
3276
     *
3277
     * @param callable $callback
3278
     */
3279 1017
    private function performCallbackOnCachedPersister(callable $callback)
3280
    {
3281 1017
        if ( ! $this->hasCache) {
3282 925
            return;
3283
        }
3284
3285 92
        foreach (array_merge($this->persisters, $this->collectionPersisters) as $persister) {
3286 92
            if ($persister instanceof CachedPersister) {
3287 92
                $callback($persister);
3288
            }
3289
        }
3290 92
    }
3291
3292 1021
    private function dispatchOnFlushEvent()
3293
    {
3294 1021
        if ($this->evm->hasListeners(Events::onFlush)) {
3295 4
            $this->evm->dispatchEvent(Events::onFlush, new OnFlushEventArgs($this->em));
3296
        }
3297 1021
    }
3298
3299 1016
    private function dispatchPostFlushEvent()
3300
    {
3301 1016
        if ($this->evm->hasListeners(Events::postFlush)) {
3302 5
            $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
3303
        }
3304 1015
    }
3305
3306
    /**
3307
     * Verifies if two given entities actually are the same based on identifier comparison
3308
     *
3309
     * @param object $entity1
3310
     * @param object $entity2
3311
     *
3312
     * @return bool
3313
     */
3314 14
    private function isIdentifierEquals($entity1, $entity2)
3315
    {
3316 14
        if ($entity1 === $entity2) {
3317
            return true;
3318
        }
3319
3320 14
        $class = $this->em->getClassMetadata(get_class($entity1));
3321
3322 14
        if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
3323 11
            return false;
3324
        }
3325
3326 3
        $oid1 = spl_object_hash($entity1);
3327 3
        $oid2 = spl_object_hash($entity2);
3328
3329 3
        $id1 = isset($this->entityIdentifiers[$oid1])
3330 3
            ? $this->entityIdentifiers[$oid1]
3331 3
            : $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity1));
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
3332 3
        $id2 = isset($this->entityIdentifiers[$oid2])
3333 3
            ? $this->entityIdentifiers[$oid2]
3334 3
            : $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity2));
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
3335
3336 3
        return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
3337
    }
3338
3339
    /**
3340
     * @param object $entity
3341
     * @param object $managedCopy
3342
     *
3343
     * @throws ORMException
3344
     * @throws OptimisticLockException
3345
     * @throws TransactionRequiredException
3346
     */
3347 31
    private function mergeEntityStateIntoManagedCopy($entity, $managedCopy)
3348
    {
3349 31
        $class = $this->em->getClassMetadata(get_class($entity));
3350
3351 31
        foreach ($this->reflectionPropertiesGetter->getProperties($class->name) as $prop) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3352 31
            $name = $prop->name;
3353
3354 31
            $prop->setAccessible(true);
3355
3356 31
            if ( ! isset($class->associationMappings[$name])) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3357 31
                if ( ! $class->isIdentifier($name)) {
3358 31
                    $prop->setValue($managedCopy, $prop->getValue($entity));
3359
                }
3360
            } else {
3361 29
                $assoc2 = $class->associationMappings[$name];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3362
3363 29
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3364 25
                    $other = $prop->getValue($entity);
3365 25
                    if ($other === null) {
3366 12
                        $prop->setValue($managedCopy, null);
3367
                    } else {
3368 16
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3369
                            // do not merge fields marked lazy that have not been fetched.
3370 4
                            continue;
3371
                        }
3372
3373 12
                        if ( ! $assoc2['isCascadeMerge']) {
3374 6
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3375 3
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3376 3
                                $relatedId   = $targetClass->getIdentifierValues($other);
3377
3378 3
                                if ($targetClass->subClasses) {
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3379 2
                                    $other = $this->em->find($targetClass->name, $relatedId);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3380
                                } else {
3381 1
                                    $other = $this->em->getProxyFactory()->getProxy(
3382 1
                                        $assoc2['targetEntity'],
3383
                                        $relatedId
3384
                                    );
3385 1
                                    $this->registerManaged($other, $relatedId, array());
3386
                                }
3387
                            }
3388
3389 21
                            $prop->setValue($managedCopy, $other);
3390
                        }
3391
                    }
3392
                } else {
3393 17
                    $mergeCol = $prop->getValue($entity);
3394
3395 17
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3396
                        // do not merge fields marked lazy that have not been fetched.
3397
                        // keep the lazy persistent collection of the managed copy.
3398 5
                        continue;
3399
                    }
3400
3401 14
                    $managedCol = $prop->getValue($managedCopy);
3402
3403 14
                    if ( ! $managedCol) {
3404 4
                        $managedCol = new PersistentCollection(
3405 4
                            $this->em,
3406 4
                            $this->em->getClassMetadata($assoc2['targetEntity']),
0 ignored issues
show
Compatibility introduced by
$this->em->getClassMetad...assoc2['targetEntity']) of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
3407 4
                            new ArrayCollection
3408
                        );
3409 4
                        $managedCol->setOwner($managedCopy, $assoc2);
3410 4
                        $prop->setValue($managedCopy, $managedCol);
3411
                    }
3412
3413 14
                    if ($assoc2['isCascadeMerge']) {
3414 9
                        $managedCol->initialize();
3415
3416
                        // clear and set dirty a managed collection if its not also the same collection to merge from.
3417 9
                        if ( ! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
3418 1
                            $managedCol->unwrap()->clear();
3419 1
                            $managedCol->setDirty(true);
3420
3421 1
                            if ($assoc2['isOwningSide']
3422 1
                                && $assoc2['type'] == ClassMetadata::MANY_TO_MANY
3423 1
                                && $class->isChangeTrackingNotify()
3424
                            ) {
3425
                                $this->scheduleForDirtyCheck($managedCopy);
3426
                            }
3427
                        }
3428
                    }
3429
                }
3430
            }
3431
3432 31
            if ($class->isChangeTrackingNotify()) {
3433
                // Just treat all properties as changed, there is no other choice.
3434 31
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
3435
            }
3436
        }
3437 31
    }
3438
3439
    /**
3440
     * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
3441
     * Unit of work able to fire deferred events, related to loading events here.
3442
     *
3443
     * @internal should be called internally from object hydrators
3444
     */
3445 886
    public function hydrationComplete()
3446
    {
3447 886
        $this->hydrationCompleteHandler->hydrationComplete();
3448 886
    }
3449
3450
    /**
3451
     * @param string $entityName
3452
     */
3453 3
    private function clearIdentityMapForEntityName($entityName)
3454
    {
3455 3
        if (! isset($this->identityMap[$entityName])) {
3456
            return;
3457
        }
3458
3459 3
        $visited = [];
3460
3461 3
        foreach ($this->identityMap[$entityName] as $entity) {
3462 3
            $this->doDetach($entity, $visited, false);
3463
        }
3464 3
    }
3465
3466
    /**
3467
     * @param string $entityName
3468
     */
3469 3
    private function clearEntityInsertionsForEntityName($entityName)
3470
    {
3471 3
        foreach ($this->entityInsertions as $hash => $entity) {
3472
            // note: performance optimization - `instanceof` is much faster than a function call
3473 1
            if ($entity instanceof $entityName && get_class($entity) === $entityName) {
3474 1
                unset($this->entityInsertions[$hash]);
3475
            }
3476
        }
3477 3
    }
3478
}
3479