Completed
Pull Request — master (#5841)
by Peter
11:07
created

UnitOfWork::executeExtraUpdates()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
c 0
b 0
f 0
ccs 7
cts 7
cp 1
rs 9.4285
cc 2
eloc 6
nc 2
nop 0
crap 2
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\Persistence\Mapping\RuntimeReflectionService;
23
use Doctrine\DBAL\LockMode;
24
use Doctrine\ORM\Internal\HydrationCompleteHandler;
25
use Doctrine\ORM\Mapping\Reflection\ReflectionPropertiesGetter;
26
use Exception;
27
use InvalidArgumentException;
28
use UnexpectedValueException;
29
30
use Doctrine\Common\Collections\ArrayCollection;
31
use Doctrine\Common\Collections\Collection;
32
use Doctrine\Common\NotifyPropertyChanged;
33
use Doctrine\Common\PropertyChangedListener;
34
use Doctrine\Common\Persistence\ObjectManagerAware;
35
use Doctrine\ORM\Mapping\ClassMetadata;
36
use Doctrine\ORM\Proxy\Proxy;
37
38
use Doctrine\ORM\Event\LifecycleEventArgs;
39
use Doctrine\ORM\Event\PreUpdateEventArgs;
40
use Doctrine\ORM\Event\PreFlushEventArgs;
41
use Doctrine\ORM\Event\OnFlushEventArgs;
42
use Doctrine\ORM\Event\PostFlushEventArgs;
43
use Doctrine\ORM\Event\ListenersInvoker;
44
45
use Doctrine\ORM\Cache\Persister\CachedPersister;
46
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
47
use Doctrine\ORM\Persisters\Entity\SingleTablePersister;
48
use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
49
use Doctrine\ORM\Persisters\Collection\OneToManyPersister;
50
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
51
use Doctrine\ORM\Utility\IdentifierFlattener;
52
53
/**
54
 * The UnitOfWork is responsible for tracking changes to objects during an
55
 * "object-level" transaction and for writing out changes to the database
56
 * in the correct order.
57
 *
58
 * Internal note: This class contains highly performance-sensitive code.
59
 *
60
 * @since       2.0
61
 * @author      Benjamin Eberlei <[email protected]>
62
 * @author      Guilherme Blanco <[email protected]>
63
 * @author      Jonathan Wage <[email protected]>
64
 * @author      Roman Borschel <[email protected]>
65
 * @author      Rob Caiger <[email protected]>
66
 */
67
class UnitOfWork implements PropertyChangedListener
68
{
69
    /**
70
     * An entity is in MANAGED state when its persistence is managed by an EntityManager.
71
     */
72
    const STATE_MANAGED = 1;
73
74
    /**
75
     * An entity is new if it has just been instantiated (i.e. using the "new" operator)
76
     * and is not (yet) managed by an EntityManager.
77
     */
78
    const STATE_NEW = 2;
79
80
    /**
81
     * A detached entity is an instance with persistent state and identity that is not
82
     * (or no longer) associated with an EntityManager (and a UnitOfWork).
83
     */
84
    const STATE_DETACHED = 3;
85
86
    /**
87
     * A removed entity instance is an instance with a persistent identity,
88
     * associated with an EntityManager, whose persistent state will be deleted
89
     * on commit.
90
     */
91
    const STATE_REMOVED = 4;
92
93
    /**
94
     * Hint used to collect all primary keys of associated entities during hydration
95
     * and execute it in a dedicated query afterwards
96
     * @see https://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html?highlight=eager#temporarily-change-fetch-mode-in-dql
97
     */
98
    const HINT_DEFEREAGERLOAD = 'deferEagerLoad';
99
100
    /**
101
     * The identity map that holds references to all managed entities that have
102
     * an identity. The entities are grouped by their class name.
103
     * Since all classes in a hierarchy must share the same identifier set,
104
     * we always take the root class name of the hierarchy.
105
     *
106
     * @var array
107
     */
108
    private $identityMap = array();
109
110
    /**
111
     * Map of all identifiers of managed entities.
112
     * Keys are object ids (spl_object_hash).
113
     *
114
     * @var array
115
     */
116
    private $entityIdentifiers = array();
117
118
    /**
119
     * Map of the original entity data of managed entities.
120
     * Keys are object ids (spl_object_hash). This is used for calculating changesets
121
     * at commit time.
122
     *
123
     * Internal note: Note that PHPs "copy-on-write" behavior helps a lot with memory usage.
124
     *                A value will only really be copied if the value in the entity is modified
125
     *                by the user.
126
     *
127
     * @var array
128
     */
129
    private $originalEntityData = array();
130
131
    /**
132
     * Map of entity changes. Keys are object ids (spl_object_hash).
133
     * Filled at the beginning of a commit of the UnitOfWork and cleaned at the end.
134
     *
135
     * @var array
136
     */
137
    private $entityChangeSets = array();
138
139
    /**
140
     * The (cached) states of any known entities.
141
     * Keys are object ids (spl_object_hash).
142
     *
143
     * @var array
144
     */
145
    private $entityStates = array();
146
147
    /**
148
     * Map of entities that are scheduled for dirty checking at commit time.
149
     * This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT.
150
     * Keys are object ids (spl_object_hash).
151
     *
152
     * @var array
153
     */
154
    private $scheduledForSynchronization = array();
155
156
    /**
157
     * A list of all pending entity insertions.
158
     *
159
     * @var array
160
     */
161
    private $entityInsertions = array();
162
163
    /**
164
     * A list of all pending entity updates.
165
     *
166
     * @var array
167
     */
168
    private $entityUpdates = array();
169
170
    /**
171
     * Any pending extra updates that have been scheduled by persisters.
172
     *
173
     * @var array
174
     */
175
    private $extraUpdates = array();
176
177
    /**
178
     * A list of all pending entity deletions.
179
     *
180
     * @var array
181
     */
182
    private $entityDeletions = array();
183
184
    /**
185
     * All pending collection deletions.
186
     *
187
     * @var array
188
     */
189
    private $collectionDeletions = array();
190
191
    /**
192
     * All pending collection updates.
193
     *
194
     * @var array
195
     */
196
    private $collectionUpdates = array();
197
198
    /**
199
     * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork.
200
     * At the end of the UnitOfWork all these collections will make new snapshots
201
     * of their data.
202
     *
203
     * @var array
204
     */
205
    private $visitedCollections = array();
206
207
    /**
208
     * The EntityManager that "owns" this UnitOfWork instance.
209
     *
210
     * @var EntityManagerInterface
211
     */
212
    private $em;
213
214
    /**
215
     * The entity persister instances used to persist entity instances.
216
     *
217
     * @var array
218
     */
219
    private $persisters = array();
220
221
    /**
222
     * The collection persister instances used to persist collections.
223
     *
224
     * @var array
225
     */
226
    private $collectionPersisters = array();
227
228
    /**
229
     * The EventManager used for dispatching events.
230
     *
231
     * @var \Doctrine\Common\EventManager
232
     */
233
    private $evm;
234
235
    /**
236
     * The ListenersInvoker used for dispatching events.
237
     *
238
     * @var \Doctrine\ORM\Event\ListenersInvoker
239
     */
240
    private $listenersInvoker;
241
242
    /**
243
     * The IdentifierFlattener used for manipulating identifiers
244
     *
245
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
246
     */
247
    private $identifierFlattener;
248
249
    /**
250
     * Orphaned entities that are scheduled for removal.
251
     *
252
     * @var array
253
     */
254
    private $orphanRemovals = array();
255
256
    /**
257
     * Read-Only objects are never evaluated
258
     *
259
     * @var array
260
     */
261
    private $readOnlyObjects = array();
262
263
    /**
264
     * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
265
     *
266
     * @var array
267
     */
268
    private $eagerLoadingEntities = array();
269
270
    /**
271
     * @var boolean
272
     */
273
    protected $hasCache = false;
274
275
    /**
276
     * Helper for handling completion of hydration
277
     *
278
     * @var HydrationCompleteHandler
279
     */
280
    private $hydrationCompleteHandler;
281
282
    /**
283
     * @var ReflectionPropertiesGetter
284
     */
285
    private $reflectionPropertiesGetter;
286
287
    /**
288
     * Initializes a new UnitOfWork instance, bound to the given EntityManager.
289
     *
290
     * @param EntityManagerInterface $em
291
     */
292 2328
    public function __construct(EntityManagerInterface $em)
293
    {
294 2328
        $this->em                         = $em;
295 2328
        $this->evm                        = $em->getEventManager();
296 2328
        $this->listenersInvoker           = new ListenersInvoker($em);
297 2328
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
298 2328
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
299 2328
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
300 2328
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
301 2328
    }
302
303
    /**
304
     * Commits the UnitOfWork, executing all operations that have been postponed
305
     * up to this point. The state of all managed entities will be synchronized with
306
     * the database.
307
     *
308
     * The operations are executed in the following order:
309
     *
310
     * 1) All entity insertions
311
     * 2) All entity updates
312
     * 3) All collection deletions
313
     * 4) All collection updates
314
     * 5) All entity deletions
315
     *
316
     * @param null|object|array $entity
317
     *
318
     * @return void
319
     *
320
     * @throws \Exception
321
     */
322 1014
    public function commit($entity = null)
323
    {
324
        // Raise preFlush
325 1014
        if ($this->evm->hasListeners(Events::preFlush)) {
326 2
            $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em));
327
        }
328
329
        // Compute changes done since last commit.
330 1014
        if ($entity === null) {
331 1006
            $this->computeChangeSets();
332 16
        } elseif (is_object($entity)) {
333 15
            $this->computeSingleEntityChangeSet($entity);
334 1
        } elseif (is_array($entity)) {
335 1
            foreach ($entity as $object) {
336 1
                $this->computeSingleEntityChangeSet($object);
337
            }
338
        }
339
340 1011
        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...
341 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...
342 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...
343 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...
344 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...
345 1011
                $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...
346 25
            $this->dispatchOnFlushEvent();
347 25
            $this->dispatchPostFlushEvent();
348
349 25
            return; // Nothing to do.
350
        }
351
352 1007
        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...
353 16
            foreach ($this->orphanRemovals as $orphan) {
354 16
                $this->remove($orphan);
355
            }
356
        }
357
358 1007
        $this->dispatchOnFlushEvent();
359
360
        // Now we need a commit order to maintain referential integrity
361 1007
        $commitOrder = $this->getCommitOrder();
362
363 1007
        $conn = $this->em->getConnection();
364 1007
        $conn->beginTransaction();
365
366
        try {
367
            // Collection deletions (deletions of complete collections)
368 1007
            foreach ($this->collectionDeletions as $collectionToDelete) {
369 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
370
            }
371
372 1007
            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...
373 1003
                foreach ($commitOrder as $class) {
374 1003
                    $this->executeInserts($class);
375
                }
376
            }
377
378 1006
            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...
379 116
                foreach ($commitOrder as $class) {
380 116
                    $this->executeUpdates($class);
381
                }
382
            }
383
384
            // Extra updates that were requested by persisters.
385 1002
            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...
386 40
                $this->executeExtraUpdates();
387
            }
388
389
            // Collection updates (deleteRows, updateRows, insertRows)
390 1002
            foreach ($this->collectionUpdates as $collectionToUpdate) {
391 529
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
392
            }
393
394
            // Entity deletions come last and need to be in reverse commit order
395 1002
            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...
396 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...
397 63
                    $this->executeDeletions($commitOrder[$i]);
398
                }
399
            }
400
401 1002
            $conn->commit();
402 11
        } catch (Exception $e) {
403 11
            $this->em->close();
404 11
            $conn->rollBack();
405
406 11
            $this->afterTransactionRolledBack();
407
408 11
            throw $e;
409
        }
410
411 1002
        $this->afterTransactionComplete();
412
413
        // Take new snapshots from visited collections
414 1002
        foreach ($this->visitedCollections as $coll) {
415 528
            $coll->takeSnapshot();
416
        }
417
418 1002
        $this->dispatchPostFlushEvent();
419
420
        // Clear up
421 1001
        $this->entityInsertions =
422 1001
        $this->entityUpdates =
423 1001
        $this->entityDeletions =
424 1001
        $this->extraUpdates =
425 1001
        $this->entityChangeSets =
426 1001
        $this->collectionUpdates =
427 1001
        $this->collectionDeletions =
428 1001
        $this->visitedCollections =
429 1001
        $this->scheduledForSynchronization =
430 1001
        $this->orphanRemovals = array();
431 1001
    }
432
433
    /**
434
     * Computes the changesets of all entities scheduled for insertion.
435
     *
436
     * @return void
437
     */
438 1013
    private function computeScheduleInsertsChangeSets()
439
    {
440 1013
        foreach ($this->entityInsertions as $entity) {
441 1005
            $class = $this->em->getClassMetadata(get_class($entity));
442
443 1005
            $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...
444
        }
445 1011
    }
446
447
    /**
448
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
449
     *
450
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
451
     * 2. Read Only entities are skipped.
452
     * 3. Proxies are skipped.
453
     * 4. Only if entity is properly managed.
454
     *
455
     * @param object $entity
456
     *
457
     * @return void
458
     *
459
     * @throws \InvalidArgumentException
460
     */
461 16
    private function computeSingleEntityChangeSet($entity)
462
    {
463 16
        $state = $this->getEntityState($entity);
464
465 16
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
466 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
467
        }
468
469 15
        $class = $this->em->getClassMetadata(get_class($entity));
470
471 15
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
472 14
            $this->persist($entity);
473
        }
474
475
        // Compute changes for INSERTed entities first. This must always happen even in this case.
476 15
        $this->computeScheduleInsertsChangeSets();
477
478 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...
479
            return;
480
        }
481
482
        // Ignore uninitialized proxy objects
483 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...
484 2
            return;
485
        }
486
487
        // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
488 13
        $oid = spl_object_hash($entity);
489
490 13
        if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
491 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...
492
        }
493 12
    }
494
495
    /**
496
     * Executes any extra updates that have been scheduled.
497
     */
498 40
    private function executeExtraUpdates()
499
    {
500 40
        foreach ($this->extraUpdates as $oid => $update) {
501 40
            list ($entity, $changeset) = $update;
502
503 40
            $this->entityChangeSets[$oid] = $changeset;
504 40
            $this->getEntityPersister(get_class($entity))->update($entity);
505
        }
506
507 40
        $this->extraUpdates = array();
508 40
    }
509
510
    /**
511
     * Gets the changeset for an entity.
512
     *
513
     * @param object $entity
514
     *
515
     * @return array
516
     */
517 1005
    public function & getEntityChangeSet($entity)
518
    {
519 1005
        $oid  = spl_object_hash($entity);
520 1005
        $data = array();
521
522 1005
        if (!isset($this->entityChangeSets[$oid])) {
523 2
            return $data;
524
        }
525
526 1005
        return $this->entityChangeSets[$oid];
527
    }
528
529
    /**
530
     * Computes the changes that happened to a single entity.
531
     *
532
     * Modifies/populates the following properties:
533
     *
534
     * {@link _originalEntityData}
535
     * If the entity is NEW or MANAGED but not yet fully persisted (only has an id)
536
     * then it was not fetched from the database and therefore we have no original
537
     * entity data yet. All of the current entity data is stored as the original entity data.
538
     *
539
     * {@link _entityChangeSets}
540
     * The changes detected on all properties of the entity are stored there.
541
     * A change is a tuple array where the first entry is the old value and the second
542
     * entry is the new value of the property. Changesets are used by persisters
543
     * to INSERT/UPDATE the persistent entity state.
544
     *
545
     * {@link _entityUpdates}
546
     * If the entity is already fully MANAGED (has been fetched from the database before)
547
     * and any changes to its properties are detected, then a reference to the entity is stored
548
     * there to mark it for an update.
549
     *
550
     * {@link _collectionDeletions}
551
     * If a PersistentCollection has been de-referenced in a fully MANAGED entity,
552
     * then this collection is marked for deletion.
553
     *
554
     * @ignore
555
     *
556
     * @internal Don't call from the outside.
557
     *
558
     * @param ClassMetadata $class  The class descriptor of the entity.
559
     * @param object        $entity The entity for which to compute the changes.
560
     *
561
     * @return void
562
     */
563 1015
    public function computeChangeSet(ClassMetadata $class, $entity)
564
    {
565 1015
        $oid = spl_object_hash($entity);
566
567 1015
        if (isset($this->readOnlyObjects[$oid])) {
568 2
            return;
569
        }
570
571 1015
        if ( ! $class->isInheritanceTypeNone()) {
572 306
            $class = $this->em->getClassMetadata(get_class($entity));
573
        }
574
575 1015
        $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...
576
577 1015
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
578 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...
579
        }
580
581 1015
        $actualData = array();
582
583 1015
        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...
584 1015
            $value = $refProp->getValue($entity);
585
586 1015
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
587 775
                if ($value instanceof PersistentCollection) {
588 198
                    if ($value->getOwner() === $entity) {
589 198
                        continue;
590
                    }
591
592 5
                    $value = new ArrayCollection($value->getValues());
593
                }
594
595
                // If $value is not a Collection then use an ArrayCollection.
596 770
                if ( ! $value instanceof Collection) {
597 242
                    $value = new ArrayCollection($value);
598
                }
599
600 770
                $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...
601
602
                // Inject PersistentCollection
603 770
                $value = new PersistentCollection(
604 770
                    $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...
605
                );
606 770
                $value->setOwner($entity, $assoc);
607 770
                $value->setDirty( ! $value->isEmpty());
608
609 770
                $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...
610
611 770
                $actualData[$name] = $value;
612
613 770
                continue;
614
            }
615
616 1015
            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...
617 1015
                $actualData[$name] = $value;
618
            }
619
        }
620
621 1015
        if ( ! isset($this->originalEntityData[$oid])) {
622
            // Entity is either NEW or MANAGED but not yet fully persisted (only has an id).
623
            // These result in an INSERT.
624 1011
            $this->originalEntityData[$oid] = $actualData;
625 1011
            $changeSet = array();
626
627 1011
            foreach ($actualData as $propName => $actualValue) {
628 996
                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...
629 945
                    $changeSet[$propName] = array(null, $actualValue);
630
631 945
                    continue;
632
                }
633
634 892
                $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...
635
636 892
                if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
637 892
                    $changeSet[$propName] = array(null, $actualValue);
638
                }
639
            }
640
641 1011
            $this->entityChangeSets[$oid] = $changeSet;
642
        } else {
643
            // Entity is "fully" MANAGED: it was already fully persisted before
644
            // and we have a copy of the original data
645 264
            $originalData           = $this->originalEntityData[$oid];
646 264
            $isChangeTrackingNotify = $class->isChangeTrackingNotify();
647 264
            $changeSet              = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid]))
648
                ? $this->entityChangeSets[$oid]
649 264
                : array();
650
651 264
            foreach ($actualData as $propName => $actualValue) {
652
                // skip field, its a partially omitted one!
653 249
                if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) {
654 8
                    continue;
655
                }
656
657 249
                $orgValue = $originalData[$propName];
658
659
                // skip if value haven't changed
660 249
                if ($orgValue === $actualValue) {
661 232
                    continue;
662
                }
663
664
                // skip if value haven't changed
665 114
                if ($actualValue instanceof DoctrineValueObject && $actualValue->equals($orgValue)) {
666 1
                    continue;
667
                }
668
669
                // if regular field
670 113
                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...
671 59
                    if ($isChangeTrackingNotify) {
672
                        continue;
673
                    }
674
675 59
                    $changeSet[$propName] = array($orgValue, $actualValue);
676
677 59
                    continue;
678
                }
679
680 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...
681
682
                // Persistent collection was exchanged with the "originally"
683
                // created one. This can only mean it was cloned and replaced
684
                // on another entity.
685 58
                if ($actualValue instanceof PersistentCollection) {
686 8
                    $owner = $actualValue->getOwner();
687 8
                    if ($owner === null) { // cloned
688
                        $actualValue->setOwner($entity, $assoc);
689 8
                    } else if ($owner !== $entity) { // no clone, we have to fix
690
                        if (!$actualValue->isInitialized()) {
691
                            $actualValue->initialize(); // we have to do this otherwise the cols share state
692
                        }
693
                        $newValue = clone $actualValue;
694
                        $newValue->setOwner($entity, $assoc);
695
                        $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...
696
                    }
697
                }
698
699 58
                if ($orgValue instanceof PersistentCollection) {
700
                    // A PersistentCollection was de-referenced, so delete it.
701 8
                    $coid = spl_object_hash($orgValue);
702
703 8
                    if (isset($this->collectionDeletions[$coid])) {
704
                        continue;
705
                    }
706
707 8
                    $this->collectionDeletions[$coid] = $orgValue;
708 8
                    $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored.
709
710 8
                    continue;
711
                }
712
713 50
                if ($assoc['type'] & ClassMetadata::TO_ONE) {
714 49
                    if ($assoc['isOwningSide']) {
715 21
                        $changeSet[$propName] = array($orgValue, $actualValue);
716
                    }
717
718 49
                    if ($orgValue !== null && $assoc['orphanRemoval']) {
719 50
                        $this->scheduleOrphanRemoval($orgValue);
720
                    }
721
                }
722
            }
723
724 264
            if ($changeSet) {
725 86
                $this->entityChangeSets[$oid]   = $changeSet;
726 86
                $this->originalEntityData[$oid] = $actualData;
727 86
                $this->entityUpdates[$oid]      = $entity;
728
            }
729
        }
730
731
        // Look for changes in associations of the entity
732 1015
        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...
733 892
            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...
734 638
                continue;
735
            }
736
737 863
            $this->computeAssociationChanges($assoc, $val);
738
739 855
            if ( ! isset($this->entityChangeSets[$oid]) &&
740 855
                $assoc['isOwningSide'] &&
741 855
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
742 855
                $val instanceof PersistentCollection &&
743 855
                $val->isDirty()) {
744
745 35
                $this->entityChangeSets[$oid]   = array();
746 35
                $this->originalEntityData[$oid] = $actualData;
747 855
                $this->entityUpdates[$oid]      = $entity;
748
            }
749
        }
750 1007
    }
751
752
    /**
753
     * Computes all the changes that have been done to entities and collections
754
     * since the last commit and stores these changes in the _entityChangeSet map
755
     * temporarily for access by the persisters, until the UoW commit is finished.
756
     *
757
     * @return void
758
     */
759 1006
    public function computeChangeSets()
760
    {
761
        // Compute changes for INSERTed entities first. This must always happen.
762 1006
        $this->computeScheduleInsertsChangeSets();
763
764
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
765 1004
        foreach ($this->identityMap as $className => $entities) {
766 445
            $class = $this->em->getClassMetadata($className);
767
768
            // Skip class if instances are read-only
769 445
            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...
770 1
                continue;
771
            }
772
773
            // If change tracking is explicit or happens through notification, then only compute
774
            // changes on entities of that type that are explicitly marked for synchronization.
775
            switch (true) {
776 444
                case ($class->isChangeTrackingDeferredImplicit()):
777 442
                    $entitiesToProcess = $entities;
778 442
                    break;
779
780 3
                case (isset($this->scheduledForSynchronization[$className])):
781 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
782 3
                    break;
783
784
                default:
785 1
                    $entitiesToProcess = array();
786
787
            }
788
789 444
            foreach ($entitiesToProcess as $entity) {
790
                // Ignore uninitialized proxy objects
791 424
                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...
792 34
                    continue;
793
                }
794
795
                // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
796 423
                $oid = spl_object_hash($entity);
797
798 423
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
799 444
                    $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...
800
                }
801
            }
802
        }
803 1004
    }
804
805
    /**
806
     * Computes the changes of an association.
807
     *
808
     * @param array $assoc The association mapping.
809
     * @param mixed $value The value of the association.
810
     *
811
     * @throws ORMInvalidArgumentException
812
     * @throws ORMException
813
     *
814
     * @return void
815
     */
816 863
    private function computeAssociationChanges($assoc, $value)
817
    {
818 863
        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...
819 27
            return;
820
        }
821
822 862
        if ($value instanceof PersistentCollection && $value->isDirty()) {
823 531
            $coid = spl_object_hash($value);
824
825 531
            $this->collectionUpdates[$coid] = $value;
826 531
            $this->visitedCollections[$coid] = $value;
827
        }
828
829
        // Look through the entities, and in any of their associations,
830
        // for transient (new) entities, recursively. ("Persistence by reachability")
831
        // Unwrap. Uninitialized collections will simply be empty.
832 862
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
833 862
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
834
835 862
        foreach ($unwrappedValue as $key => $entry) {
836 720
            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...
837 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...
838
            }
839
840 714
            $state = $this->getEntityState($entry, self::STATE_NEW);
841
842 714
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
843
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
844
            }
845
846
            switch ($state) {
847 714
                case self::STATE_NEW:
848 39
                    if ( ! $assoc['isCascadePersist']) {
849 4
                        throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
850
                    }
851
852 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...
853 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...
854 35
                    break;
855
856 708
                case self::STATE_REMOVED:
857
                    // Consume the $value as array (it's either an array or an ArrayAccess)
858
                    // and remove the element from Collection.
859 4
                    if ($assoc['type'] & ClassMetadata::TO_MANY) {
860 3
                        unset($value[$key]);
861
                    }
862 4
                    break;
863
864 708
                case self::STATE_DETACHED:
865
                    // Can actually not happen right now as we assume STATE_NEW,
866
                    // so the exception will be raised from the DBAL layer (constraint violation).
867
                    throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
868
                    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...
869
870 711
                default:
871
                    // MANAGED associated entities are already taken into account
872
                    // during changeset calculation anyway, since they are in the identity map.
873
            }
874
        }
875 854
    }
876
877
    /**
878
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
879
     * @param object                              $entity
880
     *
881
     * @return void
882
     */
883 1023
    private function persistNew($class, $entity)
884
    {
885 1023
        $oid    = spl_object_hash($entity);
886 1023
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
887
888 1023
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
889 139
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
890
        }
891
892 1023
        $idGen = $class->idGenerator;
893
894 1023
        if ( ! $idGen->isPostInsertGenerator()) {
895 260
            $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...
896
897 260
            if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
898 1
                $idValue = array($class->identifier[0] => $idValue);
899
900 1
                $class->setIdentifierValues($entity, $idValue);
901
            }
902
903 260
            $this->entityIdentifiers[$oid] = $idValue;
904
        }
905
906 1023
        $this->entityStates[$oid] = self::STATE_MANAGED;
907
908 1023
        $this->scheduleForInsert($entity);
909 1023
    }
910
911
    /**
912
     * INTERNAL:
913
     * Computes the changeset of an individual entity, independently of the
914
     * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
915
     *
916
     * The passed entity must be a managed entity. If the entity already has a change set
917
     * because this method is invoked during a commit cycle then the change sets are added.
918
     * whereby changes detected in this method prevail.
919
     *
920
     * @ignore
921
     *
922
     * @param ClassMetadata $class  The class descriptor of the entity.
923
     * @param object        $entity The entity for which to (re)calculate the change set.
924
     *
925
     * @return void
926
     *
927
     * @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
928
     */
929 16
    public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
930
    {
931 16
        $oid = spl_object_hash($entity);
932
933 16
        if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
934
            throw ORMInvalidArgumentException::entityNotManaged($entity);
935
        }
936
937
        // skip if change tracking is "NOTIFY"
938 16
        if ($class->isChangeTrackingNotify()) {
939
            return;
940
        }
941
942 16
        if ( ! $class->isInheritanceTypeNone()) {
943 3
            $class = $this->em->getClassMetadata(get_class($entity));
944
        }
945
946 16
        $actualData = array();
947
948 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...
949 16
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
950 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...
951 16
                && ! $class->isCollectionValuedAssociation($name)) {
952 16
                $actualData[$name] = $refProp->getValue($entity);
953
            }
954
        }
955
956 16
        if ( ! isset($this->originalEntityData[$oid])) {
957
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
958
        }
959
960 16
        $originalData = $this->originalEntityData[$oid];
961 16
        $changeSet = array();
962
963 16
        foreach ($actualData as $propName => $actualValue) {
964 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
965
966 16
            if ($orgValue !== $actualValue) {
967 16
                $changeSet[$propName] = array($orgValue, $actualValue);
968
            }
969
        }
970
971 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...
972 7
            if (isset($this->entityChangeSets[$oid])) {
973 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
974 1
            } else if ( ! isset($this->entityInsertions[$oid])) {
975 1
                $this->entityChangeSets[$oid] = $changeSet;
976 1
                $this->entityUpdates[$oid]    = $entity;
977
            }
978 7
            $this->originalEntityData[$oid] = $actualData;
979
        }
980 16
    }
981
982
    /**
983
     * Executes all entity insertions for entities of the specified type.
984
     *
985
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
986
     *
987
     * @return void
988
     */
989 1003
    private function executeInserts($class)
990
    {
991 1003
        $entities   = array();
992 1003
        $className  = $class->name;
993 1003
        $persister  = $this->getEntityPersister($className);
994 1003
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
995
996 1003
        foreach ($this->entityInsertions as $oid => $entity) {
997
998 1003
            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...
999 853
                continue;
1000
            }
1001
1002 1003
            $persister->addInsert($entity);
1003
1004 1003
            unset($this->entityInsertions[$oid]);
1005
1006 1003
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1007 1003
                $entities[] = $entity;
1008
            }
1009
        }
1010
1011 1003
        $postInsertIds = $persister->executeInserts();
1012
1013 1003
        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...
1014
            // Persister returned post-insert IDs
1015 920
            foreach ($postInsertIds as $postInsertId) {
1016 920
                $id      = $postInsertId['generatedId'];
1017 920
                $entity  = $postInsertId['entity'];
1018 920
                $oid     = spl_object_hash($entity);
1019 920
                $idField = $class->identifier[0];
1020
1021 920
                $class->reflFields[$idField]->setValue($entity, $id);
1022
1023 920
                $this->entityIdentifiers[$oid] = array($idField => $id);
1024 920
                $this->entityStates[$oid] = self::STATE_MANAGED;
1025 920
                $this->originalEntityData[$oid][$idField] = $id;
1026
1027 920
                $this->addToIdentityMap($entity);
1028
            }
1029
        }
1030
1031 1003
        foreach ($entities as $entity) {
1032 135
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1033
        }
1034 1003
    }
1035
1036
    /**
1037
     * Executes all entity updates for entities of the specified type.
1038
     *
1039
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1040
     *
1041
     * @return void
1042
     */
1043 116
    private function executeUpdates($class)
1044
    {
1045 116
        $className          = $class->name;
1046 116
        $persister          = $this->getEntityPersister($className);
1047 116
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1048 116
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1049
1050 116
        foreach ($this->entityUpdates as $oid => $entity) {
1051 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...
1052 74
                continue;
1053
            }
1054
1055 116
            if ($preUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1056 13
                $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->getEntityChangeSet($entity)), $preUpdateInvoke);
1057
1058 13
                $this->recomputeSingleEntityChangeSet($class, $entity);
1059
            }
1060
1061 116
            if ( ! empty($this->entityChangeSets[$oid])) {
1062 82
                $persister->update($entity);
1063
            }
1064
1065 112
            unset($this->entityUpdates[$oid]);
1066
1067 112
            if ($postUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1068 112
                $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new LifecycleEventArgs($entity, $this->em), $postUpdateInvoke);
1069
            }
1070
        }
1071 112
    }
1072
1073
    /**
1074
     * Executes all entity deletions for entities of the specified type.
1075
     *
1076
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1077
     *
1078
     * @return void
1079
     */
1080 63
    private function executeDeletions($class)
1081
    {
1082 63
        $className  = $class->name;
1083 63
        $persister  = $this->getEntityPersister($className);
1084 63
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove);
1085
1086 63
        foreach ($this->entityDeletions as $oid => $entity) {
1087 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...
1088 26
                continue;
1089
            }
1090
1091 63
            $persister->delete($entity);
1092
1093
            unset(
1094 63
                $this->entityDeletions[$oid],
1095 63
                $this->entityIdentifiers[$oid],
1096 63
                $this->originalEntityData[$oid],
1097 63
                $this->entityStates[$oid]
1098
            );
1099
1100
            // Entity with this $oid after deletion treated as NEW, even if the $oid
1101
            // is obtained by a new entity because the old one went out of scope.
1102
            //$this->entityStates[$oid] = self::STATE_NEW;
1103 63
            if ( ! $class->isIdentifierNatural()) {
1104 53
                $class->reflFields[$class->identifier[0]]->setValue($entity, null);
1105
            }
1106
1107 63
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1108 63
                $this->listenersInvoker->invoke($class, Events::postRemove, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1109
            }
1110
        }
1111 62
    }
1112
1113
    /**
1114
     * Gets the commit order.
1115
     *
1116
     * @param array|null $entityChangeSet
1117
     *
1118
     * @return array
1119
     */
1120 1007
    private function getCommitOrder(array $entityChangeSet = null)
1121
    {
1122 1007
        if ($entityChangeSet === null) {
1123 1007
            $entityChangeSet = array_merge($this->entityInsertions, $this->entityUpdates, $this->entityDeletions);
1124
        }
1125
1126 1007
        $calc = $this->getCommitOrderCalculator();
1127
1128
        // See if there are any new classes in the changeset, that are not in the
1129
        // commit order graph yet (don't have a node).
1130
        // We have to inspect changeSet to be able to correctly build dependencies.
1131
        // It is not possible to use IdentityMap here because post inserted ids
1132
        // are not yet available.
1133 1007
        $newNodes = array();
1134
1135 1007
        foreach ($entityChangeSet as $entity) {
1136 1007
            $class = $this->em->getClassMetadata(get_class($entity));
1137
1138 1007
            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...
1139 623
                continue;
1140
            }
1141
1142 1007
            $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...
1143
1144 1007
            $newNodes[] = $class;
1145
        }
1146
1147
        // Calculate dependencies for new nodes
1148 1007
        while ($class = array_pop($newNodes)) {
1149 1007
            foreach ($class->associationMappings as $assoc) {
1150 884
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1151 844
                    continue;
1152
                }
1153
1154 837
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1155
1156 837
                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...
1157 648
                    $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...
1158
1159 648
                    $newNodes[] = $targetClass;
1160
                }
1161
1162 837
                $joinColumns = reset($assoc['joinColumns']);
1163 837
                $isNullable  = isset($joinColumns['nullable']) ? $joinColumns['nullable'] : false;
1164
1165 837
                $calc->addDependency($targetClass->name, $class->name, $isNullable ? 0 : 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...
1166
1167
                // If the target class has mapped subclasses, these share the same dependency.
1168 837
                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...
1169 830
                    continue;
1170
                }
1171
1172 217
                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...
1173 217
                    $targetSubClass = $this->em->getClassMetadata($subClassName);
1174
1175 217
                    if ( ! $calc->hasNode($subClassName)) {
1176 189
                        $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...
1177
1178 189
                        $newNodes[] = $targetSubClass;
1179
                    }
1180
1181 217
                    $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...
1182
                }
1183
            }
1184
        }
1185
1186 1007
        return $calc->sort();
1187
    }
1188
1189
    /**
1190
     * Schedules an entity for insertion into the database.
1191
     * If the entity already has an identifier, it will be added to the identity map.
1192
     *
1193
     * @param object $entity The entity to schedule for insertion.
1194
     *
1195
     * @return void
1196
     *
1197
     * @throws ORMInvalidArgumentException
1198
     * @throws \InvalidArgumentException
1199
     */
1200 1024
    public function scheduleForInsert($entity)
1201
    {
1202 1024
        $oid = spl_object_hash($entity);
1203
1204 1024
        if (isset($this->entityUpdates[$oid])) {
1205
            throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion.");
1206
        }
1207
1208 1024
        if (isset($this->entityDeletions[$oid])) {
1209 1
            throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
1210
        }
1211 1024
        if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) {
1212 1
            throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
1213
        }
1214
1215 1024
        if (isset($this->entityInsertions[$oid])) {
1216 1
            throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
1217
        }
1218
1219 1024
        $this->entityInsertions[$oid] = $entity;
1220
1221 1024
        if (isset($this->entityIdentifiers[$oid])) {
1222 260
            $this->addToIdentityMap($entity);
1223
        }
1224
1225 1024
        if ($entity instanceof NotifyPropertyChanged) {
1226 5
            $entity->addPropertyChangedListener($this);
1227
        }
1228 1024
    }
1229
1230
    /**
1231
     * Checks whether an entity is scheduled for insertion.
1232
     *
1233
     * @param object $entity
1234
     *
1235
     * @return boolean
1236
     */
1237 628
    public function isScheduledForInsert($entity)
1238
    {
1239 628
        return isset($this->entityInsertions[spl_object_hash($entity)]);
1240
    }
1241
1242
    /**
1243
     * Schedules an entity for being updated.
1244
     *
1245
     * @param object $entity The entity to schedule for being updated.
1246
     *
1247
     * @return void
1248
     *
1249
     * @throws ORMInvalidArgumentException
1250
     */
1251 1
    public function scheduleForUpdate($entity)
1252
    {
1253 1
        $oid = spl_object_hash($entity);
1254
1255 1
        if ( ! isset($this->entityIdentifiers[$oid])) {
1256
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update");
1257
        }
1258
1259 1
        if (isset($this->entityDeletions[$oid])) {
1260
            throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update");
1261
        }
1262
1263 1
        if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) {
1264 1
            $this->entityUpdates[$oid] = $entity;
1265
        }
1266 1
    }
1267
1268
    /**
1269
     * INTERNAL:
1270
     * Schedules an extra update that will be executed immediately after the
1271
     * regular entity updates within the currently running commit cycle.
1272
     *
1273
     * Extra updates for entities are stored as (entity, changeset) tuples.
1274
     *
1275
     * @ignore
1276
     *
1277
     * @param object $entity    The entity for which to schedule an extra update.
1278
     * @param array  $changeset The changeset of the entity (what to update).
1279
     *
1280
     * @return void
1281
     */
1282 40
    public function scheduleExtraUpdate($entity, array $changeset)
1283
    {
1284 40
        $oid         = spl_object_hash($entity);
1285 40
        $extraUpdate = array($entity, $changeset);
1286
1287 40
        if (isset($this->extraUpdates[$oid])) {
1288 1
            list(, $changeset2) = $this->extraUpdates[$oid];
1289
1290 1
            $extraUpdate = array($entity, $changeset + $changeset2);
1291
        }
1292
1293 40
        $this->extraUpdates[$oid] = $extraUpdate;
1294 40
    }
1295
1296
    /**
1297
     * Checks whether an entity is registered as dirty in the unit of work.
1298
     * Note: Is not very useful currently as dirty entities are only registered
1299
     * at commit time.
1300
     *
1301
     * @param object $entity
1302
     *
1303
     * @return boolean
1304
     */
1305
    public function isScheduledForUpdate($entity)
1306
    {
1307
        return isset($this->entityUpdates[spl_object_hash($entity)]);
1308
    }
1309
1310
    /**
1311
     * Checks whether an entity is registered to be checked in the unit of work.
1312
     *
1313
     * @param object $entity
1314
     *
1315
     * @return boolean
1316
     */
1317 1
    public function isScheduledForDirtyCheck($entity)
1318
    {
1319 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...
1320
1321 1
        return isset($this->scheduledForSynchronization[$rootEntityName][spl_object_hash($entity)]);
1322
    }
1323
1324
    /**
1325
     * INTERNAL:
1326
     * Schedules an entity for deletion.
1327
     *
1328
     * @param object $entity
1329
     *
1330
     * @return void
1331
     */
1332 66
    public function scheduleForDelete($entity)
1333
    {
1334 66
        $oid = spl_object_hash($entity);
1335
1336 66
        if (isset($this->entityInsertions[$oid])) {
1337 1
            if ($this->isInIdentityMap($entity)) {
1338
                $this->removeFromIdentityMap($entity);
1339
            }
1340
1341 1
            unset($this->entityInsertions[$oid], $this->entityStates[$oid]);
1342
1343 1
            return; // entity has not been persisted yet, so nothing more to do.
1344
        }
1345
1346 66
        if ( ! $this->isInIdentityMap($entity)) {
1347 1
            return;
1348
        }
1349
1350 65
        $this->removeFromIdentityMap($entity);
1351
1352 65
        if (isset($this->entityUpdates[$oid])) {
1353 2
            unset($this->entityUpdates[$oid]);
1354
        }
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 1085
    public function addToIdentityMap($entity)
1407
    {
1408 1085
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1409 1085
        $idHash        = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]);
1410
1411 1085
        if ($idHash === '') {
1412 1
            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 1084
        $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...
1416
1417 1084
        if (isset($this->identityMap[$className][$idHash])) {
1418 78
            return false;
1419
        }
1420
1421 1084
        $this->identityMap[$className][$idHash] = $entity;
1422
1423 1084
        return true;
1424
    }
1425
1426
    /**
1427
     * Gets the state of an entity with regard to the current unit of work.
1428
     *
1429
     * @param object   $entity
1430
     * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED).
1431
     *                         This parameter can be set to improve performance of entity state detection
1432
     *                         by potentially avoiding a database lookup if the distinction between NEW and DETACHED
1433
     *                         is either known or does not matter for the caller of the method.
1434
     *
1435
     * @return int The entity state.
1436
     */
1437 1037
    public function getEntityState($entity, $assume = null)
1438
    {
1439 1037
        $oid = spl_object_hash($entity);
1440
1441 1037
        if (isset($this->entityStates[$oid])) {
1442 781
            return $this->entityStates[$oid];
1443
        }
1444
1445 1031
        if ($assume !== null) {
1446 1027
            return $assume;
1447
        }
1448
1449
        // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known.
1450
        // Note that you can not remember the NEW or DETACHED state in _entityStates since
1451
        // the UoW does not hold references to such objects and the object hash can be reused.
1452
        // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it.
1453 13
        $class = $this->em->getClassMetadata(get_class($entity));
1454 13
        $id    = $class->getIdentifierValues($entity);
1455
1456 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...
1457 5
            return self::STATE_NEW;
1458
        }
1459
1460 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...
1461 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...
1462
        }
1463
1464
        switch (true) {
1465 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...
1466
                // Check for a version field, if available, to avoid a db lookup.
1467 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...
1468 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...
1469
                        ? self::STATE_DETACHED
1470 1
                        : self::STATE_NEW;
1471
                }
1472
1473
                // Last try before db lookup: check the identity map.
1474 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...
1475 1
                    return self::STATE_DETACHED;
1476
                }
1477
1478
                // db lookup
1479 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...
1480
                    return self::STATE_DETACHED;
1481
                }
1482
1483 4
                return self::STATE_NEW;
1484
1485 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...
1486
                // if we have a pre insert generator we can't be sure that having an id
1487
                // really means that the entity exists. We have to verify this through
1488
                // the last resort: a db lookup
1489
1490
                // Last try before db lookup: check the identity map.
1491
                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...
1492
                    return self::STATE_DETACHED;
1493
                }
1494
1495
                // db lookup
1496
                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...
1497
                    return self::STATE_DETACHED;
1498
                }
1499
1500
                return self::STATE_NEW;
1501
1502
            default:
1503 5
                return self::STATE_DETACHED;
1504
        }
1505
    }
1506
1507
    /**
1508
     * INTERNAL:
1509
     * Removes an entity from the identity map. This effectively detaches the
1510
     * entity from the persistence management of Doctrine.
1511
     *
1512
     * @ignore
1513
     *
1514
     * @param object $entity
1515
     *
1516
     * @return boolean
1517
     *
1518
     * @throws ORMInvalidArgumentException
1519
     */
1520 76
    public function removeFromIdentityMap($entity)
1521
    {
1522 76
        $oid           = spl_object_hash($entity);
1523 76
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1524 76
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1525
1526 76
        if ($idHash === '') {
1527
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
1528
        }
1529
1530 76
        $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...
1531
1532 76
        if (isset($this->identityMap[$className][$idHash])) {
1533 76
            unset($this->identityMap[$className][$idHash]);
1534 76
            unset($this->readOnlyObjects[$oid]);
1535
1536
            //$this->entityStates[$oid] = self::STATE_DETACHED;
1537
1538 76
            return true;
1539
        }
1540
1541
        return false;
1542
    }
1543
1544
    /**
1545
     * INTERNAL:
1546
     * Gets an entity in the identity map by its identifier hash.
1547
     *
1548
     * @ignore
1549
     *
1550
     * @param string $idHash
1551
     * @param string $rootClassName
1552
     *
1553
     * @return object
1554
     */
1555
    public function getByIdHash($idHash, $rootClassName)
1556
    {
1557
        return $this->identityMap[$rootClassName][$idHash];
1558
    }
1559
1560
    /**
1561
     * INTERNAL:
1562
     * Tries to get an entity by its identifier hash. If no entity is found for
1563
     * the given hash, FALSE is returned.
1564
     *
1565
     * @ignore
1566
     *
1567
     * @param mixed  $idHash        (must be possible to cast it to string)
1568
     * @param string $rootClassName
1569
     *
1570
     * @return object|bool The found entity or FALSE.
1571
     */
1572 34
    public function tryGetByIdHash($idHash, $rootClassName)
1573
    {
1574 34
        $stringIdHash = (string) $idHash;
1575
1576 34
        if (isset($this->identityMap[$rootClassName][$stringIdHash])) {
1577 34
            return $this->identityMap[$rootClassName][$stringIdHash];
1578
        }
1579
1580 2
        return false;
1581
    }
1582
1583
    /**
1584
     * Checks whether an entity is registered in the identity map of this UnitOfWork.
1585
     *
1586
     * @param object $entity
1587
     *
1588
     * @return boolean
1589
     */
1590 212
    public function isInIdentityMap($entity)
1591
    {
1592 212
        $oid = spl_object_hash($entity);
1593
1594 212
        if ( ! isset($this->entityIdentifiers[$oid])) {
1595 30
            return false;
1596
        }
1597
1598 197
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1599 197
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1600
1601 197
        if ($idHash === '') {
1602
            return false;
1603
        }
1604
1605 197
        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...
1606
    }
1607
1608
    /**
1609
     * INTERNAL:
1610
     * Checks whether an identifier hash exists in the identity map.
1611
     *
1612
     * @ignore
1613
     *
1614
     * @param string $idHash
1615
     * @param string $rootClassName
1616
     *
1617
     * @return boolean
1618
     */
1619
    public function containsIdHash($idHash, $rootClassName)
1620
    {
1621
        return isset($this->identityMap[$rootClassName][$idHash]);
1622
    }
1623
1624
    /**
1625
     * Persists an entity as part of the current unit of work.
1626
     *
1627
     * @param object $entity The entity to persist.
1628
     *
1629
     * @return void
1630
     */
1631 1020
    public function persist($entity)
1632
    {
1633 1020
        $visited = array();
1634
1635 1020
        $this->doPersist($entity, $visited);
1636 1013
    }
1637
1638
    /**
1639
     * Persists an entity as part of the current unit of work.
1640
     *
1641
     * This method is internally called during persist() cascades as it tracks
1642
     * the already visited entities to prevent infinite recursions.
1643
     *
1644
     * @param object $entity  The entity to persist.
1645
     * @param array  $visited The already visited entities.
1646
     *
1647
     * @return void
1648
     *
1649
     * @throws ORMInvalidArgumentException
1650
     * @throws UnexpectedValueException
1651
     */
1652 1020
    private function doPersist($entity, array &$visited)
1653
    {
1654 1020
        $oid = spl_object_hash($entity);
1655
1656 1020
        if (isset($visited[$oid])) {
1657 109
            return; // Prevent infinite recursion
1658
        }
1659
1660 1020
        $visited[$oid] = $entity; // Mark visited
1661
1662 1020
        $class = $this->em->getClassMetadata(get_class($entity));
1663
1664
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1665
        // If we would detect DETACHED here we would throw an exception anyway with the same
1666
        // consequences (not recoverable/programming error), so just assuming NEW here
1667
        // lets us avoid some database lookups for entities with natural identifiers.
1668 1020
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1669
1670
        switch ($entityState) {
1671 1020
            case self::STATE_MANAGED:
1672
                // Nothing to do, except if policy is "deferred explicit"
1673 234
                if ($class->isChangeTrackingDeferredExplicit()) {
1674 2
                    $this->scheduleForDirtyCheck($entity);
1675
                }
1676 234
                break;
1677
1678 1020
            case self::STATE_NEW:
1679 1019
                $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...
1680 1019
                break;
1681
1682 1
            case self::STATE_REMOVED:
1683
                // Entity becomes managed again
1684 1
                unset($this->entityDeletions[$oid]);
1685 1
                $this->addToIdentityMap($entity);
1686
1687 1
                $this->entityStates[$oid] = self::STATE_MANAGED;
1688 1
                break;
1689
1690
            case self::STATE_DETACHED:
1691
                // Can actually not happen right now since we assume STATE_NEW.
1692
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
1693
1694
            default:
1695
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1696
        }
1697
1698 1020
        $this->cascadePersist($entity, $visited);
1699 1013
    }
1700
1701
    /**
1702
     * Deletes an entity as part of the current unit of work.
1703
     *
1704
     * @param object $entity The entity to remove.
1705
     *
1706
     * @return void
1707
     */
1708 65
    public function remove($entity)
1709
    {
1710 65
        $visited = array();
1711
1712 65
        $this->doRemove($entity, $visited);
1713 65
    }
1714
1715
    /**
1716
     * Deletes an entity as part of the current unit of work.
1717
     *
1718
     * This method is internally called during delete() cascades as it tracks
1719
     * the already visited entities to prevent infinite recursions.
1720
     *
1721
     * @param object $entity  The entity to delete.
1722
     * @param array  $visited The map of the already visited entities.
1723
     *
1724
     * @return void
1725
     *
1726
     * @throws ORMInvalidArgumentException If the instance is a detached entity.
1727
     * @throws UnexpectedValueException
1728
     */
1729 65
    private function doRemove($entity, array &$visited)
1730
    {
1731 65
        $oid = spl_object_hash($entity);
1732
1733 65
        if (isset($visited[$oid])) {
1734 1
            return; // Prevent infinite recursion
1735
        }
1736
1737 65
        $visited[$oid] = $entity; // mark visited
1738
1739
        // Cascade first, because scheduleForDelete() removes the entity from the identity map, which
1740
        // can cause problems when a lazy proxy has to be initialized for the cascade operation.
1741 65
        $this->cascadeRemove($entity, $visited);
1742
1743 65
        $class       = $this->em->getClassMetadata(get_class($entity));
1744 65
        $entityState = $this->getEntityState($entity);
1745
1746
        switch ($entityState) {
1747 65
            case self::STATE_NEW:
1748 65
            case self::STATE_REMOVED:
1749
                // nothing to do
1750 2
                break;
1751
1752 65
            case self::STATE_MANAGED:
1753 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...
1754
1755 65
                if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1756 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...
1757
                }
1758
1759 65
                $this->scheduleForDelete($entity);
1760 65
                break;
1761
1762
            case self::STATE_DETACHED:
1763
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1764
            default:
1765
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1766
        }
1767
1768 65
    }
1769
1770
    /**
1771
     * Merges the state of the given detached entity into this UnitOfWork.
1772
     *
1773
     * @param object $entity
1774
     *
1775
     * @return object The managed copy of the entity.
1776
     *
1777
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1778
     *         attribute and the version check against the managed copy fails.
1779
     *
1780
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1781
     */
1782 40
    public function merge($entity)
1783
    {
1784 40
        $visited = array();
1785
1786 40
        return $this->doMerge($entity, $visited);
1787
    }
1788
1789
    /**
1790
     * Executes a merge operation on an entity.
1791
     *
1792
     * @param object      $entity
1793
     * @param array       $visited
1794
     * @param object|null $prevManagedCopy
1795
     * @param array|null  $assoc
1796
     *
1797
     * @return object The managed copy of the entity.
1798
     *
1799
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1800
     *         attribute and the version check against the managed copy fails.
1801
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1802
     * @throws EntityNotFoundException
1803
     */
1804 40
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, $assoc = null)
1805
    {
1806 40
        $oid = spl_object_hash($entity);
1807
1808 40
        if (isset($visited[$oid])) {
1809 4
            $managedCopy = $visited[$oid];
1810
1811 4
            if ($prevManagedCopy !== null) {
1812 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $assoc defined by parameter $assoc on line 1804 can also be of type null; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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...
1813
            }
1814
1815 4
            return $managedCopy;
1816
        }
1817
1818 40
        $class = $this->em->getClassMetadata(get_class($entity));
1819
1820
        // First we assume DETACHED, although it can still be NEW but we can avoid
1821
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1822
        // we need to fetch it from the db anyway in order to merge.
1823
        // MANAGED entities are ignored by the merge operation.
1824 40
        $managedCopy = $entity;
1825
1826 40
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1827
            // Try to look the entity up in the identity map.
1828 39
            $id = $class->getIdentifierValues($entity);
1829
1830
            // If there is no ID, it is actually NEW.
1831 39
            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...
1832 5
                $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...
1833
1834 5
                $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...
1835
            } else {
1836 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...
1837 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...
1838 35
                    : $id;
1839
1840 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 1904 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1841
1842 35
                if ($managedCopy) {
1843
                    // We have the entity in-memory already, just make sure its not removed.
1844 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 1840 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...
1845 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 1840 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...
1846
                    }
1847
                } else {
1848
                    // We need to fetch the managed copy in order to merge.
1849 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...
1850
                }
1851
1852 35
                if ($managedCopy === null) {
1853
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1854
                    // since the managed entity was not found.
1855 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...
1856 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1857 1
                            $class->getName(),
1858 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...
1859
                        );
1860
                    }
1861
1862 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...
1863 1
                    $class->setIdentifierValues($managedCopy, $id);
1864
1865 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...
1866
                }
1867
            }
1868
1869 38
            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 1840 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...
1870 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...
1871 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1872 4
                $entityVersion      = $reflField->getValue($entity);
1873
1874
                // Throw exception if versions don't match.
1875 4
                if ($managedCopyVersion != $entityVersion) {
1876 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1877
                }
1878
            }
1879
1880 37
            $visited[$oid] = $managedCopy; // mark visited
1881
1882 37
            if ($this->isLoaded($entity)) {
1883 30
                if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) {
1884 4
                    $managedCopy->__load();
1885
                }
1886
1887 30
                $this->mergeEntityStateIntoManagedCopy($entity, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1840 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...
1888
            }
1889
1890 37
            if ($class->isChangeTrackingDeferredExplicit()) {
1891
                $this->scheduleForDirtyCheck($entity);
1892
            }
1893
        }
1894
1895 38
        if ($prevManagedCopy !== null) {
1896 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 1840 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...
Bug introduced by
It seems like $assoc defined by parameter $assoc on line 1804 can also be of type null; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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...
1897
        }
1898
1899
        // Mark the managed copy visited as well
1900 38
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1901
1902 38
        $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 1840 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...
1903
1904 38
        return $managedCopy;
1905
    }
1906
1907
    /**
1908
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1909
     *
1910
     * @param object $entity
1911
     *
1912
     * @return bool
1913
     */
1914 38
    private function isLoaded($entity)
1915
    {
1916 38
        return !($entity instanceof Proxy) || $entity->__isInitialized();
1917
    }
1918
1919
    /**
1920
     * Sets/adds associated managed copies into the previous entity's association field
1921
     *
1922
     * @param object $entity
1923
     * @param array  $association
1924
     * @param object $previousManagedCopy
1925
     * @param object $managedCopy
1926
     *
1927
     * @return void
1928
     */
1929 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1930
    {
1931 6
        $assocField = $association['fieldName'];
1932 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1933
1934 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1935 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...
1936
1937 6
            return;
1938
        }
1939
1940 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...
1941 1
        $value[] = $managedCopy;
1942
1943 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1944 1
            $class = $this->em->getClassMetadata(get_class($entity));
1945
1946 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...
1947
        }
1948 1
    }
1949
1950
    /**
1951
     * Detaches an entity from the persistence management. It's persistence will
1952
     * no longer be managed by Doctrine.
1953
     *
1954
     * @param object $entity The entity to detach.
1955
     *
1956
     * @return void
1957
     */
1958 12
    public function detach($entity)
1959
    {
1960 12
        $visited = array();
1961
1962 12
        $this->doDetach($entity, $visited);
1963 12
    }
1964
1965
    /**
1966
     * Executes a detach operation on the given entity.
1967
     *
1968
     * @param object  $entity
1969
     * @param array   $visited
1970
     * @param boolean $noCascade if true, don't cascade detach operation.
1971
     *
1972
     * @return void
1973
     */
1974 14
    private function doDetach($entity, array &$visited, $noCascade = false)
1975
    {
1976 14
        $oid = spl_object_hash($entity);
1977
1978 14
        if (isset($visited[$oid])) {
1979
            return; // Prevent infinite recursion
1980
        }
1981
1982 14
        $visited[$oid] = $entity; // mark visited
1983
1984 14
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
1985 14
            case self::STATE_MANAGED:
1986 12
                if ($this->isInIdentityMap($entity)) {
1987 11
                    $this->removeFromIdentityMap($entity);
1988
                }
1989
1990
                unset(
1991 12
                    $this->entityInsertions[$oid],
1992 12
                    $this->entityUpdates[$oid],
1993 12
                    $this->entityDeletions[$oid],
1994 12
                    $this->entityIdentifiers[$oid],
1995 12
                    $this->entityStates[$oid],
1996 12
                    $this->originalEntityData[$oid]
1997
                );
1998 12
                break;
1999 3
            case self::STATE_NEW:
2000 3
            case self::STATE_DETACHED:
2001 3
                return;
2002
        }
2003
2004 12
        if ( ! $noCascade) {
2005 12
            $this->cascadeDetach($entity, $visited);
2006
        }
2007 12
    }
2008
2009
    /**
2010
     * Refreshes the state of the given entity from the database, overwriting
2011
     * any local, unpersisted changes.
2012
     *
2013
     * @param object $entity The entity to refresh.
2014
     *
2015
     * @return void
2016
     *
2017
     * @throws InvalidArgumentException If the entity is not MANAGED.
2018
     */
2019 17
    public function refresh($entity)
2020
    {
2021 17
        $visited = array();
2022
2023 17
        $this->doRefresh($entity, $visited);
2024 17
    }
2025
2026
    /**
2027
     * Executes a refresh operation on an entity.
2028
     *
2029
     * @param object $entity  The entity to refresh.
2030
     * @param array  $visited The already visited entities during cascades.
2031
     *
2032
     * @return void
2033
     *
2034
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2035
     */
2036 17
    private function doRefresh($entity, array &$visited)
2037
    {
2038 17
        $oid = spl_object_hash($entity);
2039
2040 17
        if (isset($visited[$oid])) {
2041
            return; // Prevent infinite recursion
2042
        }
2043
2044 17
        $visited[$oid] = $entity; // mark visited
2045
2046 17
        $class = $this->em->getClassMetadata(get_class($entity));
2047
2048 17
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2049
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2050
        }
2051
2052 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...
2053 17
            array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2054
            $entity
2055
        );
2056
2057 17
        $this->cascadeRefresh($entity, $visited);
2058 17
    }
2059
2060
    /**
2061
     * Cascades a refresh operation to associated entities.
2062
     *
2063
     * @param object $entity
2064
     * @param array  $visited
2065
     *
2066
     * @return void
2067
     */
2068 17
    private function cascadeRefresh($entity, array &$visited)
2069
    {
2070 17
        $class = $this->em->getClassMetadata(get_class($entity));
2071
2072 17
        $associationMappings = array_filter(
2073 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...
2074
            function ($assoc) { return $assoc['isCascadeRefresh']; }
2075
        );
2076
2077 17
        foreach ($associationMappings as $assoc) {
2078 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...
2079
2080
            switch (true) {
2081 5
                case ($relatedEntities instanceof PersistentCollection):
2082
                    // Unwrap so that foreach() does not initialize
2083 5
                    $relatedEntities = $relatedEntities->unwrap();
2084
                    // break; is commented intentionally!
2085
2086
                case ($relatedEntities instanceof Collection):
2087
                case (is_array($relatedEntities)):
2088 5
                    foreach ($relatedEntities as $relatedEntity) {
2089
                        $this->doRefresh($relatedEntity, $visited);
2090
                    }
2091 5
                    break;
2092
2093
                case ($relatedEntities !== null):
2094
                    $this->doRefresh($relatedEntities, $visited);
2095
                    break;
2096
2097 5
                default:
2098
                    // Do nothing
2099
            }
2100
        }
2101 17
    }
2102
2103
    /**
2104
     * Cascades a detach operation to associated entities.
2105
     *
2106
     * @param object $entity
2107
     * @param array  $visited
2108
     *
2109
     * @return void
2110
     */
2111 12
    private function cascadeDetach($entity, array &$visited)
2112
    {
2113 12
        $class = $this->em->getClassMetadata(get_class($entity));
2114
2115 12
        $associationMappings = array_filter(
2116 12
            $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...
2117
            function ($assoc) { return $assoc['isCascadeDetach']; }
2118
        );
2119
2120 12
        foreach ($associationMappings as $assoc) {
2121 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...
2122
2123
            switch (true) {
2124 3
                case ($relatedEntities instanceof PersistentCollection):
2125
                    // Unwrap so that foreach() does not initialize
2126 2
                    $relatedEntities = $relatedEntities->unwrap();
2127
                    // break; is commented intentionally!
2128
2129
                case ($relatedEntities instanceof Collection):
2130
                case (is_array($relatedEntities)):
2131 3
                    foreach ($relatedEntities as $relatedEntity) {
2132 1
                        $this->doDetach($relatedEntity, $visited);
2133
                    }
2134 3
                    break;
2135
2136
                case ($relatedEntities !== null):
2137
                    $this->doDetach($relatedEntities, $visited);
2138
                    break;
2139
2140 3
                default:
2141
                    // Do nothing
2142
            }
2143
        }
2144 12
    }
2145
2146
    /**
2147
     * Cascades a merge operation to associated entities.
2148
     *
2149
     * @param object $entity
2150
     * @param object $managedCopy
2151
     * @param array  $visited
2152
     *
2153
     * @return void
2154
     */
2155 38
    private function cascadeMerge($entity, $managedCopy, array &$visited)
2156
    {
2157 38
        $class = $this->em->getClassMetadata(get_class($entity));
2158
2159 38
        $associationMappings = array_filter(
2160 38
            $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...
2161
            function ($assoc) { return $assoc['isCascadeMerge']; }
2162
        );
2163
2164 38
        foreach ($associationMappings as $assoc) {
2165 15
            $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...
2166
2167 15
            if ($relatedEntities instanceof Collection) {
2168 9
                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...
2169 1
                    continue;
2170
                }
2171
2172 8
                if ($relatedEntities instanceof PersistentCollection) {
2173
                    // Unwrap so that foreach() does not initialize
2174 5
                    $relatedEntities = $relatedEntities->unwrap();
2175
                }
2176
2177 8
                foreach ($relatedEntities as $relatedEntity) {
2178 8
                    $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
2179
                }
2180 7
            } else if ($relatedEntities !== null) {
2181 14
                $this->doMerge($relatedEntities, $visited, $managedCopy, $assoc);
2182
            }
2183
        }
2184 38
    }
2185
2186
    /**
2187
     * Cascades the save operation to associated entities.
2188
     *
2189
     * @param object $entity
2190
     * @param array  $visited
2191
     *
2192
     * @return void
2193
     */
2194 1020
    private function cascadePersist($entity, array &$visited)
2195
    {
2196 1020
        $class = $this->em->getClassMetadata(get_class($entity));
2197
2198 1020
        $associationMappings = array_filter(
2199 1020
            $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...
2200
            function ($assoc) { return $assoc['isCascadePersist']; }
2201
        );
2202
2203 1020
        foreach ($associationMappings as $assoc) {
2204 649
            $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...
2205
2206
            switch (true) {
2207 649
                case ($relatedEntities instanceof PersistentCollection):
2208
                    // Unwrap so that foreach() does not initialize
2209 21
                    $relatedEntities = $relatedEntities->unwrap();
2210
                    // break; is commented intentionally!
2211
2212
                case ($relatedEntities instanceof Collection):
2213 589
                case (is_array($relatedEntities)):
2214 553
                    if (($assoc['type'] & ClassMetadata::TO_MANY) <= 0) {
2215 3
                        throw ORMInvalidArgumentException::invalidAssociation(
2216 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...
2217
                            $assoc,
2218
                            $relatedEntities
2219
                        );
2220
                    }
2221
2222 550
                    foreach ($relatedEntities as $relatedEntity) {
2223 282
                        $this->doPersist($relatedEntity, $visited);
2224
                    }
2225
2226 550
                    break;
2227
2228 579
                case ($relatedEntities !== null):
2229 246
                    if (! $relatedEntities instanceof $assoc['targetEntity']) {
2230 4
                        throw ORMInvalidArgumentException::invalidAssociation(
2231 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...
2232
                            $assoc,
2233
                            $relatedEntities
2234
                        );
2235
                    }
2236
2237 242
                    $this->doPersist($relatedEntities, $visited);
2238 242
                    break;
2239
2240 643
                default:
2241
                    // Do nothing
2242
            }
2243
        }
2244 1013
    }
2245
2246
    /**
2247
     * Cascades the delete operation to associated entities.
2248
     *
2249
     * @param object $entity
2250
     * @param array  $visited
2251
     *
2252
     * @return void
2253
     */
2254 65
    private function cascadeRemove($entity, array &$visited)
2255
    {
2256 65
        $class = $this->em->getClassMetadata(get_class($entity));
2257
2258 65
        $associationMappings = array_filter(
2259 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...
2260
            function ($assoc) { return $assoc['isCascadeRemove']; }
2261
        );
2262
2263 65
        $entitiesToCascade = array();
2264
2265 65
        foreach ($associationMappings as $assoc) {
2266 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...
2267 6
                $entity->__load();
2268
            }
2269
2270 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...
2271
2272
            switch (true) {
2273 26
                case ($relatedEntities instanceof Collection):
2274 19
                case (is_array($relatedEntities)):
2275
                    // If its a PersistentCollection initialization is intended! No unwrap!
2276 20
                    foreach ($relatedEntities as $relatedEntity) {
2277 10
                        $entitiesToCascade[] = $relatedEntity;
2278
                    }
2279 20
                    break;
2280
2281 19
                case ($relatedEntities !== null):
2282 7
                    $entitiesToCascade[] = $relatedEntities;
2283 7
                    break;
2284
2285 26
                default:
2286
                    // Do nothing
2287
            }
2288
        }
2289
2290 65
        foreach ($entitiesToCascade as $relatedEntity) {
2291 16
            $this->doRemove($relatedEntity, $visited);
2292
        }
2293 65
    }
2294
2295
    /**
2296
     * Acquire a lock on the given entity.
2297
     *
2298
     * @param object $entity
2299
     * @param int    $lockMode
2300
     * @param int    $lockVersion
2301
     *
2302
     * @return void
2303
     *
2304
     * @throws ORMInvalidArgumentException
2305
     * @throws TransactionRequiredException
2306
     * @throws OptimisticLockException
2307
     */
2308 11
    public function lock($entity, $lockMode, $lockVersion = null)
2309
    {
2310 11
        if ($entity === null) {
2311 1
            throw new \InvalidArgumentException("No entity passed to UnitOfWork#lock().");
2312
        }
2313
2314 10
        if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
2315 1
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2316
        }
2317
2318 9
        $class = $this->em->getClassMetadata(get_class($entity));
2319
2320
        switch (true) {
2321 9
            case LockMode::OPTIMISTIC === $lockMode:
2322 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...
2323 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...
2324
                }
2325
2326 4
                if ($lockVersion === null) {
2327
                    return;
2328
                }
2329
2330 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...
2331 1
                    $entity->__load();
2332
                }
2333
2334 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...
2335
2336 4
                if ($entityVersion != $lockVersion) {
2337 2
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion);
2338
                }
2339
2340 2
                break;
2341
2342 3
            case LockMode::NONE === $lockMode:
2343 3
            case LockMode::PESSIMISTIC_READ === $lockMode:
2344 1
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
2345 3
                if (!$this->em->getConnection()->isTransactionActive()) {
2346 2
                    throw TransactionRequiredException::transactionRequired();
2347
                }
2348
2349 1
                $oid = spl_object_hash($entity);
2350
2351 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...
2352 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2353
                    $lockMode
2354
                );
2355 1
                break;
2356
2357
            default:
2358
                // Do nothing
2359
        }
2360 3
    }
2361
2362
    /**
2363
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2364
     *
2365
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2366
     */
2367 1007
    public function getCommitOrderCalculator()
2368
    {
2369 1007
        return new Internal\CommitOrderCalculator();
2370
    }
2371
2372
    /**
2373
     * Clears the UnitOfWork.
2374
     *
2375
     * @param string|null $entityName if given, only entities of this type will get detached.
2376
     *
2377
     * @return void
2378
     */
2379 1220
    public function clear($entityName = null)
2380
    {
2381 1220
        if ($entityName === null) {
2382 1220
            $this->identityMap =
2383 1220
            $this->entityIdentifiers =
2384 1220
            $this->originalEntityData =
2385 1220
            $this->entityChangeSets =
2386 1220
            $this->entityStates =
2387 1220
            $this->scheduledForSynchronization =
2388 1220
            $this->entityInsertions =
2389 1220
            $this->entityUpdates =
2390 1220
            $this->entityDeletions =
2391 1220
            $this->collectionDeletions =
2392 1220
            $this->collectionUpdates =
2393 1220
            $this->extraUpdates =
2394 1220
            $this->readOnlyObjects =
2395 1220
            $this->visitedCollections =
2396 1220
            $this->orphanRemovals = array();
2397
        } else {
2398 2
            $visited = array();
2399
2400 2
            foreach ($this->identityMap as $className => $entities) {
2401 2
                if ($className !== $entityName) {
2402 1
                    continue;
2403
                }
2404
2405 2
                foreach ($entities as $entity) {
2406 2
                    $this->doDetach($entity, $visited, false);
2407
                }
2408
            }
2409
        }
2410
2411 1220
        if ($this->evm->hasListeners(Events::onClear)) {
2412 7
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2413
        }
2414 1220
    }
2415
2416
    /**
2417
     * INTERNAL:
2418
     * Schedules an orphaned entity for removal. The remove() operation will be
2419
     * invoked on that entity at the beginning of the next commit of this
2420
     * UnitOfWork.
2421
     *
2422
     * @ignore
2423
     *
2424
     * @param object $entity
2425
     *
2426
     * @return void
2427
     */
2428 17
    public function scheduleOrphanRemoval($entity)
2429
    {
2430 17
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2431 17
    }
2432
2433
    /**
2434
     * INTERNAL:
2435
     * Cancels a previously scheduled orphan removal.
2436
     *
2437
     * @ignore
2438
     *
2439
     * @param object $entity
2440
     *
2441
     * @return void
2442
     */
2443 111
    public function cancelOrphanRemoval($entity)
2444
    {
2445 111
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2446 111
    }
2447
2448
    /**
2449
     * INTERNAL:
2450
     * Schedules a complete collection for removal when this UnitOfWork commits.
2451
     *
2452
     * @param PersistentCollection $coll
2453
     *
2454
     * @return void
2455
     */
2456 13
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2457
    {
2458 13
        $coid = spl_object_hash($coll);
2459
2460
        // TODO: if $coll is already scheduled for recreation ... what to do?
2461
        // Just remove $coll from the scheduled recreations?
2462 13
        if (isset($this->collectionUpdates[$coid])) {
2463
            unset($this->collectionUpdates[$coid]);
2464
        }
2465
2466 13
        $this->collectionDeletions[$coid] = $coll;
2467 13
    }
2468
2469
    /**
2470
     * @param PersistentCollection $coll
2471
     *
2472
     * @return bool
2473
     */
2474
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2475
    {
2476
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2477
    }
2478
2479
    /**
2480
     * @param ClassMetadata $class
2481
     *
2482
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2483
     */
2484 669
    private function newInstance($class)
2485
    {
2486 669
        $entity = $class->newInstance();
2487
2488 669
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2489 4
            $entity->injectObjectManager($this->em, $class);
2490
        }
2491
2492 669
        return $entity;
2493
    }
2494
2495
    /**
2496
     * INTERNAL:
2497
     * Creates an entity. Used for reconstitution of persistent entities.
2498
     *
2499
     * Internal note: Highly performance-sensitive method.
2500
     *
2501
     * @ignore
2502
     *
2503
     * @param string $className The name of the entity class.
2504
     * @param array  $data      The data for the entity.
2505
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2506
     *
2507
     * @return object The managed entity instance.
2508
     *
2509
     * @todo Rename: getOrCreateEntity
2510
     */
2511 808
    public function createEntity($className, array $data, &$hints = array())
2512
    {
2513 808
        $class = $this->em->getClassMetadata($className);
2514
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2515
2516 808
        $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...
2517 808
        $idHash = implode(' ', $id);
2518
2519 808
        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...
2520 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...
2521 312
            $oid = spl_object_hash($entity);
2522
2523
            if (
2524 312
                isset($hints[Query::HINT_REFRESH])
2525 312
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2526 312
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2527 312
                && $unmanagedProxy instanceof Proxy
2528 312
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2529
            ) {
2530
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2531
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2532
                // refreshed object may be anything
2533
2534 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...
2535 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...
2536
                }
2537
2538 2
                return $unmanagedProxy;
2539
            }
2540
2541 310
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2542 21
                $entity->__setInitialized(true);
2543
2544 21
                $overrideLocalValues = true;
2545
2546 21
                if ($entity instanceof NotifyPropertyChanged) {
2547 21
                    $entity->addPropertyChangedListener($this);
2548
                }
2549
            } else {
2550 291
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2551
2552
                // If only a specific entity is set to refresh, check that it's the one
2553 291
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2554 72
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2555
                }
2556
            }
2557
2558 310
            if ($overrideLocalValues) {
2559
                // inject ObjectManager upon refresh.
2560 113
                if ($entity instanceof ObjectManagerAware) {
2561 3
                    $entity->injectObjectManager($this->em, $class);
2562
                }
2563
2564 310
                $this->originalEntityData[$oid] = $data;
2565
            }
2566
        } else {
2567 666
            $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...
2568 666
            $oid    = spl_object_hash($entity);
2569
2570 666
            $this->entityIdentifiers[$oid]  = $id;
2571 666
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2572 666
            $this->originalEntityData[$oid] = $data;
2573
2574 666
            $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...
2575
2576 666
            if ($entity instanceof NotifyPropertyChanged) {
2577 2
                $entity->addPropertyChangedListener($this);
2578
            }
2579
2580 666
            $overrideLocalValues = true;
2581
        }
2582
2583 807
        if ( ! $overrideLocalValues) {
2584 220
            return $entity;
2585
        }
2586
2587 704
        foreach ($data as $field => $value) {
2588 704
            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...
2589 704
                $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...
2590
            }
2591
        }
2592
2593
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2594 704
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2595
2596 704
        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...
2597
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2598
        }
2599
2600
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2601 704
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2602 33
            return $entity;
2603
        }
2604
2605 671
        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...
2606
            // Check if the association is not among the fetch-joined associations already.
2607 586
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2608 259
                continue;
2609
            }
2610
2611 564
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2612
2613
            switch (true) {
2614 564
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2615 484
                    if ( ! $assoc['isOwningSide']) {
2616
2617
                        // use the given entity association
2618 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2619
2620 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2621
2622 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...
2623 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...
2624
2625 2
                            continue 2;
2626
                        }
2627
2628
                        // Inverse side of x-to-one can never be lazy
2629 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...
2630
2631 62
                        continue 2;
2632
                    }
2633
2634
                    // use the entity association
2635 484
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2636 37
                        $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...
2637 37
                        $this->originalEntityData[$oid][$field] = $data[$field];
2638
2639 37
                        continue;
2640
                    }
2641
2642 477
                    $associatedId = array();
2643
2644
                    // TODO: Is this even computed right in all cases of composite keys?
2645 477
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2646 477
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2647
2648 477
                        if ($joinColumnValue !== null) {
2649 282
                            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...
2650 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2651
                            } else {
2652 282
                                $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...
2653
                            }
2654 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...
2655 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...
2656
                        ) {
2657
                            // the missing key is part of target's entity primary key
2658 7
                            $associatedId = array();
2659 477
                            break;
2660
                        }
2661
                    }
2662
2663 477
                    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...
2664
                        // Foreign key is NULL
2665 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...
2666 287
                        $this->originalEntityData[$oid][$field] = null;
2667
2668 287
                        continue;
2669
                    }
2670
2671 282
                    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...
2672 279
                        $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...
2673
                    }
2674
2675
                    // Foreign key is set
2676
                    // Check identity map first
2677
                    // FIXME: Can break easily with composite keys if join column values are in
2678
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2679 282
                    $relatedIdHash = implode(' ', $associatedId);
2680
2681
                    switch (true) {
2682 282
                        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...
2683 164
                            $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...
2684
2685
                            // If this is an uninitialized proxy, we are deferring eager loads,
2686
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2687
                            // then we can append this entity for eager loading!
2688 164
                            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...
2689 164
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2690 164
                                !$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...
2691 164
                                $newValue instanceof Proxy &&
2692 164
                                $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...
2693
2694
                                $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...
2695
                            }
2696
2697 164
                            break;
2698
2699 191
                        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...
2700
                            // If it might be a subtype, it can not be lazy. There isn't even
2701
                            // a way to solve this with deferred eager loading, which means putting
2702
                            // an entity with subclasses at a *-to-one location is really bad! (performance-wise)
2703 30
                            $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
2704 30
                            break;
2705
2706
                        default:
2707
                            switch (true) {
2708
                                // We are negating the condition here. Other cases will assume it is valid!
2709 162
                                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...
2710 155
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2711 155
                                    break;
2712
2713
                                // Deferred eager load only works for single identifier classes
2714 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...
2715
                                    // TODO: Is there a faster approach?
2716 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...
2717
2718 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2719 7
                                    break;
2720
2721
                                default:
2722
                                    // TODO: This is very imperformant, ignore it?
2723
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2724
                                    break;
2725
                            }
2726
2727
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2728 162
                            $newValueOid = spl_object_hash($newValue);
2729 162
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2730 162
                            $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...
2731
2732
                            if (
2733 162
                                $newValue instanceof NotifyPropertyChanged &&
2734 162
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2735
                            ) {
2736
                                $newValue->addPropertyChangedListener($this);
2737
                            }
2738 162
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2739
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2740 162
                            break;
2741
                    }
2742
2743 282
                    $this->originalEntityData[$oid][$field] = $newValue;
2744 282
                    $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...
2745
2746 282
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2747 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...
2748 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...
2749
                    }
2750
2751 282
                    break;
2752
2753
                default:
2754
                    // Ignore if its a cached collection
2755 486
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2756
                        break;
2757
                    }
2758
2759
                    // use the given collection
2760 486
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2761
2762 2
                        $data[$field]->setOwner($entity, $assoc);
2763
2764 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...
2765 2
                        $this->originalEntityData[$oid][$field] = $data[$field];
2766
2767 2
                        break;
2768
                    }
2769
2770
                    // Inject collection
2771 486
                    $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...
2772 486
                    $pColl->setOwner($entity, $assoc);
2773 486
                    $pColl->setInitialized(false);
2774
2775 486
                    $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...
2776 486
                    $reflField->setValue($entity, $pColl);
2777
2778 486
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2779 4
                        $this->loadCollection($pColl);
2780 4
                        $pColl->takeSnapshot();
2781
                    }
2782
2783 486
                    $this->originalEntityData[$oid][$field] = $pColl;
2784 564
                    break;
2785
            }
2786
        }
2787
2788 671
        if ($overrideLocalValues) {
2789
            // defer invoking of postLoad event to hydration complete step
2790 671
            $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...
2791
        }
2792
2793 671
        return $entity;
2794
    }
2795
2796
    /**
2797
     * @return void
2798
     */
2799 865
    public function triggerEagerLoads()
2800
    {
2801 865
        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...
2802 865
            return;
2803
        }
2804
2805
        // avoid infinite recursion
2806 7
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2807 7
        $this->eagerLoadingEntities = array();
2808
2809 7
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2810 7
            if ( ! $ids) {
2811
                continue;
2812
            }
2813
2814 7
            $class = $this->em->getClassMetadata($entityName);
2815
2816 7
            $this->getEntityPersister($entityName)->loadAll(
2817 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...
2818
            );
2819
        }
2820 7
    }
2821
2822
    /**
2823
     * Initializes (loads) an uninitialized persistent collection of an entity.
2824
     *
2825
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2826
     *
2827
     * @return void
2828
     *
2829
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2830
     */
2831 142
    public function loadCollection(PersistentCollection $collection)
2832
    {
2833 142
        $assoc     = $collection->getMapping();
2834 142
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2835
2836 142
        switch ($assoc['type']) {
2837 142
            case ClassMetadata::ONE_TO_MANY:
2838 75
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2839 75
                break;
2840
2841 81
            case ClassMetadata::MANY_TO_MANY:
2842 81
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2843 81
                break;
2844
        }
2845
2846 142
        $collection->setInitialized(true);
2847 142
    }
2848
2849
    /**
2850
     * Gets the identity map of the UnitOfWork.
2851
     *
2852
     * @return array
2853
     */
2854 2
    public function getIdentityMap()
2855
    {
2856 2
        return $this->identityMap;
2857
    }
2858
2859
    /**
2860
     * Gets the original data of an entity. The original data is the data that was
2861
     * present at the time the entity was reconstituted from the database.
2862
     *
2863
     * @param object $entity
2864
     *
2865
     * @return array
2866
     */
2867 114
    public function getOriginalEntityData($entity)
2868
    {
2869 114
        $oid = spl_object_hash($entity);
2870
2871 114
        if (isset($this->originalEntityData[$oid])) {
2872 111
            return $this->originalEntityData[$oid];
2873
        }
2874
2875 4
        return array();
2876
    }
2877
2878
    /**
2879
     * @ignore
2880
     *
2881
     * @param object $entity
2882
     * @param array  $data
2883
     *
2884
     * @return void
2885
     */
2886
    public function setOriginalEntityData($entity, array $data)
2887
    {
2888
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2889
    }
2890
2891
    /**
2892
     * INTERNAL:
2893
     * Sets a property value of the original data array of an entity.
2894
     *
2895
     * @ignore
2896
     *
2897
     * @param string $oid
2898
     * @param string $property
2899
     * @param mixed  $value
2900
     *
2901
     * @return void
2902
     */
2903 312
    public function setOriginalEntityProperty($oid, $property, $value)
2904
    {
2905 312
        $this->originalEntityData[$oid][$property] = $value;
2906 312
    }
2907
2908
    /**
2909
     * Gets the identifier of an entity.
2910
     * The returned value is always an array of identifier values. If the entity
2911
     * has a composite identifier then the identifier values are in the same
2912
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2913
     *
2914
     * @param object $entity
2915
     *
2916
     * @return array The identifier values.
2917
     */
2918 842
    public function getEntityIdentifier($entity)
2919
    {
2920 842
        return $this->entityIdentifiers[spl_object_hash($entity)];
2921
    }
2922
2923
    /**
2924
     * Processes an entity instance to extract their identifier values.
2925
     *
2926
     * @param object $entity The entity instance.
2927
     *
2928
     * @return mixed A scalar value.
2929
     *
2930
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2931
     */
2932 126
    public function getSingleIdentifierValue($entity)
2933
    {
2934 126
        $class = $this->em->getClassMetadata(get_class($entity));
2935
2936 126
        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...
2937
            throw ORMInvalidArgumentException::invalidCompositeIdentifier();
2938
        }
2939
2940 126
        $values = $this->isInIdentityMap($entity)
2941 113
            ? $this->getEntityIdentifier($entity)
2942 126
            : $class->getIdentifierValues($entity);
2943
2944 126
        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...
2945
    }
2946
2947
    /**
2948
     * Tries to find an entity with the given identifier in the identity map of
2949
     * this UnitOfWork.
2950
     *
2951
     * @param mixed  $id            The entity identifier to look for.
2952
     * @param string $rootClassName The name of the root class of the mapped entity hierarchy.
2953
     *
2954
     * @return object|bool Returns the entity with the specified identifier if it exists in
2955
     *                     this UnitOfWork, FALSE otherwise.
2956
     */
2957 522
    public function tryGetById($id, $rootClassName)
2958
    {
2959 522
        $idHash = implode(' ', (array) $id);
2960
2961 522
        if (isset($this->identityMap[$rootClassName][$idHash])) {
2962 78
            return $this->identityMap[$rootClassName][$idHash];
2963
        }
2964
2965 508
        return false;
2966
    }
2967
2968
    /**
2969
     * Schedules an entity for dirty-checking at commit-time.
2970
     *
2971
     * @param object $entity The entity to schedule for dirty-checking.
2972
     *
2973
     * @return void
2974
     *
2975
     * @todo Rename: scheduleForSynchronization
2976
     */
2977 5
    public function scheduleForDirtyCheck($entity)
2978
    {
2979 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...
2980
2981 5
        $this->scheduledForSynchronization[$rootClassName][spl_object_hash($entity)] = $entity;
2982 5
    }
2983
2984
    /**
2985
     * Checks whether the UnitOfWork has any pending insertions.
2986
     *
2987
     * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise.
2988
     */
2989
    public function hasPendingInsertions()
2990
    {
2991
        return ! empty($this->entityInsertions);
2992
    }
2993
2994
    /**
2995
     * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the
2996
     * number of entities in the identity map.
2997
     *
2998
     * @return integer
2999
     */
3000 1
    public function size()
3001
    {
3002
        $countArray = array_map(function ($item) { return count($item); }, $this->identityMap);
3003
3004 1
        return array_sum($countArray);
3005
    }
3006
3007
    /**
3008
     * Gets the EntityPersister for an Entity.
3009
     *
3010
     * @param string $entityName The name of the Entity.
3011
     *
3012
     * @return \Doctrine\ORM\Persisters\Entity\EntityPersister
3013
     */
3014 1069
    public function getEntityPersister($entityName)
3015
    {
3016 1069
        if (isset($this->persisters[$entityName])) {
3017 845
            return $this->persisters[$entityName];
3018
        }
3019
3020 1069
        $class = $this->em->getClassMetadata($entityName);
3021
3022
        switch (true) {
3023 1069
            case ($class->isInheritanceTypeNone()):
3024 1032
                $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...
3025 1032
                break;
3026
3027 358
            case ($class->isInheritanceTypeSingleTable()):
3028 212
                $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...
3029 212
                break;
3030
3031 337
            case ($class->isInheritanceTypeJoined()):
3032 337
                $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...
3033 337
                break;
3034
3035
            default:
3036
                throw new \RuntimeException('No persister found for entity.');
3037
        }
3038
3039 1069
        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...
3040 118
            $persister = $this->em->getConfiguration()
3041 118
                ->getSecondLevelCacheConfiguration()
3042 118
                ->getCacheFactory()
3043 118
                ->buildCachedEntityPersister($this->em, $persister, $class);
3044
        }
3045
3046 1069
        $this->persisters[$entityName] = $persister;
3047
3048 1069
        return $this->persisters[$entityName];
3049
    }
3050
3051
    /**
3052
     * Gets a collection persister for a collection-valued association.
3053
     *
3054
     * @param array $association
3055
     *
3056
     * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister
3057
     */
3058 568
    public function getCollectionPersister(array $association)
3059
    {
3060 568
        $role = isset($association['cache'])
3061 75
            ? $association['sourceEntity'] . '::' . $association['fieldName']
3062 568
            : $association['type'];
3063
3064 568
        if (isset($this->collectionPersisters[$role])) {
3065 447
            return $this->collectionPersisters[$role];
3066
        }
3067
3068 568
        $persister = ClassMetadata::ONE_TO_MANY === $association['type']
3069 402
            ? new OneToManyPersister($this->em)
3070 568
            : new ManyToManyPersister($this->em);
3071
3072 568
        if ($this->hasCache && isset($association['cache'])) {
3073 74
            $persister = $this->em->getConfiguration()
3074 74
                ->getSecondLevelCacheConfiguration()
3075 74
                ->getCacheFactory()
3076 74
                ->buildCachedCollectionPersister($this->em, $persister, $association);
3077
        }
3078
3079 568
        $this->collectionPersisters[$role] = $persister;
3080
3081 568
        return $this->collectionPersisters[$role];
3082
    }
3083
3084
    /**
3085
     * INTERNAL:
3086
     * Registers an entity as managed.
3087
     *
3088
     * @param object $entity The entity.
3089
     * @param array  $id     The identifier values.
3090
     * @param array  $data   The original entity data.
3091
     *
3092
     * @return void
3093
     */
3094 201
    public function registerManaged($entity, array $id, array $data)
3095
    {
3096 201
        $oid = spl_object_hash($entity);
3097
3098 201
        $this->entityIdentifiers[$oid]  = $id;
3099 201
        $this->entityStates[$oid]       = self::STATE_MANAGED;
3100 201
        $this->originalEntityData[$oid] = $data;
3101
3102 201
        $this->addToIdentityMap($entity);
3103
3104 200
        if ($entity instanceof NotifyPropertyChanged && ( ! $entity instanceof Proxy || $entity->__isInitialized())) {
3105 2
            $entity->addPropertyChangedListener($this);
3106
        }
3107 200
    }
3108
3109
    /**
3110
     * INTERNAL:
3111
     * Clears the property changeset of the entity with the given OID.
3112
     *
3113
     * @param string $oid The entity's OID.
3114
     *
3115
     * @return void
3116
     */
3117
    public function clearEntityChangeSet($oid)
3118
    {
3119
        $this->entityChangeSets[$oid] = array();
3120
    }
3121
3122
    /* PropertyChangedListener implementation */
3123
3124
    /**
3125
     * Notifies this UnitOfWork of a property change in an entity.
3126
     *
3127
     * @param object $entity       The entity that owns the property.
3128
     * @param string $propertyName The name of the property that changed.
3129
     * @param mixed  $oldValue     The old value of the property.
3130
     * @param mixed  $newValue     The new value of the property.
3131
     *
3132
     * @return void
3133
     */
3134 3
    public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
3135
    {
3136 3
        $oid   = spl_object_hash($entity);
3137 3
        $class = $this->em->getClassMetadata(get_class($entity));
3138
3139 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...
3140
3141 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...
3142 1
            return; // ignore non-persistent fields
3143
        }
3144
3145
        // Update changeset and mark entity for synchronization
3146 3
        $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
3147
3148 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...
3149 3
            $this->scheduleForDirtyCheck($entity);
3150
        }
3151 3
    }
3152
3153
    /**
3154
     * Gets the currently scheduled entity insertions in this UnitOfWork.
3155
     *
3156
     * @return array
3157
     */
3158 2
    public function getScheduledEntityInsertions()
3159
    {
3160 2
        return $this->entityInsertions;
3161
    }
3162
3163
    /**
3164
     * Gets the currently scheduled entity updates in this UnitOfWork.
3165
     *
3166
     * @return array
3167
     */
3168 2
    public function getScheduledEntityUpdates()
3169
    {
3170 2
        return $this->entityUpdates;
3171
    }
3172
3173
    /**
3174
     * Gets the currently scheduled entity deletions in this UnitOfWork.
3175
     *
3176
     * @return array
3177
     */
3178 1
    public function getScheduledEntityDeletions()
3179
    {
3180 1
        return $this->entityDeletions;
3181
    }
3182
3183
    /**
3184
     * Gets the currently scheduled complete collection deletions
3185
     *
3186
     * @return array
3187
     */
3188 1
    public function getScheduledCollectionDeletions()
3189
    {
3190 1
        return $this->collectionDeletions;
3191
    }
3192
3193
    /**
3194
     * Gets the currently scheduled collection inserts, updates and deletes.
3195
     *
3196
     * @return array
3197
     */
3198
    public function getScheduledCollectionUpdates()
3199
    {
3200
        return $this->collectionUpdates;
3201
    }
3202
3203
    /**
3204
     * Helper method to initialize a lazy loading proxy or persistent collection.
3205
     *
3206
     * @param object $obj
3207
     *
3208
     * @return void
3209
     */
3210 2
    public function initializeObject($obj)
3211
    {
3212 2
        if ($obj instanceof Proxy) {
3213 1
            $obj->__load();
3214
3215 1
            return;
3216
        }
3217
3218 1
        if ($obj instanceof PersistentCollection) {
3219 1
            $obj->initialize();
3220
        }
3221 1
    }
3222
3223
    /**
3224
     * Helper method to show an object as string.
3225
     *
3226
     * @param object $obj
3227
     *
3228
     * @return string
3229
     */
3230 1
    private static function objToStr($obj)
3231
    {
3232 1
        return method_exists($obj, '__toString') ? (string) $obj : get_class($obj).'@'.spl_object_hash($obj);
3233
    }
3234
3235
    /**
3236
     * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit().
3237
     *
3238
     * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information
3239
     * on this object that might be necessary to perform a correct update.
3240
     *
3241
     * @param object $object
3242
     *
3243
     * @return void
3244
     *
3245
     * @throws ORMInvalidArgumentException
3246
     */
3247 6
    public function markReadOnly($object)
3248
    {
3249 6
        if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
3250 1
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3251
        }
3252
3253 5
        $this->readOnlyObjects[spl_object_hash($object)] = true;
3254 5
    }
3255
3256
    /**
3257
     * Is this entity read only?
3258
     *
3259
     * @param object $object
3260
     *
3261
     * @return bool
3262
     *
3263
     * @throws ORMInvalidArgumentException
3264
     */
3265 3
    public function isReadOnly($object)
3266
    {
3267 3
        if ( ! is_object($object)) {
3268
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3269
        }
3270
3271 3
        return isset($this->readOnlyObjects[spl_object_hash($object)]);
3272
    }
3273
3274
    /**
3275
     * Perform whatever processing is encapsulated here after completion of the transaction.
3276
     */
3277 1002
    private function afterTransactionComplete()
3278
    {
3279
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3280 88
            $persister->afterTransactionComplete();
3281 1002
        });
3282 1002
    }
3283
3284
    /**
3285
     * Perform whatever processing is encapsulated here after completion of the rolled-back.
3286
     */
3287
    private function afterTransactionRolledBack()
3288
    {
3289 11
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3290 3
            $persister->afterTransactionRolledBack();
3291 11
        });
3292 11
    }
3293
3294
    /**
3295
     * Performs an action after the transaction.
3296
     *
3297
     * @param callable $callback
3298
     */
3299 1007
    private function performCallbackOnCachedPersister(callable $callback)
3300
    {
3301 1007
        if ( ! $this->hasCache) {
3302 919
            return;
3303
        }
3304
3305 88
        foreach (array_merge($this->persisters, $this->collectionPersisters) as $persister) {
3306 88
            if ($persister instanceof CachedPersister) {
3307 88
                $callback($persister);
3308
            }
3309
        }
3310 88
    }
3311
3312 1011
    private function dispatchOnFlushEvent()
3313
    {
3314 1011
        if ($this->evm->hasListeners(Events::onFlush)) {
3315 4
            $this->evm->dispatchEvent(Events::onFlush, new OnFlushEventArgs($this->em));
3316
        }
3317 1011
    }
3318
3319 1006
    private function dispatchPostFlushEvent()
3320
    {
3321 1006
        if ($this->evm->hasListeners(Events::postFlush)) {
3322 5
            $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
3323
        }
3324 1005
    }
3325
3326
    /**
3327
     * Verifies if two given entities actually are the same based on identifier comparison
3328
     *
3329
     * @param object $entity1
3330
     * @param object $entity2
3331
     *
3332
     * @return bool
3333
     */
3334 14
    private function isIdentifierEquals($entity1, $entity2)
3335
    {
3336 14
        if ($entity1 === $entity2) {
3337
            return true;
3338
        }
3339
3340 14
        $class = $this->em->getClassMetadata(get_class($entity1));
3341
3342 14
        if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
3343 11
            return false;
3344
        }
3345
3346 3
        $oid1 = spl_object_hash($entity1);
3347 3
        $oid2 = spl_object_hash($entity2);
3348
3349 3
        $id1 = isset($this->entityIdentifiers[$oid1])
3350 3
            ? $this->entityIdentifiers[$oid1]
3351 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...
3352 3
        $id2 = isset($this->entityIdentifiers[$oid2])
3353 3
            ? $this->entityIdentifiers[$oid2]
3354 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...
3355
3356 3
        return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
3357
    }
3358
3359
    /**
3360
     * @param object $entity
3361
     * @param object $managedCopy
3362
     *
3363
     * @throws ORMException
3364
     * @throws OptimisticLockException
3365
     * @throws TransactionRequiredException
3366
     */
3367 30
    private function mergeEntityStateIntoManagedCopy($entity, $managedCopy)
3368
    {
3369 30
        $class = $this->em->getClassMetadata(get_class($entity));
3370
3371 30
        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...
3372 30
            $name = $prop->name;
3373
3374 30
            $prop->setAccessible(true);
3375
3376 30
            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...
3377 30
                if ( ! $class->isIdentifier($name)) {
3378 30
                    $prop->setValue($managedCopy, $prop->getValue($entity));
3379
                }
3380
            } else {
3381 28
                $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...
3382
3383 28
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3384 24
                    $other = $prop->getValue($entity);
3385 24
                    if ($other === null) {
3386 11
                        $prop->setValue($managedCopy, null);
3387
                    } else {
3388 16
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3389
                            // do not merge fields marked lazy that have not been fetched.
3390 4
                            continue;
3391
                        }
3392
3393 12
                        if ( ! $assoc2['isCascadeMerge']) {
3394 6
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3395 3
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3396 3
                                $relatedId   = $targetClass->getIdentifierValues($other);
3397
3398 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...
3399 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...
3400
                                } else {
3401 1
                                    $other = $this->em->getProxyFactory()->getProxy(
3402 1
                                        $assoc2['targetEntity'],
3403
                                        $relatedId
3404
                                    );
3405 1
                                    $this->registerManaged($other, $relatedId, array());
3406
                                }
3407
                            }
3408
3409 20
                            $prop->setValue($managedCopy, $other);
3410
                        }
3411
                    }
3412
                } else {
3413 16
                    $mergeCol = $prop->getValue($entity);
3414
3415 16
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3416
                        // do not merge fields marked lazy that have not been fetched.
3417
                        // keep the lazy persistent collection of the managed copy.
3418 5
                        continue;
3419
                    }
3420
3421 13
                    $managedCol = $prop->getValue($managedCopy);
3422
3423 13
                    if ( ! $managedCol) {
3424 3
                        $managedCol = new PersistentCollection(
3425 3
                            $this->em,
3426 3
                            $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...
3427 3
                            new ArrayCollection
3428
                        );
3429 3
                        $managedCol->setOwner($managedCopy, $assoc2);
3430 3
                        $prop->setValue($managedCopy, $managedCol);
3431
3432 3
                        $this->originalEntityData[spl_object_hash($entity)][$name] = $managedCol;
3433
                    }
3434
3435 13
                    if ($assoc2['isCascadeMerge']) {
3436 8
                        $managedCol->initialize();
3437
3438
                        // clear and set dirty a managed collection if its not also the same collection to merge from.
3439 8
                        if ( ! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
3440 1
                            $managedCol->unwrap()->clear();
3441 1
                            $managedCol->setDirty(true);
3442
3443 1
                            if ($assoc2['isOwningSide']
3444 1
                                && $assoc2['type'] == ClassMetadata::MANY_TO_MANY
3445 1
                                && $class->isChangeTrackingNotify()
3446
                            ) {
3447
                                $this->scheduleForDirtyCheck($managedCopy);
3448
                            }
3449
                        }
3450
                    }
3451
                }
3452
            }
3453
3454 30
            if ($class->isChangeTrackingNotify()) {
3455
                // Just treat all properties as changed, there is no other choice.
3456 30
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
3457
            }
3458
        }
3459 30
    }
3460
3461
    /**
3462
     * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
3463
     * Unit of work able to fire deferred events, related to loading events here.
3464
     *
3465
     * @internal should be called internally from object hydrators
3466
     */
3467 876
    public function hydrationComplete()
3468
    {
3469 876
        $this->hydrationCompleteHandler->hydrationComplete();
3470 876
    }
3471
}
3472