Completed
Pull Request — master (#5911)
by Reen
17:56
created

UnitOfWork::executeUpdates()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 29
ccs 17
cts 17
cp 1
rs 8.439
cc 6
eloc 16
nc 10
nop 1
crap 6
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 2327
    public function __construct(EntityManagerInterface $em)
293
    {
294 2327
        $this->em                         = $em;
295 2327
        $this->evm                        = $em->getEventManager();
296 2327
        $this->listenersInvoker           = new ListenersInvoker($em);
297 2327
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
298 2327
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
299 2327
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
300 2327
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
301 2327
    }
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 530
                $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 529
            $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 1
            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 307
            $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 776
                if ($value instanceof PersistentCollection) {
588 199
                    if ($value->getOwner() === $entity) {
589 199
                        continue;
590
                    }
591
592 5
                    $value = new ArrayCollection($value->getValues());
593
                }
594
595
                // If $value is not a Collection then use an ArrayCollection.
596 771
                if ( ! $value instanceof Collection) {
597 242
                    $value = new ArrayCollection($value);
598
                }
599
600 771
                $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 771
                $value = new PersistentCollection(
604 771
                    $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 771
                $value->setOwner($entity, $assoc);
607 771
                $value->setDirty( ! $value->isEmpty());
608
609 771
                $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 771
                $actualData[$name] = $value;
612
613 771
                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 893
                $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 893
                if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
637 893
                    $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 263
            $originalData           = $this->originalEntityData[$oid];
646 263
            $isChangeTrackingNotify = $class->isChangeTrackingNotify();
647 263
            $changeSet              = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid]))
648
                ? $this->entityChangeSets[$oid]
649 263
                : array();
650
651 263
            foreach ($actualData as $propName => $actualValue) {
652
                // skip field, its a partially omitted one!
653 248
                if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) {
654 8
                    continue;
655
                }
656
657 248
                $orgValue = $originalData[$propName];
658
659
                // skip if value haven't changed
660 248
                if ($orgValue === $actualValue) {
661 232
                    continue;
662
                }
663
664
                // if regular field
665 112
                if ( ! isset($class->associationMappings[$propName])) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
666 58
                    if ($isChangeTrackingNotify) {
667
                        continue;
668
                    }
669
670 58
                    $changeSet[$propName] = array($orgValue, $actualValue);
671
672 58
                    continue;
673
                }
674
675 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...
676
677
                // Persistent collection was exchanged with the "originally"
678
                // created one. This can only mean it was cloned and replaced
679
                // on another entity.
680 58
                if ($actualValue instanceof PersistentCollection) {
681 8
                    $owner = $actualValue->getOwner();
682 8
                    if ($owner === null) { // cloned
683
                        $actualValue->setOwner($entity, $assoc);
684 8
                    } else if ($owner !== $entity) { // no clone, we have to fix
685
                        if (!$actualValue->isInitialized()) {
686
                            $actualValue->initialize(); // we have to do this otherwise the cols share state
687
                        }
688
                        $newValue = clone $actualValue;
689
                        $newValue->setOwner($entity, $assoc);
690
                        $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...
691
                    }
692
                }
693
694 58
                if ($orgValue instanceof PersistentCollection) {
695
                    // A PersistentCollection was de-referenced, so delete it.
696 8
                    $coid = spl_object_hash($orgValue);
697
698 8
                    if (isset($this->collectionDeletions[$coid])) {
699
                        continue;
700
                    }
701
702 8
                    $this->collectionDeletions[$coid] = $orgValue;
703 8
                    $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored.
704
705 8
                    continue;
706
                }
707
708 50
                if ($assoc['type'] & ClassMetadata::TO_ONE) {
709 49
                    if ($assoc['isOwningSide']) {
710 21
                        $changeSet[$propName] = array($orgValue, $actualValue);
711
                    }
712
713 49
                    if ($orgValue !== null && $assoc['orphanRemoval']) {
714 50
                        $this->scheduleOrphanRemoval($orgValue);
715
                    }
716
                }
717
            }
718
719 263
            if ($changeSet) {
720 85
                $this->entityChangeSets[$oid]   = $changeSet;
721 85
                $this->originalEntityData[$oid] = $actualData;
722 85
                $this->entityUpdates[$oid]      = $entity;
723
            }
724
        }
725
726
        // Look for changes in associations of the entity
727 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...
728 893
            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...
729 638
                continue;
730
            }
731
732 864
            $this->computeAssociationChanges($assoc, $val);
733
734 856
            if ( ! isset($this->entityChangeSets[$oid]) &&
735 856
                $assoc['isOwningSide'] &&
736 856
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
737 856
                $val instanceof PersistentCollection &&
738 856
                $val->isDirty()) {
739
740 35
                $this->entityChangeSets[$oid]   = array();
741 35
                $this->originalEntityData[$oid] = $actualData;
742 856
                $this->entityUpdates[$oid]      = $entity;
743
            }
744
        }
745 1007
    }
746
747
    /**
748
     * Computes all the changes that have been done to entities and collections
749
     * since the last commit and stores these changes in the _entityChangeSet map
750
     * temporarily for access by the persisters, until the UoW commit is finished.
751
     *
752
     * @return void
753
     */
754 1006
    public function computeChangeSets()
755
    {
756
        // Compute changes for INSERTed entities first. This must always happen.
757 1006
        $this->computeScheduleInsertsChangeSets();
758
759
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
760 1004
        foreach ($this->identityMap as $className => $entities) {
761 447
            $class = $this->em->getClassMetadata($className);
762
763
            // Skip class if instances are read-only
764 447
            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...
765 1
                continue;
766
            }
767
768
            // If change tracking is explicit or happens through notification, then only compute
769
            // changes on entities of that type that are explicitly marked for synchronization.
770
            switch (true) {
771 446
                case ($class->isChangeTrackingDeferredImplicit()):
772 444
                    $entitiesToProcess = $entities;
773 444
                    break;
774
775 3
                case (isset($this->scheduledForSynchronization[$className])):
776 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
777 3
                    break;
778
779
                default:
780 1
                    $entitiesToProcess = array();
781
782
            }
783
784 446
            foreach ($entitiesToProcess as $entity) {
785
                // Ignore uninitialized proxy objects
786 426
                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...
787 34
                    continue;
788
                }
789
790
                // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
791 425
                $oid = spl_object_hash($entity);
792
793 425
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
794 446
                    $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...
795
                }
796
            }
797
        }
798 1004
    }
799
800
    /**
801
     * Computes the changes of an association.
802
     *
803
     * @param array $assoc The association mapping.
804
     * @param mixed $value The value of the association.
805
     *
806
     * @throws ORMInvalidArgumentException
807
     * @throws ORMException
808
     *
809
     * @return void
810
     */
811 864
    private function computeAssociationChanges($assoc, $value)
812
    {
813 864
        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...
814 27
            return;
815
        }
816
817 863
        if ($value instanceof PersistentCollection && $value->isDirty()) {
818 532
            $coid = spl_object_hash($value);
819
820 532
            $this->collectionUpdates[$coid] = $value;
821 532
            $this->visitedCollections[$coid] = $value;
822
        }
823
824
        // Look through the entities, and in any of their associations,
825
        // for transient (new) entities, recursively. ("Persistence by reachability")
826
        // Unwrap. Uninitialized collections will simply be empty.
827 863
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
828 863
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
829
830 863
        foreach ($unwrappedValue as $key => $entry) {
831 721
            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...
832 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...
833
            }
834
835 715
            $state = $this->getEntityState($entry, self::STATE_NEW);
836
837 715
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
838
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
839
            }
840
841
            switch ($state) {
842 715
                case self::STATE_NEW:
843 39
                    if ( ! $assoc['isCascadePersist']) {
844 4
                        throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
845
                    }
846
847 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...
848 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...
849 35
                    break;
850
851 709
                case self::STATE_REMOVED:
852
                    // Consume the $value as array (it's either an array or an ArrayAccess)
853
                    // and remove the element from Collection.
854 4
                    if ($assoc['type'] & ClassMetadata::TO_MANY) {
855 3
                        unset($value[$key]);
856
                    }
857 4
                    break;
858
859 709
                case self::STATE_DETACHED:
860
                    // Can actually not happen right now as we assume STATE_NEW,
861
                    // so the exception will be raised from the DBAL layer (constraint violation).
862
                    throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
863
                    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...
864
865 712
                default:
866
                    // MANAGED associated entities are already taken into account
867
                    // during changeset calculation anyway, since they are in the identity map.
868
            }
869
        }
870 855
    }
871
872
    /**
873
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
874
     * @param object                              $entity
875
     *
876
     * @return void
877
     */
878 1024
    private function persistNew($class, $entity)
879
    {
880 1024
        $oid    = spl_object_hash($entity);
881 1024
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
882
883 1024
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
884 139
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
885
        }
886
887 1024
        $idGen = $class->idGenerator;
888
889 1024
        if ( ! $idGen->isPostInsertGenerator()) {
890 262
            $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...
891
892 262
            if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
893 1
                $idValue = array($class->identifier[0] => $idValue);
894
895 1
                $class->setIdentifierValues($entity, $idValue);
896
            }
897
898 262
            $this->entityIdentifiers[$oid] = $idValue;
899
        }
900
901 1024
        $this->entityStates[$oid] = self::STATE_MANAGED;
902
903 1024
        $this->scheduleForInsert($entity);
904 1024
    }
905
906
    /**
907
     * INTERNAL:
908
     * Computes the changeset of an individual entity, independently of the
909
     * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
910
     *
911
     * The passed entity must be a managed entity. If the entity already has a change set
912
     * because this method is invoked during a commit cycle then the change sets are added.
913
     * whereby changes detected in this method prevail.
914
     *
915
     * @ignore
916
     *
917
     * @param ClassMetadata $class  The class descriptor of the entity.
918
     * @param object        $entity The entity for which to (re)calculate the change set.
919
     *
920
     * @return void
921
     *
922
     * @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
923
     */
924 16
    public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
925
    {
926 16
        $oid = spl_object_hash($entity);
927
928 16
        if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
929
            throw ORMInvalidArgumentException::entityNotManaged($entity);
930
        }
931
932
        // skip if change tracking is "NOTIFY"
933 16
        if ($class->isChangeTrackingNotify()) {
934
            return;
935
        }
936
937 16
        if ( ! $class->isInheritanceTypeNone()) {
938 3
            $class = $this->em->getClassMetadata(get_class($entity));
939
        }
940
941 16
        $actualData = array();
942
943 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...
944 16
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
945 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...
946 16
                && ! $class->isCollectionValuedAssociation($name)) {
947 16
                $actualData[$name] = $refProp->getValue($entity);
948
            }
949
        }
950
951 16
        if ( ! isset($this->originalEntityData[$oid])) {
952
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
953
        }
954
955 16
        $originalData = $this->originalEntityData[$oid];
956 16
        $changeSet = array();
957
958 16
        foreach ($actualData as $propName => $actualValue) {
959 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
960
961 16
            if ($orgValue !== $actualValue) {
962 16
                $changeSet[$propName] = array($orgValue, $actualValue);
963
            }
964
        }
965
966 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...
967 7
            if (isset($this->entityChangeSets[$oid])) {
968 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
969 1
            } else if ( ! isset($this->entityInsertions[$oid])) {
970 1
                $this->entityChangeSets[$oid] = $changeSet;
971 1
                $this->entityUpdates[$oid]    = $entity;
972
            }
973 7
            $this->originalEntityData[$oid] = $actualData;
974
        }
975 16
    }
976
977
    /**
978
     * Executes all entity insertions for entities of the specified type.
979
     *
980
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
981
     *
982
     * @return void
983
     */
984 1003
    private function executeInserts($class)
985
    {
986 1003
        $entities   = array();
987 1003
        $className  = $class->name;
988 1003
        $persister  = $this->getEntityPersister($className);
989 1003
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
990
991 1003
        foreach ($this->entityInsertions as $oid => $entity) {
992
993 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...
994 854
                continue;
995
            }
996
997 1003
            $persister->addInsert($entity);
998
999 1003
            unset($this->entityInsertions[$oid]);
1000
1001 1003
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1002 1003
                $entities[] = $entity;
1003
            }
1004
        }
1005
1006 1003
        $postInsertIds = $persister->executeInserts();
1007
1008 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...
1009
            // Persister returned post-insert IDs
1010 919
            foreach ($postInsertIds as $postInsertId) {
1011 919
                $id      = $postInsertId['generatedId'];
1012 919
                $entity  = $postInsertId['entity'];
1013 919
                $oid     = spl_object_hash($entity);
1014 919
                $idField = $class->identifier[0];
1015
1016 919
                $class->reflFields[$idField]->setValue($entity, $id);
1017
1018 919
                $this->entityIdentifiers[$oid] = array($idField => $id);
1019 919
                $this->entityStates[$oid] = self::STATE_MANAGED;
1020 919
                $this->originalEntityData[$oid][$idField] = $id;
1021
1022 919
                $this->addToIdentityMap($entity);
1023
            }
1024
        }
1025
1026 1003
        foreach ($entities as $entity) {
1027 135
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1028
        }
1029 1003
    }
1030
1031
    /**
1032
     * Executes all entity updates for entities of the specified type.
1033
     *
1034
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1035
     *
1036
     * @return void
1037
     */
1038 116
    private function executeUpdates($class)
1039
    {
1040 116
        $className          = $class->name;
1041 116
        $persister          = $this->getEntityPersister($className);
1042 116
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1043 116
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1044
1045 116
        foreach ($this->entityUpdates as $oid => $entity) {
1046 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...
1047 74
                continue;
1048
            }
1049
1050 116
            if ($preUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1051 13
                $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->getEntityChangeSet($entity)), $preUpdateInvoke);
1052
1053 13
                $this->recomputeSingleEntityChangeSet($class, $entity);
1054
            }
1055
1056 116
            if ( ! empty($this->entityChangeSets[$oid])) {
1057 82
                $persister->update($entity);
1058
            }
1059
1060 112
            unset($this->entityUpdates[$oid]);
1061
1062 112
            if ($postUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1063 112
                $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new LifecycleEventArgs($entity, $this->em), $postUpdateInvoke);
1064
            }
1065
        }
1066 112
    }
1067
1068
    /**
1069
     * Executes all entity deletions for entities of the specified type.
1070
     *
1071
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1072
     *
1073
     * @return void
1074
     */
1075 63
    private function executeDeletions($class)
1076
    {
1077 63
        $className  = $class->name;
1078 63
        $persister  = $this->getEntityPersister($className);
1079 63
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove);
1080
1081 63
        foreach ($this->entityDeletions as $oid => $entity) {
1082 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...
1083 26
                continue;
1084
            }
1085
1086 63
            $persister->delete($entity);
1087
1088
            unset(
1089 63
                $this->entityDeletions[$oid],
1090 63
                $this->entityIdentifiers[$oid],
1091 63
                $this->originalEntityData[$oid],
1092 63
                $this->entityStates[$oid]
1093
            );
1094
1095
            // Entity with this $oid after deletion treated as NEW, even if the $oid
1096
            // is obtained by a new entity because the old one went out of scope.
1097
            //$this->entityStates[$oid] = self::STATE_NEW;
1098 63
            if ( ! $class->isIdentifierNatural()) {
1099 53
                $class->reflFields[$class->identifier[0]]->setValue($entity, null);
1100
            }
1101
1102 63
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1103 63
                $this->listenersInvoker->invoke($class, Events::postRemove, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1104
            }
1105
        }
1106 62
    }
1107
1108
    /**
1109
     * Gets the commit order.
1110
     *
1111
     * @param array|null $entityChangeSet
1112
     *
1113
     * @return array
1114
     */
1115 1007
    private function getCommitOrder(array $entityChangeSet = null)
1116
    {
1117 1007
        if ($entityChangeSet === null) {
1118 1007
            $entityChangeSet = array_merge($this->entityInsertions, $this->entityUpdates, $this->entityDeletions);
1119
        }
1120
1121 1007
        $calc = $this->getCommitOrderCalculator();
1122
1123
        // See if there are any new classes in the changeset, that are not in the
1124
        // commit order graph yet (don't have a node).
1125
        // We have to inspect changeSet to be able to correctly build dependencies.
1126
        // It is not possible to use IdentityMap here because post inserted ids
1127
        // are not yet available.
1128 1007
        $newNodes = array();
1129
1130 1007
        foreach ($entityChangeSet as $entity) {
1131 1007
            $class = $this->em->getClassMetadata(get_class($entity));
1132
1133 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...
1134 624
                continue;
1135
            }
1136
1137 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...
1138
1139 1007
            $newNodes[] = $class;
1140
        }
1141
1142
        // Calculate dependencies for new nodes
1143 1007
        while ($class = array_pop($newNodes)) {
1144 1007
            foreach ($class->associationMappings as $assoc) {
1145 885
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1146 845
                    continue;
1147
                }
1148
1149 838
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1150
1151 838
                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...
1152 649
                    $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...
1153
1154 649
                    $newNodes[] = $targetClass;
1155
                }
1156
1157 838
                $joinColumns = reset($assoc['joinColumns']);
1158
1159 838
                $calc->addDependency($targetClass->name, $class->name, (int)empty($joinColumns['nullable']));
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1160
1161
                // If the target class has mapped subclasses, these share the same dependency.
1162 838
                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...
1163 831
                    continue;
1164
                }
1165
1166 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...
1167 217
                    $targetSubClass = $this->em->getClassMetadata($subClassName);
1168
1169 217
                    if ( ! $calc->hasNode($subClassName)) {
1170 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...
1171
1172 189
                        $newNodes[] = $targetSubClass;
1173
                    }
1174
1175 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...
1176
                }
1177
            }
1178
        }
1179
1180 1007
        return $calc->sort();
1181
    }
1182
1183
    /**
1184
     * Schedules an entity for insertion into the database.
1185
     * If the entity already has an identifier, it will be added to the identity map.
1186
     *
1187
     * @param object $entity The entity to schedule for insertion.
1188
     *
1189
     * @return void
1190
     *
1191
     * @throws ORMInvalidArgumentException
1192
     * @throws \InvalidArgumentException
1193
     */
1194 1025
    public function scheduleForInsert($entity)
1195
    {
1196 1025
        $oid = spl_object_hash($entity);
1197
1198 1025
        if (isset($this->entityUpdates[$oid])) {
1199
            throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion.");
1200
        }
1201
1202 1025
        if (isset($this->entityDeletions[$oid])) {
1203 1
            throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
1204
        }
1205 1025
        if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) {
1206 1
            throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
1207
        }
1208
1209 1025
        if (isset($this->entityInsertions[$oid])) {
1210 1
            throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
1211
        }
1212
1213 1025
        $this->entityInsertions[$oid] = $entity;
1214
1215 1025
        if (isset($this->entityIdentifiers[$oid])) {
1216 262
            $this->addToIdentityMap($entity);
1217
        }
1218
1219 1025
        if ($entity instanceof NotifyPropertyChanged) {
1220 5
            $entity->addPropertyChangedListener($this);
1221
        }
1222 1025
    }
1223
1224
    /**
1225
     * Checks whether an entity is scheduled for insertion.
1226
     *
1227
     * @param object $entity
1228
     *
1229
     * @return boolean
1230
     */
1231 630
    public function isScheduledForInsert($entity)
1232
    {
1233 630
        return isset($this->entityInsertions[spl_object_hash($entity)]);
1234
    }
1235
1236
    /**
1237
     * Schedules an entity for being updated.
1238
     *
1239
     * @param object $entity The entity to schedule for being updated.
1240
     *
1241
     * @return void
1242
     *
1243
     * @throws ORMInvalidArgumentException
1244
     */
1245 1
    public function scheduleForUpdate($entity)
1246
    {
1247 1
        $oid = spl_object_hash($entity);
1248
1249 1
        if ( ! isset($this->entityIdentifiers[$oid])) {
1250
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update");
1251
        }
1252
1253 1
        if (isset($this->entityDeletions[$oid])) {
1254
            throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update");
1255
        }
1256
1257 1
        if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) {
1258 1
            $this->entityUpdates[$oid] = $entity;
1259
        }
1260 1
    }
1261
1262
    /**
1263
     * INTERNAL:
1264
     * Schedules an extra update that will be executed immediately after the
1265
     * regular entity updates within the currently running commit cycle.
1266
     *
1267
     * Extra updates for entities are stored as (entity, changeset) tuples.
1268
     *
1269
     * @ignore
1270
     *
1271
     * @param object $entity    The entity for which to schedule an extra update.
1272
     * @param array  $changeset The changeset of the entity (what to update).
1273
     *
1274
     * @return void
1275
     */
1276 40
    public function scheduleExtraUpdate($entity, array $changeset)
1277
    {
1278 40
        $oid         = spl_object_hash($entity);
1279 40
        $extraUpdate = array($entity, $changeset);
1280
1281 40
        if (isset($this->extraUpdates[$oid])) {
1282 1
            list(, $changeset2) = $this->extraUpdates[$oid];
1283
1284 1
            $extraUpdate = array($entity, $changeset + $changeset2);
1285
        }
1286
1287 40
        $this->extraUpdates[$oid] = $extraUpdate;
1288 40
    }
1289
1290
    /**
1291
     * Checks whether an entity is registered as dirty in the unit of work.
1292
     * Note: Is not very useful currently as dirty entities are only registered
1293
     * at commit time.
1294
     *
1295
     * @param object $entity
1296
     *
1297
     * @return boolean
1298
     */
1299
    public function isScheduledForUpdate($entity)
1300
    {
1301
        return isset($this->entityUpdates[spl_object_hash($entity)]);
1302
    }
1303
1304
    /**
1305
     * Checks whether an entity is registered to be checked in the unit of work.
1306
     *
1307
     * @param object $entity
1308
     *
1309
     * @return boolean
1310
     */
1311 1
    public function isScheduledForDirtyCheck($entity)
1312
    {
1313 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...
1314
1315 1
        return isset($this->scheduledForSynchronization[$rootEntityName][spl_object_hash($entity)]);
1316
    }
1317
1318
    /**
1319
     * INTERNAL:
1320
     * Schedules an entity for deletion.
1321
     *
1322
     * @param object $entity
1323
     *
1324
     * @return void
1325
     */
1326 66
    public function scheduleForDelete($entity)
1327
    {
1328 66
        $oid = spl_object_hash($entity);
1329
1330 66
        if (isset($this->entityInsertions[$oid])) {
1331 1
            if ($this->isInIdentityMap($entity)) {
1332
                $this->removeFromIdentityMap($entity);
1333
            }
1334
1335 1
            unset($this->entityInsertions[$oid], $this->entityStates[$oid]);
1336
1337 1
            return; // entity has not been persisted yet, so nothing more to do.
1338
        }
1339
1340 66
        if ( ! $this->isInIdentityMap($entity)) {
1341 1
            return;
1342
        }
1343
1344 65
        $this->removeFromIdentityMap($entity);
1345
1346 65
        unset($this->entityUpdates[$oid]);
1347
1348 65
        if ( ! isset($this->entityDeletions[$oid])) {
1349 65
            $this->entityDeletions[$oid] = $entity;
1350 65
            $this->entityStates[$oid]    = self::STATE_REMOVED;
1351
        }
1352 65
    }
1353
1354
    /**
1355
     * Checks whether an entity is registered as removed/deleted with the unit
1356
     * of work.
1357
     *
1358
     * @param object $entity
1359
     *
1360
     * @return boolean
1361
     */
1362 17
    public function isScheduledForDelete($entity)
1363
    {
1364 17
        return isset($this->entityDeletions[spl_object_hash($entity)]);
1365
    }
1366
1367
    /**
1368
     * Checks whether an entity is scheduled for insertion, update or deletion.
1369
     *
1370
     * @param object $entity
1371
     *
1372
     * @return boolean
1373
     */
1374
    public function isEntityScheduled($entity)
1375
    {
1376
        $oid = spl_object_hash($entity);
1377
1378
        return isset($this->entityInsertions[$oid])
1379
            || isset($this->entityUpdates[$oid])
1380
            || isset($this->entityDeletions[$oid]);
1381
    }
1382
1383
    /**
1384
     * INTERNAL:
1385
     * Registers an entity in the identity map.
1386
     * Note that entities in a hierarchy are registered with the class name of
1387
     * the root entity.
1388
     *
1389
     * @ignore
1390
     *
1391
     * @param object $entity The entity to register.
1392
     *
1393
     * @return boolean TRUE if the registration was successful, FALSE if the identity of
1394
     *                 the entity in question is already managed.
1395
     *
1396
     * @throws ORMInvalidArgumentException
1397
     */
1398 1086
    public function addToIdentityMap($entity)
1399
    {
1400 1086
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1401 1086
        $idHash        = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]);
1402
1403 1086
        if ($idHash === '') {
1404 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...
1405
        }
1406
1407 1085
        $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...
1408
1409 1085
        if (isset($this->identityMap[$className][$idHash])) {
1410 78
            return false;
1411
        }
1412
1413 1085
        $this->identityMap[$className][$idHash] = $entity;
1414
1415 1085
        return true;
1416
    }
1417
1418
    /**
1419
     * Gets the state of an entity with regard to the current unit of work.
1420
     *
1421
     * @param object   $entity
1422
     * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED).
1423
     *                         This parameter can be set to improve performance of entity state detection
1424
     *                         by potentially avoiding a database lookup if the distinction between NEW and DETACHED
1425
     *                         is either known or does not matter for the caller of the method.
1426
     *
1427
     * @return int The entity state.
1428
     */
1429 1038
    public function getEntityState($entity, $assume = null)
1430
    {
1431 1038
        $oid = spl_object_hash($entity);
1432
1433 1038
        if (isset($this->entityStates[$oid])) {
1434 783
            return $this->entityStates[$oid];
1435
        }
1436
1437 1032
        if ($assume !== null) {
1438 1028
            return $assume;
1439
        }
1440
1441
        // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known.
1442
        // Note that you can not remember the NEW or DETACHED state in _entityStates since
1443
        // the UoW does not hold references to such objects and the object hash can be reused.
1444
        // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it.
1445 13
        $class = $this->em->getClassMetadata(get_class($entity));
1446 13
        $id    = $class->getIdentifierValues($entity);
1447
1448 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...
1449 5
            return self::STATE_NEW;
1450
        }
1451
1452 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...
1453 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...
1454
        }
1455
1456
        switch (true) {
1457 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...
1458
                // Check for a version field, if available, to avoid a db lookup.
1459 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...
1460 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...
1461
                        ? self::STATE_DETACHED
1462 1
                        : self::STATE_NEW;
1463
                }
1464
1465
                // Last try before db lookup: check the identity map.
1466 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...
1467 1
                    return self::STATE_DETACHED;
1468
                }
1469
1470
                // db lookup
1471 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...
1472
                    return self::STATE_DETACHED;
1473
                }
1474
1475 4
                return self::STATE_NEW;
1476
1477 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...
1478
                // if we have a pre insert generator we can't be sure that having an id
1479
                // really means that the entity exists. We have to verify this through
1480
                // the last resort: a db lookup
1481
1482
                // Last try before db lookup: check the identity map.
1483
                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...
1484
                    return self::STATE_DETACHED;
1485
                }
1486
1487
                // db lookup
1488
                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...
1489
                    return self::STATE_DETACHED;
1490
                }
1491
1492
                return self::STATE_NEW;
1493
1494
            default:
1495 5
                return self::STATE_DETACHED;
1496
        }
1497
    }
1498
1499
    /**
1500
     * INTERNAL:
1501
     * Removes an entity from the identity map. This effectively detaches the
1502
     * entity from the persistence management of Doctrine.
1503
     *
1504
     * @ignore
1505
     *
1506
     * @param object $entity
1507
     *
1508
     * @return boolean
1509
     *
1510
     * @throws ORMInvalidArgumentException
1511
     */
1512 77
    public function removeFromIdentityMap($entity)
1513
    {
1514 77
        $oid           = spl_object_hash($entity);
1515 77
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1516 77
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1517
1518 77
        if ($idHash === '') {
1519
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
1520
        }
1521
1522 77
        $className = $classMetadata->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1523
1524 77
        if (isset($this->identityMap[$className][$idHash])) {
1525 77
            unset($this->identityMap[$className][$idHash]);
1526 77
            unset($this->readOnlyObjects[$oid]);
1527
1528
            //$this->entityStates[$oid] = self::STATE_DETACHED;
1529
1530 77
            return true;
1531
        }
1532
1533
        return false;
1534
    }
1535
1536
    /**
1537
     * INTERNAL:
1538
     * Gets an entity in the identity map by its identifier hash.
1539
     *
1540
     * @ignore
1541
     *
1542
     * @param string $idHash
1543
     * @param string $rootClassName
1544
     *
1545
     * @return object
1546
     */
1547
    public function getByIdHash($idHash, $rootClassName)
1548
    {
1549
        return $this->identityMap[$rootClassName][$idHash];
1550
    }
1551
1552
    /**
1553
     * INTERNAL:
1554
     * Tries to get an entity by its identifier hash. If no entity is found for
1555
     * the given hash, FALSE is returned.
1556
     *
1557
     * @ignore
1558
     *
1559
     * @param mixed  $idHash        (must be possible to cast it to string)
1560
     * @param string $rootClassName
1561
     *
1562
     * @return object|bool The found entity or FALSE.
1563
     */
1564 34
    public function tryGetByIdHash($idHash, $rootClassName)
1565
    {
1566 34
        $stringIdHash = (string) $idHash;
1567
1568 34
        return isset($this->identityMap[$rootClassName][$stringIdHash])
1569 34
            ? $this->identityMap[$rootClassName][$stringIdHash]
1570 34
            : false;
1571
    }
1572
1573
    /**
1574
     * Checks whether an entity is registered in the identity map of this UnitOfWork.
1575
     *
1576
     * @param object $entity
1577
     *
1578
     * @return boolean
1579
     */
1580 213
    public function isInIdentityMap($entity)
1581
    {
1582 213
        $oid = spl_object_hash($entity);
1583
1584 213
        if ( ! isset($this->entityIdentifiers[$oid])) {
1585 31
            return false;
1586
        }
1587
1588 198
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1589 198
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1590
1591 198
        if ($idHash === '') {
1592
            return false;
1593
        }
1594
1595 198
        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...
1596
    }
1597
1598
    /**
1599
     * INTERNAL:
1600
     * Checks whether an identifier hash exists in the identity map.
1601
     *
1602
     * @ignore
1603
     *
1604
     * @param string $idHash
1605
     * @param string $rootClassName
1606
     *
1607
     * @return boolean
1608
     */
1609
    public function containsIdHash($idHash, $rootClassName)
1610
    {
1611
        return isset($this->identityMap[$rootClassName][$idHash]);
1612
    }
1613
1614
    /**
1615
     * Persists an entity as part of the current unit of work.
1616
     *
1617
     * @param object $entity The entity to persist.
1618
     *
1619
     * @return void
1620
     */
1621 1021
    public function persist($entity)
1622
    {
1623 1021
        $visited = array();
1624
1625 1021
        $this->doPersist($entity, $visited);
1626 1014
    }
1627
1628
    /**
1629
     * Persists an entity as part of the current unit of work.
1630
     *
1631
     * This method is internally called during persist() cascades as it tracks
1632
     * the already visited entities to prevent infinite recursions.
1633
     *
1634
     * @param object $entity  The entity to persist.
1635
     * @param array  $visited The already visited entities.
1636
     *
1637
     * @return void
1638
     *
1639
     * @throws ORMInvalidArgumentException
1640
     * @throws UnexpectedValueException
1641
     */
1642 1021
    private function doPersist($entity, array &$visited)
1643
    {
1644 1021
        $oid = spl_object_hash($entity);
1645
1646 1021
        if (isset($visited[$oid])) {
1647 109
            return; // Prevent infinite recursion
1648
        }
1649
1650 1021
        $visited[$oid] = $entity; // Mark visited
1651
1652 1021
        $class = $this->em->getClassMetadata(get_class($entity));
1653
1654
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1655
        // If we would detect DETACHED here we would throw an exception anyway with the same
1656
        // consequences (not recoverable/programming error), so just assuming NEW here
1657
        // lets us avoid some database lookups for entities with natural identifiers.
1658 1021
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1659
1660
        switch ($entityState) {
1661 1021
            case self::STATE_MANAGED:
1662
                // Nothing to do, except if policy is "deferred explicit"
1663 234
                if ($class->isChangeTrackingDeferredExplicit()) {
1664 2
                    $this->scheduleForDirtyCheck($entity);
1665
                }
1666 234
                break;
1667
1668 1021
            case self::STATE_NEW:
1669 1020
                $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...
1670 1020
                break;
1671
1672 1
            case self::STATE_REMOVED:
1673
                // Entity becomes managed again
1674 1
                unset($this->entityDeletions[$oid]);
1675 1
                $this->addToIdentityMap($entity);
1676
1677 1
                $this->entityStates[$oid] = self::STATE_MANAGED;
1678 1
                break;
1679
1680
            case self::STATE_DETACHED:
1681
                // Can actually not happen right now since we assume STATE_NEW.
1682
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
1683
1684
            default:
1685
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1686
        }
1687
1688 1021
        $this->cascadePersist($entity, $visited);
1689 1014
    }
1690
1691
    /**
1692
     * Deletes an entity as part of the current unit of work.
1693
     *
1694
     * @param object $entity The entity to remove.
1695
     *
1696
     * @return void
1697
     */
1698 65
    public function remove($entity)
1699
    {
1700 65
        $visited = array();
1701
1702 65
        $this->doRemove($entity, $visited);
1703 65
    }
1704
1705
    /**
1706
     * Deletes an entity as part of the current unit of work.
1707
     *
1708
     * This method is internally called during delete() cascades as it tracks
1709
     * the already visited entities to prevent infinite recursions.
1710
     *
1711
     * @param object $entity  The entity to delete.
1712
     * @param array  $visited The map of the already visited entities.
1713
     *
1714
     * @return void
1715
     *
1716
     * @throws ORMInvalidArgumentException If the instance is a detached entity.
1717
     * @throws UnexpectedValueException
1718
     */
1719 65
    private function doRemove($entity, array &$visited)
1720
    {
1721 65
        $oid = spl_object_hash($entity);
1722
1723 65
        if (isset($visited[$oid])) {
1724 1
            return; // Prevent infinite recursion
1725
        }
1726
1727 65
        $visited[$oid] = $entity; // mark visited
1728
1729
        // Cascade first, because scheduleForDelete() removes the entity from the identity map, which
1730
        // can cause problems when a lazy proxy has to be initialized for the cascade operation.
1731 65
        $this->cascadeRemove($entity, $visited);
1732
1733 65
        $class       = $this->em->getClassMetadata(get_class($entity));
1734 65
        $entityState = $this->getEntityState($entity);
1735
1736
        switch ($entityState) {
1737 65
            case self::STATE_NEW:
1738 65
            case self::STATE_REMOVED:
1739
                // nothing to do
1740 2
                break;
1741
1742 65
            case self::STATE_MANAGED:
1743 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...
1744
1745 65
                if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1746 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...
1747
                }
1748
1749 65
                $this->scheduleForDelete($entity);
1750 65
                break;
1751
1752
            case self::STATE_DETACHED:
1753
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1754
            default:
1755
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1756
        }
1757
1758 65
    }
1759
1760
    /**
1761
     * Merges the state of the given detached entity into this UnitOfWork.
1762
     *
1763
     * @param object $entity
1764
     *
1765
     * @return object The managed copy of the entity.
1766
     *
1767
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1768
     *         attribute and the version check against the managed copy fails.
1769
     *
1770
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1771
     */
1772 40
    public function merge($entity)
1773
    {
1774 40
        $visited = array();
1775
1776 40
        return $this->doMerge($entity, $visited);
1777
    }
1778
1779
    /**
1780
     * Executes a merge operation on an entity.
1781
     *
1782
     * @param object      $entity
1783
     * @param array       $visited
1784
     * @param object|null $prevManagedCopy
1785
     * @param array|null  $assoc
1786
     *
1787
     * @return object The managed copy of the entity.
1788
     *
1789
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1790
     *         attribute and the version check against the managed copy fails.
1791
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1792
     * @throws EntityNotFoundException
1793
     */
1794 40
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, array $assoc = [])
1795
    {
1796 40
        $oid = spl_object_hash($entity);
1797
1798 40
        if (isset($visited[$oid])) {
1799 4
            $managedCopy = $visited[$oid];
1800
1801 4
            if ($prevManagedCopy !== null) {
1802 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
1803
            }
1804
1805 4
            return $managedCopy;
1806
        }
1807
1808 40
        $class = $this->em->getClassMetadata(get_class($entity));
1809
1810
        // First we assume DETACHED, although it can still be NEW but we can avoid
1811
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1812
        // we need to fetch it from the db anyway in order to merge.
1813
        // MANAGED entities are ignored by the merge operation.
1814 40
        $managedCopy = $entity;
1815
1816 40
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1817
            // Try to look the entity up in the identity map.
1818 39
            $id = $class->getIdentifierValues($entity);
1819
1820
            // If there is no ID, it is actually NEW.
1821 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...
1822 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...
1823
1824 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...
1825
            } else {
1826 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...
1827 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...
1828 35
                    : $id;
1829
1830 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 1894 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1831
1832 35
                if ($managedCopy) {
1833
                    // We have the entity in-memory already, just make sure its not removed.
1834 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 1830 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...
1835 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 1830 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...
1836
                    }
1837
                } else {
1838
                    // We need to fetch the managed copy in order to merge.
1839 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...
1840
                }
1841
1842 35
                if ($managedCopy === null) {
1843
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1844
                    // since the managed entity was not found.
1845 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...
1846 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1847 1
                            $class->getName(),
1848 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...
1849
                        );
1850
                    }
1851
1852 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...
1853 1
                    $class->setIdentifierValues($managedCopy, $id);
1854
1855 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...
1856
                }
1857
            }
1858
1859 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 1830 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...
1860 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...
1861 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1862 4
                $entityVersion      = $reflField->getValue($entity);
1863
1864
                // Throw exception if versions don't match.
1865 4
                if ($managedCopyVersion != $entityVersion) {
1866 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1867
                }
1868
            }
1869
1870 37
            $visited[$oid] = $managedCopy; // mark visited
1871
1872 37
            if ($this->isLoaded($entity)) {
1873 30
                if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) {
1874 4
                    $managedCopy->__load();
1875
                }
1876
1877 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 1830 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...
1878
            }
1879
1880 37
            if ($class->isChangeTrackingDeferredExplicit()) {
1881
                $this->scheduleForDirtyCheck($entity);
1882
            }
1883
        }
1884
1885 38
        if ($prevManagedCopy !== null) {
1886 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 1830 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...
1887
        }
1888
1889
        // Mark the managed copy visited as well
1890 38
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1891
1892 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 1830 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...
1893
1894 38
        return $managedCopy;
1895
    }
1896
1897
    /**
1898
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1899
     *
1900
     * @param object $entity
1901
     *
1902
     * @return bool
1903
     */
1904 38
    private function isLoaded($entity)
1905
    {
1906 38
        return !($entity instanceof Proxy) || $entity->__isInitialized();
1907
    }
1908
1909
    /**
1910
     * Sets/adds associated managed copies into the previous entity's association field
1911
     *
1912
     * @param object $entity
1913
     * @param array  $association
1914
     * @param object $previousManagedCopy
1915
     * @param object $managedCopy
1916
     *
1917
     * @return void
1918
     */
1919 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1920
    {
1921 6
        $assocField = $association['fieldName'];
1922 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1923
1924 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1925 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...
1926
1927 6
            return;
1928
        }
1929
1930 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...
1931 1
        $value[] = $managedCopy;
1932
1933 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1934 1
            $class = $this->em->getClassMetadata(get_class($entity));
1935
1936 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...
1937
        }
1938 1
    }
1939
1940
    /**
1941
     * Detaches an entity from the persistence management. It's persistence will
1942
     * no longer be managed by Doctrine.
1943
     *
1944
     * @param object $entity The entity to detach.
1945
     *
1946
     * @return void
1947
     */
1948 12
    public function detach($entity)
1949
    {
1950 12
        $visited = array();
1951
1952 12
        $this->doDetach($entity, $visited);
1953 12
    }
1954
1955
    /**
1956
     * Executes a detach operation on the given entity.
1957
     *
1958
     * @param object  $entity
1959
     * @param array   $visited
1960
     * @param boolean $noCascade if true, don't cascade detach operation.
1961
     *
1962
     * @return void
1963
     */
1964 15
    private function doDetach($entity, array &$visited, $noCascade = false)
1965
    {
1966 15
        $oid = spl_object_hash($entity);
1967
1968 15
        if (isset($visited[$oid])) {
1969
            return; // Prevent infinite recursion
1970
        }
1971
1972 15
        $visited[$oid] = $entity; // mark visited
1973
1974 15
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
1975 15
            case self::STATE_MANAGED:
1976 13
                if ($this->isInIdentityMap($entity)) {
1977 12
                    $this->removeFromIdentityMap($entity);
1978
                }
1979
1980
                unset(
1981 13
                    $this->entityInsertions[$oid],
1982 13
                    $this->entityUpdates[$oid],
1983 13
                    $this->entityDeletions[$oid],
1984 13
                    $this->entityIdentifiers[$oid],
1985 13
                    $this->entityStates[$oid],
1986 13
                    $this->originalEntityData[$oid]
1987
                );
1988 13
                break;
1989 3
            case self::STATE_NEW:
1990 3
            case self::STATE_DETACHED:
1991 3
                return;
1992
        }
1993
1994 13
        if ( ! $noCascade) {
1995 13
            $this->cascadeDetach($entity, $visited);
1996
        }
1997 13
    }
1998
1999
    /**
2000
     * Refreshes the state of the given entity from the database, overwriting
2001
     * any local, unpersisted changes.
2002
     *
2003
     * @param object $entity The entity to refresh.
2004
     *
2005
     * @return void
2006
     *
2007
     * @throws InvalidArgumentException If the entity is not MANAGED.
2008
     */
2009 17
    public function refresh($entity)
2010
    {
2011 17
        $visited = array();
2012
2013 17
        $this->doRefresh($entity, $visited);
2014 17
    }
2015
2016
    /**
2017
     * Executes a refresh operation on an entity.
2018
     *
2019
     * @param object $entity  The entity to refresh.
2020
     * @param array  $visited The already visited entities during cascades.
2021
     *
2022
     * @return void
2023
     *
2024
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2025
     */
2026 17
    private function doRefresh($entity, array &$visited)
2027
    {
2028 17
        $oid = spl_object_hash($entity);
2029
2030 17
        if (isset($visited[$oid])) {
2031
            return; // Prevent infinite recursion
2032
        }
2033
2034 17
        $visited[$oid] = $entity; // mark visited
2035
2036 17
        $class = $this->em->getClassMetadata(get_class($entity));
2037
2038 17
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2039
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2040
        }
2041
2042 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...
2043 17
            array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2044
            $entity
2045
        );
2046
2047 17
        $this->cascadeRefresh($entity, $visited);
2048 17
    }
2049
2050
    /**
2051
     * Cascades a refresh operation to associated entities.
2052
     *
2053
     * @param object $entity
2054
     * @param array  $visited
2055
     *
2056
     * @return void
2057
     */
2058 17
    private function cascadeRefresh($entity, array &$visited)
2059
    {
2060 17
        $class = $this->em->getClassMetadata(get_class($entity));
2061
2062 17
        $associationMappings = array_filter(
2063 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...
2064
            function ($assoc) { return $assoc['isCascadeRefresh']; }
2065
        );
2066
2067 17
        foreach ($associationMappings as $assoc) {
2068 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...
2069
2070
            switch (true) {
2071 5
                case ($relatedEntities instanceof PersistentCollection):
2072
                    // Unwrap so that foreach() does not initialize
2073 5
                    $relatedEntities = $relatedEntities->unwrap();
2074
                    // break; is commented intentionally!
2075
2076
                case ($relatedEntities instanceof Collection):
2077
                case (is_array($relatedEntities)):
2078 5
                    foreach ($relatedEntities as $relatedEntity) {
2079
                        $this->doRefresh($relatedEntity, $visited);
2080
                    }
2081 5
                    break;
2082
2083
                case ($relatedEntities !== null):
2084
                    $this->doRefresh($relatedEntities, $visited);
2085
                    break;
2086
2087 5
                default:
2088
                    // Do nothing
2089
            }
2090
        }
2091 17
    }
2092
2093
    /**
2094
     * Cascades a detach operation to associated entities.
2095
     *
2096
     * @param object $entity
2097
     * @param array  $visited
2098
     *
2099
     * @return void
2100
     */
2101 13
    private function cascadeDetach($entity, array &$visited)
2102
    {
2103 13
        $class = $this->em->getClassMetadata(get_class($entity));
2104
2105 13
        $associationMappings = array_filter(
2106 13
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2107
            function ($assoc) { return $assoc['isCascadeDetach']; }
2108
        );
2109
2110 13
        foreach ($associationMappings as $assoc) {
2111 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...
2112
2113
            switch (true) {
2114 3
                case ($relatedEntities instanceof PersistentCollection):
2115
                    // Unwrap so that foreach() does not initialize
2116 2
                    $relatedEntities = $relatedEntities->unwrap();
2117
                    // break; is commented intentionally!
2118
2119
                case ($relatedEntities instanceof Collection):
2120
                case (is_array($relatedEntities)):
2121 3
                    foreach ($relatedEntities as $relatedEntity) {
2122 1
                        $this->doDetach($relatedEntity, $visited);
2123
                    }
2124 3
                    break;
2125
2126
                case ($relatedEntities !== null):
2127
                    $this->doDetach($relatedEntities, $visited);
2128
                    break;
2129
2130 3
                default:
2131
                    // Do nothing
2132
            }
2133
        }
2134 13
    }
2135
2136
    /**
2137
     * Cascades a merge operation to associated entities.
2138
     *
2139
     * @param object $entity
2140
     * @param object $managedCopy
2141
     * @param array  $visited
2142
     *
2143
     * @return void
2144
     */
2145 38
    private function cascadeMerge($entity, $managedCopy, array &$visited)
2146
    {
2147 38
        $class = $this->em->getClassMetadata(get_class($entity));
2148
2149 38
        $associationMappings = array_filter(
2150 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...
2151
            function ($assoc) { return $assoc['isCascadeMerge']; }
2152
        );
2153
2154 38
        foreach ($associationMappings as $assoc) {
2155 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...
2156
2157 15
            if ($relatedEntities instanceof Collection) {
2158 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...
2159 1
                    continue;
2160
                }
2161
2162 8
                if ($relatedEntities instanceof PersistentCollection) {
2163
                    // Unwrap so that foreach() does not initialize
2164 5
                    $relatedEntities = $relatedEntities->unwrap();
2165
                }
2166
2167 8
                foreach ($relatedEntities as $relatedEntity) {
2168 8
                    $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
2169
                }
2170 7
            } else if ($relatedEntities !== null) {
2171 14
                $this->doMerge($relatedEntities, $visited, $managedCopy, $assoc);
2172
            }
2173
        }
2174 38
    }
2175
2176
    /**
2177
     * Cascades the save operation to associated entities.
2178
     *
2179
     * @param object $entity
2180
     * @param array  $visited
2181
     *
2182
     * @return void
2183
     */
2184 1021
    private function cascadePersist($entity, array &$visited)
2185
    {
2186 1021
        $class = $this->em->getClassMetadata(get_class($entity));
2187
2188 1021
        $associationMappings = array_filter(
2189 1021
            $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...
2190
            function ($assoc) { return $assoc['isCascadePersist']; }
2191
        );
2192
2193 1021
        foreach ($associationMappings as $assoc) {
2194 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...
2195
2196
            switch (true) {
2197 649
                case ($relatedEntities instanceof PersistentCollection):
2198
                    // Unwrap so that foreach() does not initialize
2199 21
                    $relatedEntities = $relatedEntities->unwrap();
2200
                    // break; is commented intentionally!
2201
2202
                case ($relatedEntities instanceof Collection):
2203 589
                case (is_array($relatedEntities)):
2204 553
                    if (($assoc['type'] & ClassMetadata::TO_MANY) <= 0) {
2205 3
                        throw ORMInvalidArgumentException::invalidAssociation(
2206 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...
2207
                            $assoc,
2208
                            $relatedEntities
2209
                        );
2210
                    }
2211
2212 550
                    foreach ($relatedEntities as $relatedEntity) {
2213 282
                        $this->doPersist($relatedEntity, $visited);
2214
                    }
2215
2216 550
                    break;
2217
2218 579
                case ($relatedEntities !== null):
2219 246
                    if (! $relatedEntities instanceof $assoc['targetEntity']) {
2220 4
                        throw ORMInvalidArgumentException::invalidAssociation(
2221 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...
2222
                            $assoc,
2223
                            $relatedEntities
2224
                        );
2225
                    }
2226
2227 242
                    $this->doPersist($relatedEntities, $visited);
2228 242
                    break;
2229
2230 643
                default:
2231
                    // Do nothing
2232
            }
2233
        }
2234 1014
    }
2235
2236
    /**
2237
     * Cascades the delete operation to associated entities.
2238
     *
2239
     * @param object $entity
2240
     * @param array  $visited
2241
     *
2242
     * @return void
2243
     */
2244 65
    private function cascadeRemove($entity, array &$visited)
2245
    {
2246 65
        $class = $this->em->getClassMetadata(get_class($entity));
2247
2248 65
        $associationMappings = array_filter(
2249 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...
2250
            function ($assoc) { return $assoc['isCascadeRemove']; }
2251
        );
2252
2253 65
        $entitiesToCascade = array();
2254
2255 65
        foreach ($associationMappings as $assoc) {
2256 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...
2257 6
                $entity->__load();
2258
            }
2259
2260 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...
2261
2262
            switch (true) {
2263 26
                case ($relatedEntities instanceof Collection):
2264 19
                case (is_array($relatedEntities)):
2265
                    // If its a PersistentCollection initialization is intended! No unwrap!
2266 20
                    foreach ($relatedEntities as $relatedEntity) {
2267 10
                        $entitiesToCascade[] = $relatedEntity;
2268
                    }
2269 20
                    break;
2270
2271 19
                case ($relatedEntities !== null):
2272 7
                    $entitiesToCascade[] = $relatedEntities;
2273 7
                    break;
2274
2275 26
                default:
2276
                    // Do nothing
2277
            }
2278
        }
2279
2280 65
        foreach ($entitiesToCascade as $relatedEntity) {
2281 16
            $this->doRemove($relatedEntity, $visited);
2282
        }
2283 65
    }
2284
2285
    /**
2286
     * Acquire a lock on the given entity.
2287
     *
2288
     * @param object $entity
2289
     * @param int    $lockMode
2290
     * @param int    $lockVersion
2291
     *
2292
     * @return void
2293
     *
2294
     * @throws ORMInvalidArgumentException
2295
     * @throws TransactionRequiredException
2296
     * @throws OptimisticLockException
2297
     */
2298 11
    public function lock($entity, $lockMode, $lockVersion = null)
2299
    {
2300 11
        if ($entity === null) {
2301 1
            throw new \InvalidArgumentException("No entity passed to UnitOfWork#lock().");
2302
        }
2303
2304 10
        if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
2305 1
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2306
        }
2307
2308 9
        $class = $this->em->getClassMetadata(get_class($entity));
2309
2310
        switch (true) {
2311 9
            case LockMode::OPTIMISTIC === $lockMode:
2312 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...
2313 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...
2314
                }
2315
2316 4
                if ($lockVersion === null) {
2317
                    return;
2318
                }
2319
2320 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...
2321 1
                    $entity->__load();
2322
                }
2323
2324 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...
2325
2326 4
                if ($entityVersion != $lockVersion) {
2327 2
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion);
2328
                }
2329
2330 2
                break;
2331
2332 3
            case LockMode::NONE === $lockMode:
2333 3
            case LockMode::PESSIMISTIC_READ === $lockMode:
2334 1
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
2335 3
                if (!$this->em->getConnection()->isTransactionActive()) {
2336 2
                    throw TransactionRequiredException::transactionRequired();
2337
                }
2338
2339 1
                $oid = spl_object_hash($entity);
2340
2341 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...
2342 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2343
                    $lockMode
2344
                );
2345 1
                break;
2346
2347
            default:
2348
                // Do nothing
2349
        }
2350 3
    }
2351
2352
    /**
2353
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2354
     *
2355
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2356
     */
2357 1007
    public function getCommitOrderCalculator()
2358
    {
2359 1007
        return new Internal\CommitOrderCalculator();
2360
    }
2361
2362
    /**
2363
     * Clears the UnitOfWork.
2364
     *
2365
     * @param string|null $entityName if given, only entities of this type will get detached.
2366
     *
2367
     * @return void
2368
     */
2369 1218
    public function clear($entityName = null)
2370
    {
2371 1218
        if ($entityName === null) {
2372 1217
            $this->identityMap =
2373 1217
            $this->entityIdentifiers =
2374 1217
            $this->originalEntityData =
2375 1217
            $this->entityChangeSets =
2376 1217
            $this->entityStates =
2377 1217
            $this->scheduledForSynchronization =
2378 1217
            $this->entityInsertions =
2379 1217
            $this->entityUpdates =
2380 1217
            $this->entityDeletions =
2381 1217
            $this->collectionDeletions =
2382 1217
            $this->collectionUpdates =
2383 1217
            $this->extraUpdates =
2384 1217
            $this->readOnlyObjects =
2385 1217
            $this->visitedCollections =
2386 1217
            $this->orphanRemovals = array();
2387
        } else {
2388 3
            $this->clearIdentityMapForEntityName($entityName);
2389 3
            $this->clearEntityInsertionsForEntityName($entityName);
2390
        }
2391
2392 1218
        if ($this->evm->hasListeners(Events::onClear)) {
2393 7
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2394
        }
2395 1218
    }
2396
2397
    /**
2398
     * INTERNAL:
2399
     * Schedules an orphaned entity for removal. The remove() operation will be
2400
     * invoked on that entity at the beginning of the next commit of this
2401
     * UnitOfWork.
2402
     *
2403
     * @ignore
2404
     *
2405
     * @param object $entity
2406
     *
2407
     * @return void
2408
     */
2409 17
    public function scheduleOrphanRemoval($entity)
2410
    {
2411 17
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2412 17
    }
2413
2414
    /**
2415
     * INTERNAL:
2416
     * Cancels a previously scheduled orphan removal.
2417
     *
2418
     * @ignore
2419
     *
2420
     * @param object $entity
2421
     *
2422
     * @return void
2423
     */
2424 112
    public function cancelOrphanRemoval($entity)
2425
    {
2426 112
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2427 112
    }
2428
2429
    /**
2430
     * INTERNAL:
2431
     * Schedules a complete collection for removal when this UnitOfWork commits.
2432
     *
2433
     * @param PersistentCollection $coll
2434
     *
2435
     * @return void
2436
     */
2437 13
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2438
    {
2439 13
        $coid = spl_object_hash($coll);
2440
2441
        // TODO: if $coll is already scheduled for recreation ... what to do?
2442
        // Just remove $coll from the scheduled recreations?
2443 13
        unset($this->collectionUpdates[$coid]);
2444
2445 13
        $this->collectionDeletions[$coid] = $coll;
2446 13
    }
2447
2448
    /**
2449
     * @param PersistentCollection $coll
2450
     *
2451
     * @return bool
2452
     */
2453
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2454
    {
2455
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2456
    }
2457
2458
    /**
2459
     * @param ClassMetadata $class
2460
     *
2461
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2462
     */
2463 669
    private function newInstance($class)
2464
    {
2465 669
        $entity = $class->newInstance();
2466
2467 669
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2468 4
            $entity->injectObjectManager($this->em, $class);
2469
        }
2470
2471 669
        return $entity;
2472
    }
2473
2474
    /**
2475
     * INTERNAL:
2476
     * Creates an entity. Used for reconstitution of persistent entities.
2477
     *
2478
     * Internal note: Highly performance-sensitive method.
2479
     *
2480
     * @ignore
2481
     *
2482
     * @param string $className The name of the entity class.
2483
     * @param array  $data      The data for the entity.
2484
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2485
     *
2486
     * @return object The managed entity instance.
2487
     *
2488
     * @todo Rename: getOrCreateEntity
2489
     */
2490 808
    public function createEntity($className, array $data, &$hints = array())
2491
    {
2492 808
        $class = $this->em->getClassMetadata($className);
2493
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2494
2495 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...
2496 808
        $idHash = implode(' ', $id);
2497
2498 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...
2499 313
            $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...
2500 313
            $oid = spl_object_hash($entity);
2501
2502
            if (
2503 313
                isset($hints[Query::HINT_REFRESH])
2504 313
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2505 313
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2506 313
                && $unmanagedProxy instanceof Proxy
2507 313
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2508
            ) {
2509
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2510
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2511
                // refreshed object may be anything
2512
2513 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...
2514 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...
2515
                }
2516
2517 2
                return $unmanagedProxy;
2518
            }
2519
2520 311
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2521 22
                $entity->__setInitialized(true);
2522
2523 22
                $overrideLocalValues = true;
2524
2525 22
                if ($entity instanceof NotifyPropertyChanged) {
2526 22
                    $entity->addPropertyChangedListener($this);
2527
                }
2528
            } else {
2529 291
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2530
2531
                // If only a specific entity is set to refresh, check that it's the one
2532 291
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2533 72
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2534
                }
2535
            }
2536
2537 311
            if ($overrideLocalValues) {
2538
                // inject ObjectManager upon refresh.
2539 114
                if ($entity instanceof ObjectManagerAware) {
2540 3
                    $entity->injectObjectManager($this->em, $class);
2541
                }
2542
2543 311
                $this->originalEntityData[$oid] = $data;
2544
            }
2545
        } else {
2546 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...
2547 666
            $oid    = spl_object_hash($entity);
2548
2549 666
            $this->entityIdentifiers[$oid]  = $id;
2550 666
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2551 666
            $this->originalEntityData[$oid] = $data;
2552
2553 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...
2554
2555 666
            if ($entity instanceof NotifyPropertyChanged) {
2556 2
                $entity->addPropertyChangedListener($this);
2557
            }
2558
2559 666
            $overrideLocalValues = true;
2560
        }
2561
2562 807
        if ( ! $overrideLocalValues) {
2563 220
            return $entity;
2564
        }
2565
2566 704
        foreach ($data as $field => $value) {
2567 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...
2568 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...
2569
            }
2570
        }
2571
2572
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2573 704
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2574
2575 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...
2576
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2577
        }
2578
2579
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2580 704
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2581 33
            return $entity;
2582
        }
2583
2584 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...
2585
            // Check if the association is not among the fetch-joined associations already.
2586 587
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2587 260
                continue;
2588
            }
2589
2590 565
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2591
2592
            switch (true) {
2593 565
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2594 485
                    if ( ! $assoc['isOwningSide']) {
2595
2596
                        // use the given entity association
2597 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2598
2599 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2600
2601 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...
2602 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...
2603
2604 2
                            continue 2;
2605
                        }
2606
2607
                        // Inverse side of x-to-one can never be lazy
2608 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...
2609
2610 62
                        continue 2;
2611
                    }
2612
2613
                    // use the entity association
2614 485
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2615 38
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2616 38
                        $this->originalEntityData[$oid][$field] = $data[$field];
2617
2618 38
                        continue;
2619
                    }
2620
2621 478
                    $associatedId = array();
2622
2623
                    // TODO: Is this even computed right in all cases of composite keys?
2624 478
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2625 478
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2626
2627 478
                        if ($joinColumnValue !== null) {
2628 283
                            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...
2629 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2630
                            } else {
2631 283
                                $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...
2632
                            }
2633 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...
2634 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...
2635
                        ) {
2636
                            // the missing key is part of target's entity primary key
2637 7
                            $associatedId = array();
2638 478
                            break;
2639
                        }
2640
                    }
2641
2642 478
                    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...
2643
                        // Foreign key is NULL
2644 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...
2645 287
                        $this->originalEntityData[$oid][$field] = null;
2646
2647 287
                        continue;
2648
                    }
2649
2650 283
                    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...
2651 280
                        $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...
2652
                    }
2653
2654
                    // Foreign key is set
2655
                    // Check identity map first
2656
                    // FIXME: Can break easily with composite keys if join column values are in
2657
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2658 283
                    $relatedIdHash = implode(' ', $associatedId);
2659
2660
                    switch (true) {
2661 283
                        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...
2662 165
                            $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...
2663
2664
                            // If this is an uninitialized proxy, we are deferring eager loads,
2665
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2666
                            // then we can append this entity for eager loading!
2667 165
                            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...
2668 165
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2669 165
                                !$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...
2670 165
                                $newValue instanceof Proxy &&
2671 165
                                $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...
2672
2673
                                $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...
2674
                            }
2675
2676 165
                            break;
2677
2678 192
                        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...
2679
                            // If it might be a subtype, it can not be lazy. There isn't even
2680
                            // a way to solve this with deferred eager loading, which means putting
2681
                            // an entity with subclasses at a *-to-one location is really bad! (performance-wise)
2682 30
                            $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
2683 30
                            break;
2684
2685
                        default:
2686
                            switch (true) {
2687
                                // We are negating the condition here. Other cases will assume it is valid!
2688 163
                                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...
2689 156
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2690 156
                                    break;
2691
2692
                                // Deferred eager load only works for single identifier classes
2693 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...
2694
                                    // TODO: Is there a faster approach?
2695 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...
2696
2697 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2698 7
                                    break;
2699
2700
                                default:
2701
                                    // TODO: This is very imperformant, ignore it?
2702
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2703
                                    break;
2704
                            }
2705
2706
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2707 163
                            $newValueOid = spl_object_hash($newValue);
2708 163
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2709 163
                            $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...
2710
2711
                            if (
2712 163
                                $newValue instanceof NotifyPropertyChanged &&
2713 163
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2714
                            ) {
2715
                                $newValue->addPropertyChangedListener($this);
2716
                            }
2717 163
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2718
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2719 163
                            break;
2720
                    }
2721
2722 283
                    $this->originalEntityData[$oid][$field] = $newValue;
2723 283
                    $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...
2724
2725 283
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2726 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...
2727 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...
2728
                    }
2729
2730 283
                    break;
2731
2732
                default:
2733
                    // Ignore if its a cached collection
2734 487
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2735
                        break;
2736
                    }
2737
2738
                    // use the given collection
2739 487
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2740
2741 3
                        $data[$field]->setOwner($entity, $assoc);
2742
2743 3
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2744 3
                        $this->originalEntityData[$oid][$field] = $data[$field];
2745
2746 3
                        break;
2747
                    }
2748
2749
                    // Inject collection
2750 487
                    $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...
2751 487
                    $pColl->setOwner($entity, $assoc);
2752 487
                    $pColl->setInitialized(false);
2753
2754 487
                    $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...
2755 487
                    $reflField->setValue($entity, $pColl);
2756
2757 487
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2758 4
                        $this->loadCollection($pColl);
2759 4
                        $pColl->takeSnapshot();
2760
                    }
2761
2762 487
                    $this->originalEntityData[$oid][$field] = $pColl;
2763 565
                    break;
2764
            }
2765
        }
2766
2767 671
        if ($overrideLocalValues) {
2768
            // defer invoking of postLoad event to hydration complete step
2769 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...
2770
        }
2771
2772 671
        return $entity;
2773
    }
2774
2775
    /**
2776
     * @return void
2777
     */
2778 865
    public function triggerEagerLoads()
2779
    {
2780 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...
2781 865
            return;
2782
        }
2783
2784
        // avoid infinite recursion
2785 7
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2786 7
        $this->eagerLoadingEntities = array();
2787
2788 7
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2789 7
            if ( ! $ids) {
2790
                continue;
2791
            }
2792
2793 7
            $class = $this->em->getClassMetadata($entityName);
2794
2795 7
            $this->getEntityPersister($entityName)->loadAll(
2796 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...
2797
            );
2798
        }
2799 7
    }
2800
2801
    /**
2802
     * Initializes (loads) an uninitialized persistent collection of an entity.
2803
     *
2804
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2805
     *
2806
     * @return void
2807
     *
2808
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2809
     */
2810 143
    public function loadCollection(PersistentCollection $collection)
2811
    {
2812 143
        $assoc     = $collection->getMapping();
2813 143
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2814
2815 143
        switch ($assoc['type']) {
2816 143
            case ClassMetadata::ONE_TO_MANY:
2817 76
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2818 76
                break;
2819
2820 81
            case ClassMetadata::MANY_TO_MANY:
2821 81
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2822 81
                break;
2823
        }
2824
2825 143
        $collection->setInitialized(true);
2826 143
    }
2827
2828
    /**
2829
     * Gets the identity map of the UnitOfWork.
2830
     *
2831
     * @return array
2832
     */
2833 2
    public function getIdentityMap()
2834
    {
2835 2
        return $this->identityMap;
2836
    }
2837
2838
    /**
2839
     * Gets the original data of an entity. The original data is the data that was
2840
     * present at the time the entity was reconstituted from the database.
2841
     *
2842
     * @param object $entity
2843
     *
2844
     * @return array
2845
     */
2846 115
    public function getOriginalEntityData($entity)
2847
    {
2848 115
        $oid = spl_object_hash($entity);
2849
2850 115
        return isset($this->originalEntityData[$oid])
2851 112
            ? $this->originalEntityData[$oid]
2852 115
            : [];
2853
    }
2854
2855
    /**
2856
     * @ignore
2857
     *
2858
     * @param object $entity
2859
     * @param array  $data
2860
     *
2861
     * @return void
2862
     */
2863
    public function setOriginalEntityData($entity, array $data)
2864
    {
2865
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2866
    }
2867
2868
    /**
2869
     * INTERNAL:
2870
     * Sets a property value of the original data array of an entity.
2871
     *
2872
     * @ignore
2873
     *
2874
     * @param string $oid
2875
     * @param string $property
2876
     * @param mixed  $value
2877
     *
2878
     * @return void
2879
     */
2880 313
    public function setOriginalEntityProperty($oid, $property, $value)
2881
    {
2882 313
        $this->originalEntityData[$oid][$property] = $value;
2883 313
    }
2884
2885
    /**
2886
     * Gets the identifier of an entity.
2887
     * The returned value is always an array of identifier values. If the entity
2888
     * has a composite identifier then the identifier values are in the same
2889
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2890
     *
2891
     * @param object $entity
2892
     *
2893
     * @return array The identifier values.
2894
     */
2895 843
    public function getEntityIdentifier($entity)
2896
    {
2897 843
        return $this->entityIdentifiers[spl_object_hash($entity)];
2898
    }
2899
2900
    /**
2901
     * Processes an entity instance to extract their identifier values.
2902
     *
2903
     * @param object $entity The entity instance.
2904
     *
2905
     * @return mixed A scalar value.
2906
     *
2907
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2908
     */
2909 126
    public function getSingleIdentifierValue($entity)
2910
    {
2911 126
        $class = $this->em->getClassMetadata(get_class($entity));
2912
2913 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...
2914
            throw ORMInvalidArgumentException::invalidCompositeIdentifier();
2915
        }
2916
2917 126
        $values = $this->isInIdentityMap($entity)
2918 113
            ? $this->getEntityIdentifier($entity)
2919 126
            : $class->getIdentifierValues($entity);
2920
2921 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...
2922
    }
2923
2924
    /**
2925
     * Tries to find an entity with the given identifier in the identity map of
2926
     * this UnitOfWork.
2927
     *
2928
     * @param mixed  $id            The entity identifier to look for.
2929
     * @param string $rootClassName The name of the root class of the mapped entity hierarchy.
2930
     *
2931
     * @return object|bool Returns the entity with the specified identifier if it exists in
2932
     *                     this UnitOfWork, FALSE otherwise.
2933
     */
2934 522
    public function tryGetById($id, $rootClassName)
2935
    {
2936 522
        $idHash = implode(' ', (array) $id);
2937
2938 522
        return isset($this->identityMap[$rootClassName][$idHash])
2939 79
            ? $this->identityMap[$rootClassName][$idHash]
2940 522
            : false;
2941
    }
2942
2943
    /**
2944
     * Schedules an entity for dirty-checking at commit-time.
2945
     *
2946
     * @param object $entity The entity to schedule for dirty-checking.
2947
     *
2948
     * @return void
2949
     *
2950
     * @todo Rename: scheduleForSynchronization
2951
     */
2952 5
    public function scheduleForDirtyCheck($entity)
2953
    {
2954 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...
2955
2956 5
        $this->scheduledForSynchronization[$rootClassName][spl_object_hash($entity)] = $entity;
2957 5
    }
2958
2959
    /**
2960
     * Checks whether the UnitOfWork has any pending insertions.
2961
     *
2962
     * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise.
2963
     */
2964
    public function hasPendingInsertions()
2965
    {
2966
        return ! empty($this->entityInsertions);
2967
    }
2968
2969
    /**
2970
     * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the
2971
     * number of entities in the identity map.
2972
     *
2973
     * @return integer
2974
     */
2975 1
    public function size()
2976
    {
2977 1
        $countArray = array_map('count', $this->identityMap);
2978
2979 1
        return array_sum($countArray);
2980
    }
2981
2982
    /**
2983
     * Gets the EntityPersister for an Entity.
2984
     *
2985
     * @param string $entityName The name of the Entity.
2986
     *
2987
     * @return \Doctrine\ORM\Persisters\Entity\EntityPersister
2988
     */
2989 1069
    public function getEntityPersister($entityName)
2990
    {
2991 1069
        if (isset($this->persisters[$entityName])) {
2992 846
            return $this->persisters[$entityName];
2993
        }
2994
2995 1069
        $class = $this->em->getClassMetadata($entityName);
2996
2997
        switch (true) {
2998 1069
            case ($class->isInheritanceTypeNone()):
2999 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...
3000 1032
                break;
3001
3002 359
            case ($class->isInheritanceTypeSingleTable()):
3003 213
                $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...
3004 213
                break;
3005
3006 338
            case ($class->isInheritanceTypeJoined()):
3007 338
                $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...
3008 338
                break;
3009
3010
            default:
3011
                throw new \RuntimeException('No persister found for entity.');
3012
        }
3013
3014 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...
3015 119
            $persister = $this->em->getConfiguration()
3016 119
                ->getSecondLevelCacheConfiguration()
3017 119
                ->getCacheFactory()
3018 119
                ->buildCachedEntityPersister($this->em, $persister, $class);
3019
        }
3020
3021 1069
        $this->persisters[$entityName] = $persister;
3022
3023 1069
        return $this->persisters[$entityName];
3024
    }
3025
3026
    /**
3027
     * Gets a collection persister for a collection-valued association.
3028
     *
3029
     * @param array $association
3030
     *
3031
     * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister
3032
     */
3033 569
    public function getCollectionPersister(array $association)
3034
    {
3035 569
        $role = isset($association['cache'])
3036 76
            ? $association['sourceEntity'] . '::' . $association['fieldName']
3037 569
            : $association['type'];
3038
3039 569
        if (isset($this->collectionPersisters[$role])) {
3040 448
            return $this->collectionPersisters[$role];
3041
        }
3042
3043 569
        $persister = ClassMetadata::ONE_TO_MANY === $association['type']
3044 403
            ? new OneToManyPersister($this->em)
3045 569
            : new ManyToManyPersister($this->em);
3046
3047 569
        if ($this->hasCache && isset($association['cache'])) {
3048 75
            $persister = $this->em->getConfiguration()
3049 75
                ->getSecondLevelCacheConfiguration()
3050 75
                ->getCacheFactory()
3051 75
                ->buildCachedCollectionPersister($this->em, $persister, $association);
3052
        }
3053
3054 569
        $this->collectionPersisters[$role] = $persister;
3055
3056 569
        return $this->collectionPersisters[$role];
3057
    }
3058
3059
    /**
3060
     * INTERNAL:
3061
     * Registers an entity as managed.
3062
     *
3063
     * @param object $entity The entity.
3064
     * @param array  $id     The identifier values.
3065
     * @param array  $data   The original entity data.
3066
     *
3067
     * @return void
3068
     */
3069 202
    public function registerManaged($entity, array $id, array $data)
3070
    {
3071 202
        $oid = spl_object_hash($entity);
3072
3073 202
        $this->entityIdentifiers[$oid]  = $id;
3074 202
        $this->entityStates[$oid]       = self::STATE_MANAGED;
3075 202
        $this->originalEntityData[$oid] = $data;
3076
3077 202
        $this->addToIdentityMap($entity);
3078
3079 201
        if ($entity instanceof NotifyPropertyChanged && ( ! $entity instanceof Proxy || $entity->__isInitialized())) {
3080 2
            $entity->addPropertyChangedListener($this);
3081
        }
3082 201
    }
3083
3084
    /**
3085
     * INTERNAL:
3086
     * Clears the property changeset of the entity with the given OID.
3087
     *
3088
     * @param string $oid The entity's OID.
3089
     *
3090
     * @return void
3091
     */
3092
    public function clearEntityChangeSet($oid)
3093
    {
3094
        $this->entityChangeSets[$oid] = array();
3095
    }
3096
3097
    /* PropertyChangedListener implementation */
3098
3099
    /**
3100
     * Notifies this UnitOfWork of a property change in an entity.
3101
     *
3102
     * @param object $entity       The entity that owns the property.
3103
     * @param string $propertyName The name of the property that changed.
3104
     * @param mixed  $oldValue     The old value of the property.
3105
     * @param mixed  $newValue     The new value of the property.
3106
     *
3107
     * @return void
3108
     */
3109 3
    public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
3110
    {
3111 3
        $oid   = spl_object_hash($entity);
3112 3
        $class = $this->em->getClassMetadata(get_class($entity));
3113
3114 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...
3115
3116 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...
3117 1
            return; // ignore non-persistent fields
3118
        }
3119
3120
        // Update changeset and mark entity for synchronization
3121 3
        $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
3122
3123 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...
3124 3
            $this->scheduleForDirtyCheck($entity);
3125
        }
3126 3
    }
3127
3128
    /**
3129
     * Gets the currently scheduled entity insertions in this UnitOfWork.
3130
     *
3131
     * @return array
3132
     */
3133 2
    public function getScheduledEntityInsertions()
3134
    {
3135 2
        return $this->entityInsertions;
3136
    }
3137
3138
    /**
3139
     * Gets the currently scheduled entity updates in this UnitOfWork.
3140
     *
3141
     * @return array
3142
     */
3143 2
    public function getScheduledEntityUpdates()
3144
    {
3145 2
        return $this->entityUpdates;
3146
    }
3147
3148
    /**
3149
     * Gets the currently scheduled entity deletions in this UnitOfWork.
3150
     *
3151
     * @return array
3152
     */
3153 1
    public function getScheduledEntityDeletions()
3154
    {
3155 1
        return $this->entityDeletions;
3156
    }
3157
3158
    /**
3159
     * Gets the currently scheduled complete collection deletions
3160
     *
3161
     * @return array
3162
     */
3163 1
    public function getScheduledCollectionDeletions()
3164
    {
3165 1
        return $this->collectionDeletions;
3166
    }
3167
3168
    /**
3169
     * Gets the currently scheduled collection inserts, updates and deletes.
3170
     *
3171
     * @return array
3172
     */
3173
    public function getScheduledCollectionUpdates()
3174
    {
3175
        return $this->collectionUpdates;
3176
    }
3177
3178
    /**
3179
     * Helper method to initialize a lazy loading proxy or persistent collection.
3180
     *
3181
     * @param object $obj
3182
     *
3183
     * @return void
3184
     */
3185 2
    public function initializeObject($obj)
3186
    {
3187 2
        if ($obj instanceof Proxy) {
3188 1
            $obj->__load();
3189
3190 1
            return;
3191
        }
3192
3193 1
        if ($obj instanceof PersistentCollection) {
3194 1
            $obj->initialize();
3195
        }
3196 1
    }
3197
3198
    /**
3199
     * Helper method to show an object as string.
3200
     *
3201
     * @param object $obj
3202
     *
3203
     * @return string
3204
     */
3205 1
    private static function objToStr($obj)
3206
    {
3207 1
        return method_exists($obj, '__toString') ? (string) $obj : get_class($obj).'@'.spl_object_hash($obj);
3208
    }
3209
3210
    /**
3211
     * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit().
3212
     *
3213
     * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information
3214
     * on this object that might be necessary to perform a correct update.
3215
     *
3216
     * @param object $object
3217
     *
3218
     * @return void
3219
     *
3220
     * @throws ORMInvalidArgumentException
3221
     */
3222 6
    public function markReadOnly($object)
3223
    {
3224 6
        if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
3225 1
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3226
        }
3227
3228 5
        $this->readOnlyObjects[spl_object_hash($object)] = true;
3229 5
    }
3230
3231
    /**
3232
     * Is this entity read only?
3233
     *
3234
     * @param object $object
3235
     *
3236
     * @return bool
3237
     *
3238
     * @throws ORMInvalidArgumentException
3239
     */
3240 3
    public function isReadOnly($object)
3241
    {
3242 3
        if ( ! is_object($object)) {
3243
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3244
        }
3245
3246 3
        return isset($this->readOnlyObjects[spl_object_hash($object)]);
3247
    }
3248
3249
    /**
3250
     * Perform whatever processing is encapsulated here after completion of the transaction.
3251
     */
3252 1002
    private function afterTransactionComplete()
3253
    {
3254
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3255 89
            $persister->afterTransactionComplete();
3256 1002
        });
3257 1002
    }
3258
3259
    /**
3260
     * Perform whatever processing is encapsulated here after completion of the rolled-back.
3261
     */
3262
    private function afterTransactionRolledBack()
3263
    {
3264 11
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3265 3
            $persister->afterTransactionRolledBack();
3266 11
        });
3267 11
    }
3268
3269
    /**
3270
     * Performs an action after the transaction.
3271
     *
3272
     * @param callable $callback
3273
     */
3274 1007
    private function performCallbackOnCachedPersister(callable $callback)
3275
    {
3276 1007
        if ( ! $this->hasCache) {
3277 918
            return;
3278
        }
3279
3280 89
        foreach (array_merge($this->persisters, $this->collectionPersisters) as $persister) {
3281 89
            if ($persister instanceof CachedPersister) {
3282 89
                $callback($persister);
3283
            }
3284
        }
3285 89
    }
3286
3287 1011
    private function dispatchOnFlushEvent()
3288
    {
3289 1011
        if ($this->evm->hasListeners(Events::onFlush)) {
3290 4
            $this->evm->dispatchEvent(Events::onFlush, new OnFlushEventArgs($this->em));
3291
        }
3292 1011
    }
3293
3294 1006
    private function dispatchPostFlushEvent()
3295
    {
3296 1006
        if ($this->evm->hasListeners(Events::postFlush)) {
3297 5
            $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
3298
        }
3299 1005
    }
3300
3301
    /**
3302
     * Verifies if two given entities actually are the same based on identifier comparison
3303
     *
3304
     * @param object $entity1
3305
     * @param object $entity2
3306
     *
3307
     * @return bool
3308
     */
3309 14
    private function isIdentifierEquals($entity1, $entity2)
3310
    {
3311 14
        if ($entity1 === $entity2) {
3312
            return true;
3313
        }
3314
3315 14
        $class = $this->em->getClassMetadata(get_class($entity1));
3316
3317 14
        if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
3318 11
            return false;
3319
        }
3320
3321 3
        $oid1 = spl_object_hash($entity1);
3322 3
        $oid2 = spl_object_hash($entity2);
3323
3324 3
        $id1 = isset($this->entityIdentifiers[$oid1])
3325 3
            ? $this->entityIdentifiers[$oid1]
3326 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...
3327 3
        $id2 = isset($this->entityIdentifiers[$oid2])
3328 3
            ? $this->entityIdentifiers[$oid2]
3329 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...
3330
3331 3
        return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
3332
    }
3333
3334
    /**
3335
     * @param object $entity
3336
     * @param object $managedCopy
3337
     *
3338
     * @throws ORMException
3339
     * @throws OptimisticLockException
3340
     * @throws TransactionRequiredException
3341
     */
3342 30
    private function mergeEntityStateIntoManagedCopy($entity, $managedCopy)
3343
    {
3344 30
        $class = $this->em->getClassMetadata(get_class($entity));
3345
3346 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...
3347 30
            $name = $prop->name;
3348
3349 30
            $prop->setAccessible(true);
3350
3351 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...
3352 30
                if ( ! $class->isIdentifier($name)) {
3353 30
                    $prop->setValue($managedCopy, $prop->getValue($entity));
3354
                }
3355
            } else {
3356 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...
3357
3358 28
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3359 24
                    $other = $prop->getValue($entity);
3360 24
                    if ($other === null) {
3361 11
                        $prop->setValue($managedCopy, null);
3362
                    } else {
3363 16
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3364
                            // do not merge fields marked lazy that have not been fetched.
3365 4
                            continue;
3366
                        }
3367
3368 12
                        if ( ! $assoc2['isCascadeMerge']) {
3369 6
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3370 3
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3371 3
                                $relatedId   = $targetClass->getIdentifierValues($other);
3372
3373 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...
3374 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...
3375
                                } else {
3376 1
                                    $other = $this->em->getProxyFactory()->getProxy(
3377 1
                                        $assoc2['targetEntity'],
3378
                                        $relatedId
3379
                                    );
3380 1
                                    $this->registerManaged($other, $relatedId, array());
3381
                                }
3382
                            }
3383
3384 20
                            $prop->setValue($managedCopy, $other);
3385
                        }
3386
                    }
3387
                } else {
3388 16
                    $mergeCol = $prop->getValue($entity);
3389
3390 16
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3391
                        // do not merge fields marked lazy that have not been fetched.
3392
                        // keep the lazy persistent collection of the managed copy.
3393 5
                        continue;
3394
                    }
3395
3396 13
                    $managedCol = $prop->getValue($managedCopy);
3397
3398 13
                    if ( ! $managedCol) {
3399 3
                        $managedCol = new PersistentCollection(
3400 3
                            $this->em,
3401 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...
3402 3
                            new ArrayCollection
3403
                        );
3404 3
                        $managedCol->setOwner($managedCopy, $assoc2);
3405 3
                        $prop->setValue($managedCopy, $managedCol);
3406
3407 3
                        $this->originalEntityData[spl_object_hash($entity)][$name] = $managedCol;
3408
                    }
3409
3410 13
                    if ($assoc2['isCascadeMerge']) {
3411 8
                        $managedCol->initialize();
3412
3413
                        // clear and set dirty a managed collection if its not also the same collection to merge from.
3414 8
                        if ( ! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
3415 1
                            $managedCol->unwrap()->clear();
3416 1
                            $managedCol->setDirty(true);
3417
3418 1
                            if ($assoc2['isOwningSide']
3419 1
                                && $assoc2['type'] == ClassMetadata::MANY_TO_MANY
3420 1
                                && $class->isChangeTrackingNotify()
3421
                            ) {
3422
                                $this->scheduleForDirtyCheck($managedCopy);
3423
                            }
3424
                        }
3425
                    }
3426
                }
3427
            }
3428
3429 30
            if ($class->isChangeTrackingNotify()) {
3430
                // Just treat all properties as changed, there is no other choice.
3431 30
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
3432
            }
3433
        }
3434 30
    }
3435
3436
    /**
3437
     * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
3438
     * Unit of work able to fire deferred events, related to loading events here.
3439
     *
3440
     * @internal should be called internally from object hydrators
3441
     */
3442 876
    public function hydrationComplete()
3443
    {
3444 876
        $this->hydrationCompleteHandler->hydrationComplete();
3445 876
    }
3446
3447
    /**
3448
     * @param string $entityName
3449
     */
3450 3
    private function clearIdentityMapForEntityName($entityName)
3451
    {
3452 3
        if (! isset($this->identityMap[$entityName])) {
3453
            return;
3454
        }
3455
3456 3
        $visited = [];
3457
3458 3
        foreach ($this->identityMap[$entityName] as $entity) {
3459 3
            $this->doDetach($entity, $visited, false);
3460
        }
3461 3
    }
3462
3463
    /**
3464
     * @param string $entityName
3465
     */
3466 3
    private function clearEntityInsertionsForEntityName($entityName)
3467
    {
3468 3
        foreach ($this->entityInsertions as $hash => $entity) {
3469
            // note: performance optimization - `instanceof` is much faster than a function call
3470 1
            if ($entity instanceof $entityName && get_class($entity) === $entityName) {
3471 1
                unset($this->entityInsertions[$hash]);
3472
            }
3473
        }
3474 3
    }
3475
}
3476