Completed
Pull Request — master (#6020)
by Renan
08:56
created

UnitOfWork::cascadeMerge()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 30
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 30
c 0
b 0
f 0
ccs 16
cts 16
cp 1
rs 6.7272
cc 7
eloc 16
nc 6
nop 3
crap 7
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 2349
    public function __construct(EntityManagerInterface $em)
293
    {
294 2349
        $this->em                         = $em;
295 2349
        $this->evm                        = $em->getEventManager();
296 2349
        $this->listenersInvoker           = new ListenersInvoker($em);
297 2349
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
298 2349
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
299 2349
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
300 2349
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
301 2349
    }
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 1020
    public function commit($entity = null)
323
    {
324
        // Raise preFlush
325 1020
        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 1020
        if ($entity === null) {
331 1012
            $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 1017
        if ( ! ($this->entityInsertions ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityInsertions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
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 1017
                $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 1013
        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 1013
        $this->dispatchOnFlushEvent();
359
360
        // Now we need a commit order to maintain referential integrity
361 1013
        $commitOrder = $this->getCommitOrder();
362
363 1013
        $conn = $this->em->getConnection();
364 1013
        $conn->beginTransaction();
365
366
        try {
367
            // Collection deletions (deletions of complete collections)
368 1013
            foreach ($this->collectionDeletions as $collectionToDelete) {
369 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
370
            }
371
372 1013
            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 1009
                foreach ($commitOrder as $class) {
374 1009
                    $this->executeInserts($class);
375
                }
376
            }
377
378 1012
            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 1008
            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 1008
            foreach ($this->collectionUpdates as $collectionToUpdate) {
391 531
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
392
            }
393
394
            // Entity deletions come last and need to be in reverse commit order
395 1008
            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 1008
            $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 1008
        $this->afterTransactionComplete();
412
413
        // Take new snapshots from visited collections
414 1008
        foreach ($this->visitedCollections as $coll) {
415 530
            $coll->takeSnapshot();
416
        }
417
418 1008
        $this->dispatchPostFlushEvent();
419
420
        // Clear up
421 1007
        $this->entityInsertions =
422 1007
        $this->entityUpdates =
423 1007
        $this->entityDeletions =
424 1007
        $this->extraUpdates =
425 1007
        $this->entityChangeSets =
426 1007
        $this->collectionUpdates =
427 1007
        $this->collectionDeletions =
428 1007
        $this->visitedCollections =
429 1007
        $this->scheduledForSynchronization =
430 1007
        $this->orphanRemovals = array();
431 1007
    }
432
433
    /**
434
     * Computes the changesets of all entities scheduled for insertion.
435
     *
436
     * @return void
437
     */
438 1019
    private function computeScheduleInsertsChangeSets()
439
    {
440 1019
        foreach ($this->entityInsertions as $entity) {
441 1011
            $class = $this->em->getClassMetadata(get_class($entity));
442
443 1011
            $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 1017
    }
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 1011
    public function & getEntityChangeSet($entity)
518
    {
519 1011
        $oid  = spl_object_hash($entity);
520 1011
        $data = array();
521
522 1011
        if (!isset($this->entityChangeSets[$oid])) {
523 1
            return $data;
524
        }
525
526 1011
        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 1021
    public function computeChangeSet(ClassMetadata $class, $entity)
564
    {
565 1021
        $oid = spl_object_hash($entity);
566
567 1021
        if (isset($this->readOnlyObjects[$oid])) {
568 2
            return;
569
        }
570
571 1021
        if ( ! $class->isInheritanceTypeNone()) {
572 308
            $class = $this->em->getClassMetadata(get_class($entity));
573
        }
574
575 1021
        $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 1021
        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 1021
        $actualData = array();
582
583 1021
        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 1021
            $value = $refProp->getValue($entity);
585
586 1021
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
587 779
                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 774
                if ( ! $value instanceof Collection) {
597 242
                    $value = new ArrayCollection($value);
598
                }
599
600 774
                $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 774
                $value = new PersistentCollection(
604 774
                    $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 774
                $value->setOwner($entity, $assoc);
607 774
                $value->setDirty( ! $value->isEmpty());
608
609 774
                $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 774
                $actualData[$name] = $value;
612
613 774
                continue;
614
            }
615
616 1021
            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 1021
                $actualData[$name] = $value;
618
            }
619
        }
620
621 1021
        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 1017
            $this->originalEntityData[$oid] = $actualData;
625 1017
            $changeSet = array();
626
627 1017
            foreach ($actualData as $propName => $actualValue) {
628 1002
                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 951
                    $changeSet[$propName] = array(null, $actualValue);
630
631 951
                    continue;
632
                }
633
634 896
                $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 896
                if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
637 896
                    $changeSet[$propName] = array(null, $actualValue);
638
                }
639
            }
640
641 1017
            $this->entityChangeSets[$oid] = $changeSet;
642
        } else {
643
            // Entity is "fully" MANAGED: it was already fully persisted before
644
            // and we have a copy of the original data
645 264
            $originalData           = $this->originalEntityData[$oid];
646 264
            $isChangeTrackingNotify = $class->isChangeTrackingNotify();
647 264
            $changeSet              = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid]))
648
                ? $this->entityChangeSets[$oid]
649 264
                : array();
650
651 264
            foreach ($actualData as $propName => $actualValue) {
652
                // skip field, its a partially omitted one!
653 249
                if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) {
654 8
                    continue;
655
                }
656
657 249
                $orgValue = $originalData[$propName];
658
659
                // skip if value haven't changed
660 249
                if ($orgValue === $actualValue) {
661 233
                    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 264
            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 1021
        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 896
            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 640
                continue;
730
            }
731
732 867
            $this->computeAssociationChanges($assoc, $val);
733
734 859
            if ( ! isset($this->entityChangeSets[$oid]) &&
735 859
                $assoc['isOwningSide'] &&
736 859
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
737 859
                $val instanceof PersistentCollection &&
738 859
                $val->isDirty()) {
739
740 35
                $this->entityChangeSets[$oid]   = array();
741 35
                $this->originalEntityData[$oid] = $actualData;
742 859
                $this->entityUpdates[$oid]      = $entity;
743
            }
744
        }
745 1013
    }
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 1012
    public function computeChangeSets()
755
    {
756
        // Compute changes for INSERTed entities first. This must always happen.
757 1012
        $this->computeScheduleInsertsChangeSets();
758
759
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
760 1010
        foreach ($this->identityMap as $className => $entities) {
761 449
            $class = $this->em->getClassMetadata($className);
762
763
            // Skip class if instances are read-only
764 449
            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 448
                case ($class->isChangeTrackingDeferredImplicit()):
772 446
                    $entitiesToProcess = $entities;
773 446
                    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 448
            foreach ($entitiesToProcess as $entity) {
785
                // Ignore uninitialized proxy objects
786 428
                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 427
                $oid = spl_object_hash($entity);
792
793 427
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
794 448
                    $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 1010
    }
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 867
    private function computeAssociationChanges($assoc, $value)
812
    {
813 867
        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 866
        if ($value instanceof PersistentCollection && $value->isDirty()) {
818 533
            $coid = spl_object_hash($value);
819
820 533
            $this->collectionUpdates[$coid] = $value;
821 533
            $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 866
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
828 866
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
829
830 866
        foreach ($unwrappedValue as $key => $entry) {
831 722
            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 716
            $state = $this->getEntityState($entry, self::STATE_NEW);
836
837 716
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
838
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
839
            }
840
841
            switch ($state) {
842 716
                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 710
                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 710
                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 713
                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 858
    }
871
872
    /**
873
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
874
     * @param object                              $entity
875
     *
876
     * @return void
877
     */
878 1037
    private function persistNew($class, $entity)
879
    {
880 1037
        $oid    = spl_object_hash($entity);
881 1037
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
882
883 1037
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
884 139
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
885
        }
886
887 1037
        $idGen = $class->idGenerator;
888
889 1037
        if ( ! $idGen->isPostInsertGenerator()) {
890 269
            $idValue = $idGen->generate($this->em, $entity);
0 ignored issues
show
Compatibility introduced by
$this->em of type object<Doctrine\ORM\EntityManagerInterface> is not a sub-type of object<Doctrine\ORM\EntityManager>. It seems like you assume a concrete implementation of the interface Doctrine\ORM\EntityManagerInterface to be always present.

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
950 16
                && ! $class->isCollectionValuedAssociation($name)) {
951 16
                $actualData[$name] = $refProp->getValue($entity);
952
            }
953
        }
954
955 16
        if ( ! isset($this->originalEntityData[$oid])) {
956
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
957
        }
958
959 16
        $originalData = $this->originalEntityData[$oid];
960 16
        $changeSet = array();
961
962 16
        foreach ($actualData as $propName => $actualValue) {
963 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
964
965 16
            if ($orgValue !== $actualValue) {
966 16
                $changeSet[$propName] = array($orgValue, $actualValue);
967
            }
968
        }
969
970 16
        if ($changeSet) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $changeSet of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
971 7
            if (isset($this->entityChangeSets[$oid])) {
972 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
973 1
            } else if ( ! isset($this->entityInsertions[$oid])) {
974 1
                $this->entityChangeSets[$oid] = $changeSet;
975 1
                $this->entityUpdates[$oid]    = $entity;
976
            }
977 7
            $this->originalEntityData[$oid] = $actualData;
978
        }
979 16
    }
980
981
    /**
982
     * Executes all entity insertions for entities of the specified type.
983
     *
984
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
985
     *
986
     * @return void
987
     */
988 1009
    private function executeInserts($class)
989
    {
990 1009
        $entities   = array();
991 1009
        $className  = $class->name;
992 1009
        $persister  = $this->getEntityPersister($className);
993 1009
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
994
995 1009
        foreach ($this->entityInsertions as $oid => $entity) {
996
997 1009
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
998 858
                continue;
999
            }
1000
1001 1009
            $persister->addInsert($entity);
1002
1003 1009
            unset($this->entityInsertions[$oid]);
1004
1005 1009
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1006 1009
                $entities[] = $entity;
1007
            }
1008
        }
1009
1010 1009
        $postInsertIds = $persister->executeInserts();
1011
1012 1009
        if ($postInsertIds) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $postInsertIds of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
1013
            // Persister returned post-insert IDs
1014 922
            foreach ($postInsertIds as $postInsertId) {
1015 922
                $idField = $class->identifier[0];
1016 922
                $idType  = $class->getTypeOfField($idField);
1017
1018 922
                $idValue = $postInsertId['generatedId'];
1019 922
                $idValue = $this->em->getConnection()->convertToPHPValue($idValue, $idType);
0 ignored issues
show
Bug introduced by
It seems like $idType defined by $class->getTypeOfField($idField) on line 1016 can also be of type null or object<Doctrine\DBAL\Types\Type>; however, Doctrine\DBAL\Connection::convertToPHPValue() does only seem to accept string, maybe add an additional type check?

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1417
1418 1097
        if (isset($this->identityMap[$className][$idHash])) {
1419 83
            return false;
1420
        }
1421
1422 1097
        $this->identityMap[$className][$idHash] = $entity;
1423
1424 1097
        return true;
1425
    }
1426
1427
    /**
1428
     * Gets the state of an entity with regard to the current unit of work.
1429
     *
1430
     * @param object   $entity
1431
     * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED).
1432
     *                         This parameter can be set to improve performance of entity state detection
1433
     *                         by potentially avoiding a database lookup if the distinction between NEW and DETACHED
1434
     *                         is either known or does not matter for the caller of the method.
1435
     *
1436
     * @return int The entity state.
1437
     */
1438 1051
    public function getEntityState($entity, $assume = null)
1439
    {
1440 1051
        $oid = spl_object_hash($entity);
1441
1442 1051
        if (isset($this->entityStates[$oid])) {
1443 784
            return $this->entityStates[$oid];
1444
        }
1445
1446 1045
        if ($assume !== null) {
1447 1041
            return $assume;
1448
        }
1449
1450
        // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known.
1451
        // Note that you can not remember the NEW or DETACHED state in _entityStates since
1452
        // the UoW does not hold references to such objects and the object hash can be reused.
1453
        // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it.
1454 13
        $class = $this->em->getClassMetadata(get_class($entity));
1455 13
        $id    = $class->getIdentifierValues($entity);
1456
1457 13
        if ( ! $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
1458 5
            return self::STATE_NEW;
1459
        }
1460
1461 10
        if ($class->containsForeignIdentifier) {
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1605
    }
1606
1607
    /**
1608
     * INTERNAL:
1609
     * Checks whether an identifier hash exists in the identity map.
1610
     *
1611
     * @ignore
1612
     *
1613
     * @param string $idHash
1614
     * @param string $rootClassName
1615
     *
1616
     * @return boolean
1617
     */
1618
    public function containsIdHash($idHash, $rootClassName)
1619
    {
1620
        return isset($this->identityMap[$rootClassName][$idHash]);
1621
    }
1622
1623
    /**
1624
     * Persists an entity as part of the current unit of work.
1625
     *
1626
     * @param object $entity The entity to persist.
1627
     *
1628
     * @return void
1629
     */
1630 1034
    public function persist($entity)
1631
    {
1632 1034
        $visited = array();
1633
1634 1034
        $this->doPersist($entity, $visited);
1635 1027
    }
1636
1637
    /**
1638
     * Persists an entity as part of the current unit of work.
1639
     *
1640
     * This method is internally called during persist() cascades as it tracks
1641
     * the already visited entities to prevent infinite recursions.
1642
     *
1643
     * @param object $entity  The entity to persist.
1644
     * @param array  $visited The already visited entities.
1645
     *
1646
     * @return void
1647
     *
1648
     * @throws ORMInvalidArgumentException
1649
     * @throws UnexpectedValueException
1650
     */
1651 1034
    private function doPersist($entity, array &$visited)
1652
    {
1653 1034
        $oid = spl_object_hash($entity);
1654
1655 1034
        if (isset($visited[$oid])) {
1656 109
            return; // Prevent infinite recursion
1657
        }
1658
1659 1034
        $visited[$oid] = $entity; // Mark visited
1660
1661 1034
        $class = $this->em->getClassMetadata(get_class($entity));
1662
1663
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1664
        // If we would detect DETACHED here we would throw an exception anyway with the same
1665
        // consequences (not recoverable/programming error), so just assuming NEW here
1666
        // lets us avoid some database lookups for entities with natural identifiers.
1667 1034
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1668
1669
        switch ($entityState) {
1670 1034
            case self::STATE_MANAGED:
1671
                // Nothing to do, except if policy is "deferred explicit"
1672 234
                if ($class->isChangeTrackingDeferredExplicit()) {
1673 2
                    $this->scheduleForDirtyCheck($entity);
1674
                }
1675 234
                break;
1676
1677 1034
            case self::STATE_NEW:
1678 1033
                $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...
1679 1033
                break;
1680
1681 1
            case self::STATE_REMOVED:
1682
                // Entity becomes managed again
1683 1
                unset($this->entityDeletions[$oid]);
1684 1
                $this->addToIdentityMap($entity);
1685
1686 1
                $this->entityStates[$oid] = self::STATE_MANAGED;
1687 1
                break;
1688
1689
            case self::STATE_DETACHED:
1690
                // Can actually not happen right now since we assume STATE_NEW.
1691
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
1692
1693
            default:
1694
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1695
        }
1696
1697 1034
        $this->cascadePersist($entity, $visited);
1698 1027
    }
1699
1700
    /**
1701
     * Deletes an entity as part of the current unit of work.
1702
     *
1703
     * @param object $entity The entity to remove.
1704
     *
1705
     * @return void
1706
     */
1707 65
    public function remove($entity)
1708
    {
1709 65
        $visited = array();
1710
1711 65
        $this->doRemove($entity, $visited);
1712 65
    }
1713
1714
    /**
1715
     * Deletes an entity as part of the current unit of work.
1716
     *
1717
     * This method is internally called during delete() cascades as it tracks
1718
     * the already visited entities to prevent infinite recursions.
1719
     *
1720
     * @param object $entity  The entity to delete.
1721
     * @param array  $visited The map of the already visited entities.
1722
     *
1723
     * @return void
1724
     *
1725
     * @throws ORMInvalidArgumentException If the instance is a detached entity.
1726
     * @throws UnexpectedValueException
1727
     */
1728 65
    private function doRemove($entity, array &$visited)
1729
    {
1730 65
        $oid = spl_object_hash($entity);
1731
1732 65
        if (isset($visited[$oid])) {
1733 1
            return; // Prevent infinite recursion
1734
        }
1735
1736 65
        $visited[$oid] = $entity; // mark visited
1737
1738
        // Cascade first, because scheduleForDelete() removes the entity from the identity map, which
1739
        // can cause problems when a lazy proxy has to be initialized for the cascade operation.
1740 65
        $this->cascadeRemove($entity, $visited);
1741
1742 65
        $class       = $this->em->getClassMetadata(get_class($entity));
1743 65
        $entityState = $this->getEntityState($entity);
1744
1745
        switch ($entityState) {
1746 65
            case self::STATE_NEW:
1747 65
            case self::STATE_REMOVED:
1748
                // nothing to do
1749 2
                break;
1750
1751 65
            case self::STATE_MANAGED:
1752 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...
1753
1754 65
                if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1755 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...
1756
                }
1757
1758 65
                $this->scheduleForDelete($entity);
1759 65
                break;
1760
1761
            case self::STATE_DETACHED:
1762
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1763
            default:
1764
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1765
        }
1766
1767 65
    }
1768
1769
    /**
1770
     * Merges the state of the given detached entity into this UnitOfWork.
1771
     *
1772
     * @param object $entity
1773
     *
1774
     * @return object The managed copy of the entity.
1775
     *
1776
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1777
     *         attribute and the version check against the managed copy fails.
1778
     *
1779
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1780
     */
1781 41
    public function merge($entity)
1782
    {
1783 41
        $visited = array();
1784
1785 41
        return $this->doMerge($entity, $visited);
1786
    }
1787
1788
    /**
1789
     * Executes a merge operation on an entity.
1790
     *
1791
     * @param object      $entity
1792
     * @param array       $visited
1793
     * @param object|null $prevManagedCopy
1794
     * @param array|null  $assoc
1795
     *
1796
     * @return object The managed copy of the entity.
1797
     *
1798
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1799
     *         attribute and the version check against the managed copy fails.
1800
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1801
     * @throws EntityNotFoundException
1802
     */
1803 41
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, array $assoc = [])
1804
    {
1805 41
        $oid = spl_object_hash($entity);
1806
1807 41
        if (isset($visited[$oid])) {
1808 4
            $managedCopy = $visited[$oid];
1809
1810 4
            if ($prevManagedCopy !== null) {
1811 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
1812
            }
1813
1814 4
            return $managedCopy;
1815
        }
1816
1817 41
        $class = $this->em->getClassMetadata(get_class($entity));
1818
1819
        // First we assume DETACHED, although it can still be NEW but we can avoid
1820
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1821
        // we need to fetch it from the db anyway in order to merge.
1822
        // MANAGED entities are ignored by the merge operation.
1823 41
        $managedCopy = $entity;
1824
1825 41
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1826
            // Try to look the entity up in the identity map.
1827 40
            $id = $class->getIdentifierValues($entity);
1828
1829
            // If there is no ID, it is actually NEW.
1830 40
            if ( ! $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

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

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

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

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

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

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

Loading history...
1834
            } else {
1835 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...
1836 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...
1837 35
                    : $id;
1838
1839 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 1903 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1840
1841 35
                if ($managedCopy) {
1842
                    // We have the entity in-memory already, just make sure its not removed.
1843 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 1839 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...
1844 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 1839 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...
1845
                    }
1846
                } else {
1847
                    // We need to fetch the managed copy in order to merge.
1848 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...
1849
                }
1850
1851 35
                if ($managedCopy === null) {
1852
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1853
                    // since the managed entity was not found.
1854 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...
1855 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1856 1
                            $class->getName(),
1857 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...
1858
                        );
1859
                    }
1860
1861 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...
1862 1
                    $class->setIdentifierValues($managedCopy, $id);
1863
1864 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...
1865
                }
1866
            }
1867
1868 39
            if ($class->isVersioned && $this->isLoaded($managedCopy) && $this->isLoaded($entity)) {
0 ignored issues
show
Bug introduced by
Accessing isVersioned on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1839 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...
1869 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...
1870 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1871 4
                $entityVersion      = $reflField->getValue($entity);
1872
1873
                // Throw exception if versions don't match.
1874 4
                if ($managedCopyVersion != $entityVersion) {
1875 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1876
                }
1877
            }
1878
1879 38
            $visited[$oid] = $managedCopy; // mark visited
1880
1881 38
            if ($this->isLoaded($entity)) {
1882 31
                if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) {
1883 4
                    $managedCopy->__load();
1884
                }
1885
1886 31
                $this->mergeEntityStateIntoManagedCopy($entity, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1839 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...
1887
            }
1888
1889 38
            if ($class->isChangeTrackingDeferredExplicit()) {
1890
                $this->scheduleForDirtyCheck($entity);
1891
            }
1892
        }
1893
1894 39
        if ($prevManagedCopy !== null) {
1895 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 1839 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...
1896
        }
1897
1898
        // Mark the managed copy visited as well
1899 39
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1900
1901 39
        $this->cascadeMerge($entity, $managedCopy, $visited);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1839 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...
1902
1903 39
        return $managedCopy;
1904
    }
1905
1906
    /**
1907
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1908
     *
1909
     * @param object $entity
1910
     *
1911
     * @return bool
1912
     */
1913 39
    private function isLoaded($entity)
1914
    {
1915 39
        return !($entity instanceof Proxy) || $entity->__isInitialized();
1916
    }
1917
1918
    /**
1919
     * Sets/adds associated managed copies into the previous entity's association field
1920
     *
1921
     * @param object $entity
1922
     * @param array  $association
1923
     * @param object $previousManagedCopy
1924
     * @param object $managedCopy
1925
     *
1926
     * @return void
1927
     */
1928 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1929
    {
1930 6
        $assocField = $association['fieldName'];
1931 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1932
1933 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1934 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...
1935
1936 6
            return;
1937
        }
1938
1939 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...
1940 1
        $value[] = $managedCopy;
1941
1942 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1943 1
            $class = $this->em->getClassMetadata(get_class($entity));
1944
1945 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...
1946
        }
1947 1
    }
1948
1949
    /**
1950
     * Detaches an entity from the persistence management. It's persistence will
1951
     * no longer be managed by Doctrine.
1952
     *
1953
     * @param object $entity The entity to detach.
1954
     *
1955
     * @return void
1956
     */
1957 12
    public function detach($entity)
1958
    {
1959 12
        $visited = array();
1960
1961 12
        $this->doDetach($entity, $visited);
1962 12
    }
1963
1964
    /**
1965
     * Executes a detach operation on the given entity.
1966
     *
1967
     * @param object  $entity
1968
     * @param array   $visited
1969
     * @param boolean $noCascade if true, don't cascade detach operation.
1970
     *
1971
     * @return void
1972
     */
1973 15
    private function doDetach($entity, array &$visited, $noCascade = false)
1974
    {
1975 15
        $oid = spl_object_hash($entity);
1976
1977 15
        if (isset($visited[$oid])) {
1978
            return; // Prevent infinite recursion
1979
        }
1980
1981 15
        $visited[$oid] = $entity; // mark visited
1982
1983 15
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
1984 15
            case self::STATE_MANAGED:
1985 13
                if ($this->isInIdentityMap($entity)) {
1986 12
                    $this->removeFromIdentityMap($entity);
1987
                }
1988
1989
                unset(
1990 13
                    $this->entityInsertions[$oid],
1991 13
                    $this->entityUpdates[$oid],
1992 13
                    $this->entityDeletions[$oid],
1993 13
                    $this->entityIdentifiers[$oid],
1994 13
                    $this->entityStates[$oid],
1995 13
                    $this->originalEntityData[$oid]
1996
                );
1997 13
                break;
1998 3
            case self::STATE_NEW:
1999 3
            case self::STATE_DETACHED:
2000 3
                return;
2001
        }
2002
2003 13
        if ( ! $noCascade) {
2004 13
            $this->cascadeDetach($entity, $visited);
2005
        }
2006 13
    }
2007
2008
    /**
2009
     * Refreshes the state of the given entity from the database, overwriting
2010
     * any local, unpersisted changes.
2011
     *
2012
     * @param object $entity The entity to refresh.
2013
     *
2014
     * @return void
2015
     *
2016
     * @throws InvalidArgumentException If the entity is not MANAGED.
2017
     */
2018 17
    public function refresh($entity)
2019
    {
2020 17
        $visited = array();
2021
2022 17
        $this->doRefresh($entity, $visited);
2023 17
    }
2024
2025
    /**
2026
     * Executes a refresh operation on an entity.
2027
     *
2028
     * @param object $entity  The entity to refresh.
2029
     * @param array  $visited The already visited entities during cascades.
2030
     *
2031
     * @return void
2032
     *
2033
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2034
     */
2035 17
    private function doRefresh($entity, array &$visited)
2036
    {
2037 17
        $oid = spl_object_hash($entity);
2038
2039 17
        if (isset($visited[$oid])) {
2040
            return; // Prevent infinite recursion
2041
        }
2042
2043 17
        $visited[$oid] = $entity; // mark visited
2044
2045 17
        $class = $this->em->getClassMetadata(get_class($entity));
2046
2047 17
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2048
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2049
        }
2050
2051 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...
2052 17
            array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2053
            $entity
2054
        );
2055
2056 17
        $this->cascadeRefresh($entity, $visited);
2057 17
    }
2058
2059
    /**
2060
     * Cascades a refresh operation to associated entities.
2061
     *
2062
     * @param object $entity
2063
     * @param array  $visited
2064
     *
2065
     * @return void
2066
     */
2067 17
    private function cascadeRefresh($entity, array &$visited)
2068
    {
2069 17
        $class = $this->em->getClassMetadata(get_class($entity));
2070
2071 17
        $associationMappings = array_filter(
2072 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...
2073
            function ($assoc) { return $assoc['isCascadeRefresh']; }
2074
        );
2075
2076 17
        foreach ($associationMappings as $assoc) {
2077 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...
2078
2079
            switch (true) {
2080 5
                case ($relatedEntities instanceof PersistentCollection):
2081
                    // Unwrap so that foreach() does not initialize
2082 5
                    $relatedEntities = $relatedEntities->unwrap();
2083
                    // break; is commented intentionally!
2084
2085
                case ($relatedEntities instanceof Collection):
2086
                case (is_array($relatedEntities)):
2087 5
                    foreach ($relatedEntities as $relatedEntity) {
2088
                        $this->doRefresh($relatedEntity, $visited);
2089
                    }
2090 5
                    break;
2091
2092
                case ($relatedEntities !== null):
2093
                    $this->doRefresh($relatedEntities, $visited);
2094
                    break;
2095
2096 5
                default:
2097
                    // Do nothing
2098
            }
2099
        }
2100 17
    }
2101
2102
    /**
2103
     * Cascades a detach operation to associated entities.
2104
     *
2105
     * @param object $entity
2106
     * @param array  $visited
2107
     *
2108
     * @return void
2109
     */
2110 13
    private function cascadeDetach($entity, array &$visited)
2111
    {
2112 13
        $class = $this->em->getClassMetadata(get_class($entity));
2113
2114 13
        $associationMappings = array_filter(
2115 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...
2116
            function ($assoc) { return $assoc['isCascadeDetach']; }
2117
        );
2118
2119 13
        foreach ($associationMappings as $assoc) {
2120 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...
2121
2122
            switch (true) {
2123 3
                case ($relatedEntities instanceof PersistentCollection):
2124
                    // Unwrap so that foreach() does not initialize
2125 2
                    $relatedEntities = $relatedEntities->unwrap();
2126
                    // break; is commented intentionally!
2127
2128
                case ($relatedEntities instanceof Collection):
2129
                case (is_array($relatedEntities)):
2130 3
                    foreach ($relatedEntities as $relatedEntity) {
2131 1
                        $this->doDetach($relatedEntity, $visited);
2132
                    }
2133 3
                    break;
2134
2135
                case ($relatedEntities !== null):
2136
                    $this->doDetach($relatedEntities, $visited);
2137
                    break;
2138
2139 3
                default:
2140
                    // Do nothing
2141
            }
2142
        }
2143 13
    }
2144
2145
    /**
2146
     * Cascades a merge operation to associated entities.
2147
     *
2148
     * @param object $entity
2149
     * @param object $managedCopy
2150
     * @param array  $visited
2151
     *
2152
     * @return void
2153
     */
2154 39
    private function cascadeMerge($entity, $managedCopy, array &$visited)
2155
    {
2156 39
        $class = $this->em->getClassMetadata(get_class($entity));
2157
2158 39
        $associationMappings = array_filter(
2159 39
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2204
2205
            switch (true) {
2206 652
                case ($relatedEntities instanceof PersistentCollection):
2207
                    // Unwrap so that foreach() does not initialize
2208 21
                    $relatedEntities = $relatedEntities->unwrap();
2209
                    // break; is commented intentionally!
2210
2211
                case ($relatedEntities instanceof Collection):
2212 592
                case (is_array($relatedEntities)):
2213 556
                    if (($assoc['type'] & ClassMetadata::TO_MANY) <= 0) {
2214 3
                        throw ORMInvalidArgumentException::invalidAssociation(
2215 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...
2216
                            $assoc,
2217
                            $relatedEntities
2218
                        );
2219
                    }
2220
2221 553
                    foreach ($relatedEntities as $relatedEntity) {
2222 282
                        $this->doPersist($relatedEntity, $visited);
2223
                    }
2224
2225 553
                    break;
2226
2227 582
                case ($relatedEntities !== null):
2228 246
                    if (! $relatedEntities instanceof $assoc['targetEntity']) {
2229 4
                        throw ORMInvalidArgumentException::invalidAssociation(
2230 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...
2231
                            $assoc,
2232
                            $relatedEntities
2233
                        );
2234
                    }
2235
2236 242
                    $this->doPersist($relatedEntities, $visited);
2237 242
                    break;
2238
2239 646
                default:
2240
                    // Do nothing
2241
            }
2242
        }
2243 1027
    }
2244
2245
    /**
2246
     * Cascades the delete operation to associated entities.
2247
     *
2248
     * @param object $entity
2249
     * @param array  $visited
2250
     *
2251
     * @return void
2252
     */
2253 65
    private function cascadeRemove($entity, array &$visited)
2254
    {
2255 65
        $class = $this->em->getClassMetadata(get_class($entity));
2256
2257 65
        $associationMappings = array_filter(
2258 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...
2259
            function ($assoc) { return $assoc['isCascadeRemove']; }
2260
        );
2261
2262 65
        $entitiesToCascade = array();
2263
2264 65
        foreach ($associationMappings as $assoc) {
2265 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...
2266 6
                $entity->__load();
2267
            }
2268
2269 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...
2270
2271
            switch (true) {
2272 26
                case ($relatedEntities instanceof Collection):
2273 19
                case (is_array($relatedEntities)):
2274
                    // If its a PersistentCollection initialization is intended! No unwrap!
2275 20
                    foreach ($relatedEntities as $relatedEntity) {
2276 10
                        $entitiesToCascade[] = $relatedEntity;
2277
                    }
2278 20
                    break;
2279
2280 19
                case ($relatedEntities !== null):
2281 7
                    $entitiesToCascade[] = $relatedEntities;
2282 7
                    break;
2283
2284 26
                default:
2285
                    // Do nothing
2286
            }
2287
        }
2288
2289 65
        foreach ($entitiesToCascade as $relatedEntity) {
2290 16
            $this->doRemove($relatedEntity, $visited);
2291
        }
2292 65
    }
2293
2294
    /**
2295
     * Acquire a lock on the given entity.
2296
     *
2297
     * @param object $entity
2298
     * @param int    $lockMode
2299
     * @param int    $lockVersion
2300
     *
2301
     * @return void
2302
     *
2303
     * @throws ORMInvalidArgumentException
2304
     * @throws TransactionRequiredException
2305
     * @throws OptimisticLockException
2306
     */
2307 11
    public function lock($entity, $lockMode, $lockVersion = null)
2308
    {
2309 11
        if ($entity === null) {
2310 1
            throw new \InvalidArgumentException("No entity passed to UnitOfWork#lock().");
2311
        }
2312
2313 10
        if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
2314 1
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2315
        }
2316
2317 9
        $class = $this->em->getClassMetadata(get_class($entity));
2318
2319
        switch (true) {
2320 9
            case LockMode::OPTIMISTIC === $lockMode:
2321 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...
2322 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...
2323
                }
2324
2325 4
                if ($lockVersion === null) {
2326
                    return;
2327
                }
2328
2329 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...
2330 1
                    $entity->__load();
2331
                }
2332
2333 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...
2334
2335 4
                if ($entityVersion != $lockVersion) {
2336 2
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion);
2337
                }
2338
2339 2
                break;
2340
2341 3
            case LockMode::NONE === $lockMode:
2342 3
            case LockMode::PESSIMISTIC_READ === $lockMode:
2343 1
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
2344 3
                if (!$this->em->getConnection()->isTransactionActive()) {
2345 2
                    throw TransactionRequiredException::transactionRequired();
2346
                }
2347
2348 1
                $oid = spl_object_hash($entity);
2349
2350 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...
2351 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2352
                    $lockMode
2353
                );
2354 1
                break;
2355
2356
            default:
2357
                // Do nothing
2358
        }
2359 3
    }
2360
2361
    /**
2362
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2363
     *
2364
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2365
     */
2366 1013
    public function getCommitOrderCalculator()
2367
    {
2368 1013
        return new Internal\CommitOrderCalculator();
2369
    }
2370
2371
    /**
2372
     * Clears the UnitOfWork.
2373
     *
2374
     * @param string|null $entityName if given, only entities of this type will get detached.
2375
     *
2376
     * @return void
2377
     */
2378 1226
    public function clear($entityName = null)
2379
    {
2380 1226
        if ($entityName === null) {
2381 1225
            $this->identityMap =
2382 1225
            $this->entityIdentifiers =
2383 1225
            $this->originalEntityData =
2384 1225
            $this->entityChangeSets =
2385 1225
            $this->entityStates =
2386 1225
            $this->scheduledForSynchronization =
2387 1225
            $this->entityInsertions =
2388 1225
            $this->entityUpdates =
2389 1225
            $this->entityDeletions =
2390 1225
            $this->collectionDeletions =
2391 1225
            $this->collectionUpdates =
2392 1225
            $this->extraUpdates =
2393 1225
            $this->readOnlyObjects =
2394 1225
            $this->visitedCollections =
2395 1225
            $this->orphanRemovals = array();
2396
        } else {
2397 3
            $this->clearIdentityMapForEntityName($entityName);
2398 3
            $this->clearEntityInsertionsForEntityName($entityName);
2399
        }
2400
2401 1226
        if ($this->evm->hasListeners(Events::onClear)) {
2402 7
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2403
        }
2404 1226
    }
2405
2406
    /**
2407
     * INTERNAL:
2408
     * Schedules an orphaned entity for removal. The remove() operation will be
2409
     * invoked on that entity at the beginning of the next commit of this
2410
     * UnitOfWork.
2411
     *
2412
     * @ignore
2413
     *
2414
     * @param object $entity
2415
     *
2416
     * @return void
2417
     */
2418 17
    public function scheduleOrphanRemoval($entity)
2419
    {
2420 17
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2421 17
    }
2422
2423
    /**
2424
     * INTERNAL:
2425
     * Cancels a previously scheduled orphan removal.
2426
     *
2427
     * @ignore
2428
     *
2429
     * @param object $entity
2430
     *
2431
     * @return void
2432
     */
2433 112
    public function cancelOrphanRemoval($entity)
2434
    {
2435 112
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2436 112
    }
2437
2438
    /**
2439
     * INTERNAL:
2440
     * Schedules a complete collection for removal when this UnitOfWork commits.
2441
     *
2442
     * @param PersistentCollection $coll
2443
     *
2444
     * @return void
2445
     */
2446 13
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2447
    {
2448 13
        $coid = spl_object_hash($coll);
2449
2450
        // TODO: if $coll is already scheduled for recreation ... what to do?
2451
        // Just remove $coll from the scheduled recreations?
2452 13
        unset($this->collectionUpdates[$coid]);
2453
2454 13
        $this->collectionDeletions[$coid] = $coll;
2455 13
    }
2456
2457
    /**
2458
     * @param PersistentCollection $coll
2459
     *
2460
     * @return bool
2461
     */
2462
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2463
    {
2464
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2465
    }
2466
2467
    /**
2468
     * @param ClassMetadata $class
2469
     *
2470
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2471
     */
2472 674
    private function newInstance($class)
2473
    {
2474 674
        $entity = $class->newInstance();
2475
2476 674
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2477 4
            $entity->injectObjectManager($this->em, $class);
2478
        }
2479
2480 674
        return $entity;
2481
    }
2482
2483
    /**
2484
     * INTERNAL:
2485
     * Creates an entity. Used for reconstitution of persistent entities.
2486
     *
2487
     * Internal note: Highly performance-sensitive method.
2488
     *
2489
     * @ignore
2490
     *
2491
     * @param string $className The name of the entity class.
2492
     * @param array  $data      The data for the entity.
2493
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2494
     *
2495
     * @return object The managed entity instance.
2496
     *
2497
     * @todo Rename: getOrCreateEntity
2498
     */
2499 812
    public function createEntity($className, array $data, &$hints = array())
2500
    {
2501 812
        $class = $this->em->getClassMetadata($className);
2502
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2503
2504 812
        $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...
2505 812
        $idHash = implode(' ', $id);
2506
2507 812
        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...
2508 312
            $entity = $this->identityMap[$class->rootEntityName][$idHash];
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2509 312
            $oid = spl_object_hash($entity);
2510
2511
            if (
2512 312
                isset($hints[Query::HINT_REFRESH])
2513 312
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2514 312
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2515 312
                && $unmanagedProxy instanceof Proxy
2516 312
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2517
            ) {
2518
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2519
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2520
                // refreshed object may be anything
2521
2522 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...
2523 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...
2524
                }
2525
2526 2
                return $unmanagedProxy;
2527
            }
2528
2529 310
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2530 22
                $entity->__setInitialized(true);
2531
2532 22
                $overrideLocalValues = true;
2533
2534 22
                if ($entity instanceof NotifyPropertyChanged) {
2535 22
                    $entity->addPropertyChangedListener($this);
2536
                }
2537
            } else {
2538 290
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2539
2540
                // If only a specific entity is set to refresh, check that it's the one
2541 290
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2542 71
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2543
                }
2544
            }
2545
2546 310
            if ($overrideLocalValues) {
2547
                // inject ObjectManager upon refresh.
2548 113
                if ($entity instanceof ObjectManagerAware) {
2549 3
                    $entity->injectObjectManager($this->em, $class);
2550
                }
2551
2552 310
                $this->originalEntityData[$oid] = $data;
2553
            }
2554
        } else {
2555 670
            $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...
2556 670
            $oid    = spl_object_hash($entity);
2557
2558 670
            $this->entityIdentifiers[$oid]  = $id;
2559 670
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2560 670
            $this->originalEntityData[$oid] = $data;
2561
2562 670
            $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...
2563
2564 670
            if ($entity instanceof NotifyPropertyChanged) {
2565 2
                $entity->addPropertyChangedListener($this);
2566
            }
2567
2568 670
            $overrideLocalValues = true;
2569
        }
2570
2571 811
        if ( ! $overrideLocalValues) {
2572 220
            return $entity;
2573
        }
2574
2575 708
        foreach ($data as $field => $value) {
2576 708
            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...
2577 708
                $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...
2578
            }
2579
        }
2580
2581
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2582 708
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2583
2584 708
        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...
2585
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2586
        }
2587
2588
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2589 708
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2590 33
            return $entity;
2591
        }
2592
2593 675
        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...
2594
            // Check if the association is not among the fetch-joined associations already.
2595 588
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2596 261
                continue;
2597
            }
2598
2599 566
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2600
2601
            switch (true) {
2602 566
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2603 486
                    if ( ! $assoc['isOwningSide']) {
2604
2605
                        // use the given entity association
2606 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2607
2608 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2609
2610 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...
2611 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...
2612
2613 2
                            continue 2;
2614
                        }
2615
2616
                        // Inverse side of x-to-one can never be lazy
2617 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...
2618
2619 62
                        continue 2;
2620
                    }
2621
2622
                    // use the entity association
2623 486
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2624 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...
2625 38
                        $this->originalEntityData[$oid][$field] = $data[$field];
2626
2627 38
                        continue;
2628
                    }
2629
2630 479
                    $associatedId = array();
2631
2632
                    // TODO: Is this even computed right in all cases of composite keys?
2633 479
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2634 479
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2635
2636 479
                        if ($joinColumnValue !== null) {
2637 284
                            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...
2638 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2639
                            } else {
2640 284
                                $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...
2641
                            }
2642 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...
2643 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...
2644
                        ) {
2645
                            // the missing key is part of target's entity primary key
2646 7
                            $associatedId = array();
2647 479
                            break;
2648
                        }
2649
                    }
2650
2651 479
                    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...
2652
                        // Foreign key is NULL
2653 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...
2654 287
                        $this->originalEntityData[$oid][$field] = null;
2655
2656 287
                        continue;
2657
                    }
2658
2659 284
                    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...
2660 281
                        $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...
2661
                    }
2662
2663
                    // Foreign key is set
2664
                    // Check identity map first
2665
                    // FIXME: Can break easily with composite keys if join column values are in
2666
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2667 284
                    $relatedIdHash = implode(' ', $associatedId);
2668
2669
                    switch (true) {
2670 284
                        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...
2671 166
                            $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...
2672
2673
                            // If this is an uninitialized proxy, we are deferring eager loads,
2674
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2675
                            // then we can append this entity for eager loading!
2676 166
                            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...
2677 166
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2678 166
                                !$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...
2679 166
                                $newValue instanceof Proxy &&
2680 166
                                $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...
2681
2682
                                $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...
2683
                            }
2684
2685 166
                            break;
2686
2687 191
                        case ($targetClass->subClasses):
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2698 155
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2699 155
                                    break;
2700
2701
                                // Deferred eager load only works for single identifier classes
2702 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...
2703
                                    // TODO: Is there a faster approach?
2704 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...
2705
2706 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2707 7
                                    break;
2708
2709
                                default:
2710
                                    // TODO: This is very imperformant, ignore it?
2711
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2712
                                    break;
2713
                            }
2714
2715
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2716 162
                            $newValueOid = spl_object_hash($newValue);
2717 162
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2718 162
                            $this->identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2719
2720
                            if (
2721 162
                                $newValue instanceof NotifyPropertyChanged &&
2722 162
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2723
                            ) {
2724
                                $newValue->addPropertyChangedListener($this);
2725
                            }
2726 162
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2727
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2728 162
                            break;
2729
                    }
2730
2731 284
                    $this->originalEntityData[$oid][$field] = $newValue;
2732 284
                    $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...
2733
2734 284
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2735 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...
2736 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...
2737
                    }
2738
2739 284
                    break;
2740
2741
                default:
2742
                    // Ignore if its a cached collection
2743 488
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2744
                        break;
2745
                    }
2746
2747
                    // use the given collection
2748 488
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2749
2750 3
                        $data[$field]->setOwner($entity, $assoc);
2751
2752 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...
2753 3
                        $this->originalEntityData[$oid][$field] = $data[$field];
2754
2755 3
                        break;
2756
                    }
2757
2758
                    // Inject collection
2759 488
                    $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...
2760 488
                    $pColl->setOwner($entity, $assoc);
2761 488
                    $pColl->setInitialized(false);
2762
2763 488
                    $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...
2764 488
                    $reflField->setValue($entity, $pColl);
2765
2766 488
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2767 4
                        $this->loadCollection($pColl);
2768 4
                        $pColl->takeSnapshot();
2769
                    }
2770
2771 488
                    $this->originalEntityData[$oid][$field] = $pColl;
2772 566
                    break;
2773
            }
2774
        }
2775
2776 675
        if ($overrideLocalValues) {
2777
            // defer invoking of postLoad event to hydration complete step
2778 675
            $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...
2779
        }
2780
2781 675
        return $entity;
2782
    }
2783
2784
    /**
2785
     * @return void
2786
     */
2787 868
    public function triggerEagerLoads()
2788
    {
2789 868
        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...
2790 868
            return;
2791
        }
2792
2793
        // avoid infinite recursion
2794 7
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2795 7
        $this->eagerLoadingEntities = array();
2796
2797 7
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2798 7
            if ( ! $ids) {
2799
                continue;
2800
            }
2801
2802 7
            $class = $this->em->getClassMetadata($entityName);
2803
2804 7
            $this->getEntityPersister($entityName)->loadAll(
2805 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...
2806
            );
2807
        }
2808 7
    }
2809
2810
    /**
2811
     * Initializes (loads) an uninitialized persistent collection of an entity.
2812
     *
2813
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2814
     *
2815
     * @return void
2816
     *
2817
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2818
     */
2819 143
    public function loadCollection(PersistentCollection $collection)
2820
    {
2821 143
        $assoc     = $collection->getMapping();
2822 143
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2823
2824 143
        switch ($assoc['type']) {
2825 143
            case ClassMetadata::ONE_TO_MANY:
2826 76
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2827 76
                break;
2828
2829 81
            case ClassMetadata::MANY_TO_MANY:
2830 81
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2831 81
                break;
2832
        }
2833
2834 143
        $collection->setInitialized(true);
2835 143
    }
2836
2837
    /**
2838
     * Gets the identity map of the UnitOfWork.
2839
     *
2840
     * @return array
2841
     */
2842 2
    public function getIdentityMap()
2843
    {
2844 2
        return $this->identityMap;
2845
    }
2846
2847
    /**
2848
     * Gets the original data of an entity. The original data is the data that was
2849
     * present at the time the entity was reconstituted from the database.
2850
     *
2851
     * @param object $entity
2852
     *
2853
     * @return array
2854
     */
2855 117
    public function getOriginalEntityData($entity)
2856
    {
2857 117
        $oid = spl_object_hash($entity);
2858
2859 117
        return isset($this->originalEntityData[$oid])
2860 113
            ? $this->originalEntityData[$oid]
2861 117
            : [];
2862
    }
2863
2864
    /**
2865
     * @ignore
2866
     *
2867
     * @param object $entity
2868
     * @param array  $data
2869
     *
2870
     * @return void
2871
     */
2872
    public function setOriginalEntityData($entity, array $data)
2873
    {
2874
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2875
    }
2876
2877
    /**
2878
     * INTERNAL:
2879
     * Sets a property value of the original data array of an entity.
2880
     *
2881
     * @ignore
2882
     *
2883
     * @param string $oid
2884
     * @param string $property
2885
     * @param mixed  $value
2886
     *
2887
     * @return void
2888
     */
2889 314
    public function setOriginalEntityProperty($oid, $property, $value)
2890
    {
2891 314
        $this->originalEntityData[$oid][$property] = $value;
2892 314
    }
2893
2894
    /**
2895
     * Gets the identifier of an entity.
2896
     * The returned value is always an array of identifier values. If the entity
2897
     * has a composite identifier then the identifier values are in the same
2898
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2899
     *
2900
     * @param object $entity
2901
     *
2902
     * @return array The identifier values.
2903
     */
2904 845
    public function getEntityIdentifier($entity)
2905
    {
2906 845
        return $this->entityIdentifiers[spl_object_hash($entity)];
2907
    }
2908
2909
    /**
2910
     * Processes an entity instance to extract their identifier values.
2911
     *
2912
     * @param object $entity The entity instance.
2913
     *
2914
     * @return mixed A scalar value.
2915
     *
2916
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2917
     */
2918 127
    public function getSingleIdentifierValue($entity)
2919
    {
2920 127
        $class = $this->em->getClassMetadata(get_class($entity));
2921
2922 127
        if ($class->isIdentifierComposite) {
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2931
    }
2932
2933
    /**
2934
     * Tries to find an entity with the given identifier in the identity map of
2935
     * this UnitOfWork.
2936
     *
2937
     * @param mixed  $id            The entity identifier to look for.
2938
     * @param string $rootClassName The name of the root class of the mapped entity hierarchy.
2939
     *
2940
     * @return object|bool Returns the entity with the specified identifier if it exists in
2941
     *                     this UnitOfWork, FALSE otherwise.
2942
     */
2943 523
    public function tryGetById($id, $rootClassName)
2944
    {
2945 523
        $idHash = implode(' ', (array) $id);
2946
2947 523
        return isset($this->identityMap[$rootClassName][$idHash])
2948 79
            ? $this->identityMap[$rootClassName][$idHash]
2949 523
            : false;
2950
    }
2951
2952
    /**
2953
     * Schedules an entity for dirty-checking at commit-time.
2954
     *
2955
     * @param object $entity The entity to schedule for dirty-checking.
2956
     *
2957
     * @return void
2958
     *
2959
     * @todo Rename: scheduleForSynchronization
2960
     */
2961 5
    public function scheduleForDirtyCheck($entity)
2962
    {
2963 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...
2964
2965 5
        $this->scheduledForSynchronization[$rootClassName][spl_object_hash($entity)] = $entity;
2966 5
    }
2967
2968
    /**
2969
     * Checks whether the UnitOfWork has any pending insertions.
2970
     *
2971
     * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise.
2972
     */
2973
    public function hasPendingInsertions()
2974
    {
2975
        return ! empty($this->entityInsertions);
2976
    }
2977
2978
    /**
2979
     * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the
2980
     * number of entities in the identity map.
2981
     *
2982
     * @return integer
2983
     */
2984 1
    public function size()
2985
    {
2986 1
        $countArray = array_map('count', $this->identityMap);
2987
2988 1
        return array_sum($countArray);
2989
    }
2990
2991
    /**
2992
     * Gets the EntityPersister for an Entity.
2993
     *
2994
     * @param string $entityName The name of the Entity.
2995
     *
2996
     * @return \Doctrine\ORM\Persisters\Entity\EntityPersister
2997
     */
2998 1075
    public function getEntityPersister($entityName)
2999
    {
3000 1075
        if (isset($this->persisters[$entityName])) {
3001 849
            return $this->persisters[$entityName];
3002
        }
3003
3004 1075
        $class = $this->em->getClassMetadata($entityName);
3005
3006
        switch (true) {
3007 1075
            case ($class->isInheritanceTypeNone()):
3008 1037
                $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...
3009 1037
                break;
3010
3011 360
            case ($class->isInheritanceTypeSingleTable()):
3012 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...
3013 213
                break;
3014
3015 339
            case ($class->isInheritanceTypeJoined()):
3016 339
                $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...
3017 339
                break;
3018
3019
            default:
3020
                throw new \RuntimeException('No persister found for entity.');
3021
        }
3022
3023 1075
        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...
3024 120
            $persister = $this->em->getConfiguration()
3025 120
                ->getSecondLevelCacheConfiguration()
3026 120
                ->getCacheFactory()
3027 120
                ->buildCachedEntityPersister($this->em, $persister, $class);
3028
        }
3029
3030 1075
        $this->persisters[$entityName] = $persister;
3031
3032 1075
        return $this->persisters[$entityName];
3033
    }
3034
3035
    /**
3036
     * Gets a collection persister for a collection-valued association.
3037
     *
3038
     * @param array $association
3039
     *
3040
     * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister
3041
     */
3042 570
    public function getCollectionPersister(array $association)
3043
    {
3044 570
        $role = isset($association['cache'])
3045 76
            ? $association['sourceEntity'] . '::' . $association['fieldName']
3046 570
            : $association['type'];
3047
3048 570
        if (isset($this->collectionPersisters[$role])) {
3049 449
            return $this->collectionPersisters[$role];
3050
        }
3051
3052 570
        $persister = ClassMetadata::ONE_TO_MANY === $association['type']
3053 404
            ? new OneToManyPersister($this->em)
3054 570
            : new ManyToManyPersister($this->em);
3055
3056 570
        if ($this->hasCache && isset($association['cache'])) {
3057 75
            $persister = $this->em->getConfiguration()
3058 75
                ->getSecondLevelCacheConfiguration()
3059 75
                ->getCacheFactory()
3060 75
                ->buildCachedCollectionPersister($this->em, $persister, $association);
3061
        }
3062
3063 570
        $this->collectionPersisters[$role] = $persister;
3064
3065 570
        return $this->collectionPersisters[$role];
3066
    }
3067
3068
    /**
3069
     * INTERNAL:
3070
     * Registers an entity as managed.
3071
     *
3072
     * @param object $entity The entity.
3073
     * @param array  $id     The identifier values.
3074
     * @param array  $data   The original entity data.
3075
     *
3076
     * @return void
3077
     */
3078 206
    public function registerManaged($entity, array $id, array $data)
3079
    {
3080 206
        $oid = spl_object_hash($entity);
3081
3082 206
        $this->entityIdentifiers[$oid]  = $id;
3083 206
        $this->entityStates[$oid]       = self::STATE_MANAGED;
3084 206
        $this->originalEntityData[$oid] = $data;
3085
3086 206
        $this->addToIdentityMap($entity);
3087
3088 200
        if ($entity instanceof NotifyPropertyChanged && ( ! $entity instanceof Proxy || $entity->__isInitialized())) {
3089 2
            $entity->addPropertyChangedListener($this);
3090
        }
3091 200
    }
3092
3093
    /**
3094
     * INTERNAL:
3095
     * Clears the property changeset of the entity with the given OID.
3096
     *
3097
     * @param string $oid The entity's OID.
3098
     *
3099
     * @return void
3100
     */
3101
    public function clearEntityChangeSet($oid)
3102
    {
3103
        $this->entityChangeSets[$oid] = array();
3104
    }
3105
3106
    /* PropertyChangedListener implementation */
3107
3108
    /**
3109
     * Notifies this UnitOfWork of a property change in an entity.
3110
     *
3111
     * @param object $entity       The entity that owns the property.
3112
     * @param string $propertyName The name of the property that changed.
3113
     * @param mixed  $oldValue     The old value of the property.
3114
     * @param mixed  $newValue     The new value of the property.
3115
     *
3116
     * @return void
3117
     */
3118 3
    public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
3119
    {
3120 3
        $oid   = spl_object_hash($entity);
3121 3
        $class = $this->em->getClassMetadata(get_class($entity));
3122
3123 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...
3124
3125 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...
3126 1
            return; // ignore non-persistent fields
3127
        }
3128
3129
        // Update changeset and mark entity for synchronization
3130 3
        $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
3131
3132 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...
3133 3
            $this->scheduleForDirtyCheck($entity);
3134
        }
3135 3
    }
3136
3137
    /**
3138
     * Gets the currently scheduled entity insertions in this UnitOfWork.
3139
     *
3140
     * @return array
3141
     */
3142 2
    public function getScheduledEntityInsertions()
3143
    {
3144 2
        return $this->entityInsertions;
3145
    }
3146
3147
    /**
3148
     * Gets the currently scheduled entity updates in this UnitOfWork.
3149
     *
3150
     * @return array
3151
     */
3152 2
    public function getScheduledEntityUpdates()
3153
    {
3154 2
        return $this->entityUpdates;
3155
    }
3156
3157
    /**
3158
     * Gets the currently scheduled entity deletions in this UnitOfWork.
3159
     *
3160
     * @return array
3161
     */
3162 1
    public function getScheduledEntityDeletions()
3163
    {
3164 1
        return $this->entityDeletions;
3165
    }
3166
3167
    /**
3168
     * Gets the currently scheduled complete collection deletions
3169
     *
3170
     * @return array
3171
     */
3172 1
    public function getScheduledCollectionDeletions()
3173
    {
3174 1
        return $this->collectionDeletions;
3175
    }
3176
3177
    /**
3178
     * Gets the currently scheduled collection inserts, updates and deletes.
3179
     *
3180
     * @return array
3181
     */
3182
    public function getScheduledCollectionUpdates()
3183
    {
3184
        return $this->collectionUpdates;
3185
    }
3186
3187
    /**
3188
     * Helper method to initialize a lazy loading proxy or persistent collection.
3189
     *
3190
     * @param object $obj
3191
     *
3192
     * @return void
3193
     */
3194 2
    public function initializeObject($obj)
3195
    {
3196 2
        if ($obj instanceof Proxy) {
3197 1
            $obj->__load();
3198
3199 1
            return;
3200
        }
3201
3202 1
        if ($obj instanceof PersistentCollection) {
3203 1
            $obj->initialize();
3204
        }
3205 1
    }
3206
3207
    /**
3208
     * Helper method to show an object as string.
3209
     *
3210
     * @param object $obj
3211
     *
3212
     * @return string
3213
     */
3214 1
    private static function objToStr($obj)
3215
    {
3216 1
        return method_exists($obj, '__toString') ? (string) $obj : get_class($obj).'@'.spl_object_hash($obj);
3217
    }
3218
3219
    /**
3220
     * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit().
3221
     *
3222
     * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information
3223
     * on this object that might be necessary to perform a correct update.
3224
     *
3225
     * @param object $object
3226
     *
3227
     * @return void
3228
     *
3229
     * @throws ORMInvalidArgumentException
3230
     */
3231 6
    public function markReadOnly($object)
3232
    {
3233 6
        if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
3234 1
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3235
        }
3236
3237 5
        $this->readOnlyObjects[spl_object_hash($object)] = true;
3238 5
    }
3239
3240
    /**
3241
     * Is this entity read only?
3242
     *
3243
     * @param object $object
3244
     *
3245
     * @return bool
3246
     *
3247
     * @throws ORMInvalidArgumentException
3248
     */
3249 3
    public function isReadOnly($object)
3250
    {
3251 3
        if ( ! is_object($object)) {
3252
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3253
        }
3254
3255 3
        return isset($this->readOnlyObjects[spl_object_hash($object)]);
3256
    }
3257
3258
    /**
3259
     * Perform whatever processing is encapsulated here after completion of the transaction.
3260
     */
3261 1008
    private function afterTransactionComplete()
3262
    {
3263
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3264 90
            $persister->afterTransactionComplete();
3265 1008
        });
3266 1008
    }
3267
3268
    /**
3269
     * Perform whatever processing is encapsulated here after completion of the rolled-back.
3270
     */
3271
    private function afterTransactionRolledBack()
3272
    {
3273 11
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3274 3
            $persister->afterTransactionRolledBack();
3275 11
        });
3276 11
    }
3277
3278
    /**
3279
     * Performs an action after the transaction.
3280
     *
3281
     * @param callable $callback
3282
     */
3283 1013
    private function performCallbackOnCachedPersister(callable $callback)
3284
    {
3285 1013
        if ( ! $this->hasCache) {
3286 923
            return;
3287
        }
3288
3289 90
        foreach (array_merge($this->persisters, $this->collectionPersisters) as $persister) {
3290 90
            if ($persister instanceof CachedPersister) {
3291 90
                $callback($persister);
3292
            }
3293
        }
3294 90
    }
3295
3296 1017
    private function dispatchOnFlushEvent()
3297
    {
3298 1017
        if ($this->evm->hasListeners(Events::onFlush)) {
3299 4
            $this->evm->dispatchEvent(Events::onFlush, new OnFlushEventArgs($this->em));
3300
        }
3301 1017
    }
3302
3303 1012
    private function dispatchPostFlushEvent()
3304
    {
3305 1012
        if ($this->evm->hasListeners(Events::postFlush)) {
3306 5
            $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
3307
        }
3308 1011
    }
3309
3310
    /**
3311
     * Verifies if two given entities actually are the same based on identifier comparison
3312
     *
3313
     * @param object $entity1
3314
     * @param object $entity2
3315
     *
3316
     * @return bool
3317
     */
3318 14
    private function isIdentifierEquals($entity1, $entity2)
3319
    {
3320 14
        if ($entity1 === $entity2) {
3321
            return true;
3322
        }
3323
3324 14
        $class = $this->em->getClassMetadata(get_class($entity1));
3325
3326 14
        if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
3327 11
            return false;
3328
        }
3329
3330 3
        $oid1 = spl_object_hash($entity1);
3331 3
        $oid2 = spl_object_hash($entity2);
3332
3333 3
        $id1 = isset($this->entityIdentifiers[$oid1])
3334 3
            ? $this->entityIdentifiers[$oid1]
3335 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...
3336 3
        $id2 = isset($this->entityIdentifiers[$oid2])
3337 3
            ? $this->entityIdentifiers[$oid2]
3338 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...
3339
3340 3
        return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
3341
    }
3342
3343
    /**
3344
     * @param object $entity
3345
     * @param object $managedCopy
3346
     *
3347
     * @throws ORMException
3348
     * @throws OptimisticLockException
3349
     * @throws TransactionRequiredException
3350
     */
3351 31
    private function mergeEntityStateIntoManagedCopy($entity, $managedCopy)
3352
    {
3353 31
        $class = $this->em->getClassMetadata(get_class($entity));
3354
3355 31
        foreach ($this->reflectionPropertiesGetter->getProperties($class->name) as $prop) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3366
3367 29
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3368 25
                    $other = $prop->getValue($entity);
3369 25
                    if ($other === null) {
3370 12
                        $prop->setValue($managedCopy, null);
3371
                    } else {
3372 16
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3373
                            // do not merge fields marked lazy that have not been fetched.
3374 4
                            continue;
3375
                        }
3376
3377 12
                        if ( ! $assoc2['isCascadeMerge']) {
3378 6
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3379 3
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3380 3
                                $relatedId   = $targetClass->getIdentifierValues($other);
3381
3382 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...
3383 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...
3384
                                } else {
3385 1
                                    $other = $this->em->getProxyFactory()->getProxy(
3386 1
                                        $assoc2['targetEntity'],
3387
                                        $relatedId
3388
                                    );
3389 1
                                    $this->registerManaged($other, $relatedId, array());
3390
                                }
3391
                            }
3392
3393 21
                            $prop->setValue($managedCopy, $other);
3394
                        }
3395
                    }
3396
                } else {
3397 17
                    $mergeCol = $prop->getValue($entity);
3398
3399 17
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3400
                        // do not merge fields marked lazy that have not been fetched.
3401
                        // keep the lazy persistent collection of the managed copy.
3402 5
                        continue;
3403
                    }
3404
3405 14
                    $managedCol = $prop->getValue($managedCopy);
3406
3407 14
                    if ( ! $managedCol) {
3408 4
                        $managedCol = new PersistentCollection(
3409 4
                            $this->em,
3410 4
                            $this->em->getClassMetadata($assoc2['targetEntity']),
0 ignored issues
show
Compatibility introduced by
$this->em->getClassMetad...assoc2['targetEntity']) of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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