Completed
Pull Request — master (#1139)
by Asmir
11:11
created

UnitOfWork::doRefresh()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0582

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 11
cts 13
cp 0.8462
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 13
nc 4
nop 2
crap 4.0582
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 insertions, that can be avoided if we call
165
     * a flush() method with a non related entity.
166
     * @var array
167
     */
168
    private $entityShouldBeInserted = array();
169
170
    /**
171
     * Used to detect if a flush is in progress.
172
     * @see UnitOfWork::scheduleForInsert() method.
173
     * @var boolean
174
     */
175
    private $flushing = false;
176
177
178
    /**
179
     * A list of all pending entity updates.
180
     *
181
     * @var array
182
     */
183
    private $entityUpdates = array();
184
185
    /**
186
     * Any pending extra updates that have been scheduled by persisters.
187
     *
188
     * @var array
189
     */
190
    private $extraUpdates = array();
191
192
    /**
193
     * A list of all pending entity deletions.
194
     *
195
     * @var array
196
     */
197
    private $entityDeletions = array();
198
199
    /**
200
     * All pending collection deletions.
201
     *
202
     * @var array
203
     */
204
    private $collectionDeletions = array();
205
206
    /**
207
     * All pending collection updates.
208
     *
209
     * @var array
210
     */
211
    private $collectionUpdates = array();
212
213
    /**
214
     * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork.
215
     * At the end of the UnitOfWork all these collections will make new snapshots
216
     * of their data.
217
     *
218
     * @var array
219
     */
220
    private $visitedCollections = array();
221
222
    /**
223
     * The EntityManager that "owns" this UnitOfWork instance.
224
     *
225
     * @var EntityManagerInterface
226
     */
227
    private $em;
228
229
    /**
230
     * The entity persister instances used to persist entity instances.
231
     *
232
     * @var array
233
     */
234
    private $persisters = array();
235
236
    /**
237
     * The collection persister instances used to persist collections.
238
     *
239
     * @var array
240
     */
241
    private $collectionPersisters = array();
242
243
    /**
244
     * The EventManager used for dispatching events.
245
     *
246
     * @var \Doctrine\Common\EventManager
247
     */
248
    private $evm;
249
250
    /**
251
     * The ListenersInvoker used for dispatching events.
252
     *
253
     * @var \Doctrine\ORM\Event\ListenersInvoker
254
     */
255
    private $listenersInvoker;
256
257
    /**
258
     * The IdentifierFlattener used for manipulating identifiers
259
     *
260
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
261
     */
262
    private $identifierFlattener;
263
264
    /**
265
     * Orphaned entities that are scheduled for removal.
266
     *
267
     * @var array
268
     */
269
    private $orphanRemovals = array();
270
271
    /**
272
     * Read-Only objects are never evaluated
273
     *
274
     * @var array
275
     */
276
    private $readOnlyObjects = array();
277
278
    /**
279
     * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
280
     *
281
     * @var array
282
     */
283
    private $eagerLoadingEntities = array();
284
285
    /**
286
     * @var boolean
287
     */
288
    protected $hasCache = false;
289
290
    /**
291
     * Helper for handling completion of hydration
292
     *
293
     * @var HydrationCompleteHandler
294
     */
295
    private $hydrationCompleteHandler;
296
297
    /**
298
     * @var ReflectionPropertiesGetter
299
     */
300
    private $reflectionPropertiesGetter;
301
302
    /**
303
     * Initializes a new UnitOfWork instance, bound to the given EntityManager.
304
     *
305
     * @param EntityManagerInterface $em
306
     */
307 2349
    public function __construct(EntityManagerInterface $em)
308
    {
309 2349
        $this->em                         = $em;
310 2349
        $this->evm                        = $em->getEventManager();
311 2349
        $this->listenersInvoker           = new ListenersInvoker($em);
312 2349
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
313 2349
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
314 2349
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
315 2349
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
316 2349
    }
317
318
    /**
319
     * Commits the UnitOfWork, executing all operations that have been postponed
320
     * up to this point. The state of all managed entities will be synchronized with
321
     * the database.
322
     *
323
     * The operations are executed in the following order:
324
     *
325
     * 1) All entity insertions
326
     * 2) All entity updates
327
     * 3) All collection deletions
328
     * 4) All collection updates
329
     * 5) All entity deletions
330
     *
331
     * @param null|object|array $entity
332
     *
333
     * @return void
334
     *
335
     * @throws \Exception
336
     */
337 1021
    public function commit($entity = null)
338
    {
339 1021
        $this->flushing = true;
340
        // Raise preFlush
341 1021
        if ($this->evm->hasListeners(Events::preFlush)) {
342 2
            $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em));
343
        }
344
345
        // Compute changes done since last commit.
346 1021
        if ($entity === null) {
347 1011
            $this->computeChangeSets();
348 18
        } elseif (is_object($entity)) {
349 17
            $this->computeSingleEntityChangeSet($entity);
350 1
        } elseif (is_array($entity)) {
351 1
            foreach ($entity as $object) {
352 1
                $this->computeSingleEntityChangeSet($object);
353
            }
354
        }
355
356 1018
        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...
357 168
                $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...
358 132
                $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...
359 41
                $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...
360 38
                $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...
361 1018
                $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...
362 26
            $this->dispatchOnFlushEvent();
363 26
            $this->dispatchPostFlushEvent();
364 26
            $this->flushing = false;
365 26
            return; // Nothing to do.
366
        }
367
368 1014
        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...
369 16
            foreach ($this->orphanRemovals as $orphan) {
370 16
                $this->remove($orphan);
371
            }
372
        }
373
374 1014
        $this->dispatchOnFlushEvent();
375
376
        // Now we need a commit order to maintain referential integrity
377 1014
        $commitOrder = $this->getCommitOrder();
378
379 1014
        $conn = $this->em->getConnection();
380 1014
        $conn->beginTransaction();
381
382
        try {
383
            // Collection deletions (deletions of complete collections)
384 1014
            foreach ($this->collectionDeletions as $collectionToDelete) {
385 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
386
            }
387
388 1014
            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...
389 1010
                foreach ($commitOrder as $class) {
390 1010
                    $this->executeInserts($class);
391
                }
392
            }
393
394 1013
            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...
395 116
                foreach ($commitOrder as $class) {
396 116
                    $this->executeUpdates($class);
397
                }
398
            }
399
400
            // Extra updates that were requested by persisters.
401 1009
            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...
402 40
                $this->executeExtraUpdates();
403
            }
404
405
            // Collection updates (deleteRows, updateRows, insertRows)
406 1009
            foreach ($this->collectionUpdates as $collectionToUpdate) {
407 531
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
408
            }
409
410
            // Entity deletions come last and need to be in reverse commit order
411 1009
            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...
412 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...
413 63
                    $this->executeDeletions($commitOrder[$i]);
414
                }
415
            }
416
417 1009
            $conn->commit();
418 11
        } catch (Exception $e) {
419 11
            $this->em->close();
420 11
            $conn->rollBack();
421
422 11
            $this->afterTransactionRolledBack();
423 11
            $this->flushing = false;
424
425 11
            throw $e;
426
        }
427
428 1009
        $this->afterTransactionComplete();
429
430
        // Take new snapshots from visited collections
431 1009
        foreach ($this->visitedCollections as $coll) {
432 530
            $coll->takeSnapshot();
433
        }
434
435 1009
        $this->dispatchPostFlushEvent();
436
437
        // Clear up
438 1008
        $this->entityInsertions =
439 1008
        $this->entityUpdates =
440 1008
        $this->entityDeletions =
441 1008
        $this->extraUpdates =
442 1008
        $this->entityChangeSets =
443 1008
        $this->collectionUpdates =
444 1008
        $this->collectionDeletions =
445 1008
        $this->visitedCollections =
446 1008
        $this->scheduledForSynchronization =
447 1008
        $this->orphanRemovals = array();
448 1008
        $this->flushing = false;
449 1008
    }
450
451
    /**
452
     * Computes the changesets of all entities scheduled for insertion.
453
     *
454
     * @return void
455
     */
456 1020
    private function computeScheduleInsertsChangeSets()
457
    {
458 1020
        foreach ($this->entityInsertions as $entity) {
459 1012
            $class = $this->em->getClassMetadata(get_class($entity));
460
461 1012
            $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...
462
        }
463 1018
    }
464
465
    /**
466
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
467
     *
468
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
469
     * 2. Read Only entities are skipped.
470
     * 3. Proxies are skipped.
471
     * 4. Only if entity is properly managed.
472
     *
473
     * @param object $entity
474
     *
475
     * @return void
476
     *
477
     * @throws \InvalidArgumentException
478
     */
479 18
    private function computeSingleEntityChangeSet($entity)
480
    {
481 18
        $state = $this->getEntityState($entity);
482
483 18
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
484 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
485
        }
486
487 17
        $class = $this->em->getClassMetadata(get_class($entity));
488
489 17
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
490 16
            $this->persist($entity);
491
        }
492 17
        $oid = spl_object_hash($entity);
493
494
        // Compute changes for INSERTed entities first. This must always happen even in this case.
495 17
        if (isset($this->entityShouldBeInserted[$oid])) {
496 9
            $this->entityInsertions[$oid] = $entity;
497 9
            unset($this->entityShouldBeInserted[$oid]);
498
        }
499 17
        $this->computeScheduleInsertsChangeSets();
500
501 17
        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...
502
            return;
503
        }
504
505
        // Ignore uninitialized proxy objects
506 17
        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...
507 2
            return;
508
        }
509
510
        // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
511 15
        if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
512 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...
513
        }
514 14
    }
515
516
    /**
517
     * Executes any extra updates that have been scheduled.
518
     */
519 40
    private function executeExtraUpdates()
520
    {
521 40
        foreach ($this->extraUpdates as $oid => $update) {
522 40
            list ($entity, $changeset) = $update;
523
524 40
            $this->entityChangeSets[$oid] = $changeset;
525 40
            $this->getEntityPersister(get_class($entity))->update($entity);
526
        }
527
528 40
        $this->extraUpdates = array();
529 40
    }
530
531
    /**
532
     * Gets the changeset for an entity.
533
     *
534
     * @param object $entity
535
     *
536
     * @return array
537
     */
538 1012
    public function & getEntityChangeSet($entity)
539
    {
540 1012
        $oid  = spl_object_hash($entity);
541 1012
        $data = array();
542
543 1012
        if (!isset($this->entityChangeSets[$oid])) {
544 1
            return $data;
545
        }
546
547 1012
        return $this->entityChangeSets[$oid];
548
    }
549
550
    /**
551
     * Computes the changes that happened to a single entity.
552
     *
553
     * Modifies/populates the following properties:
554
     *
555
     * {@link _originalEntityData}
556
     * If the entity is NEW or MANAGED but not yet fully persisted (only has an id)
557
     * then it was not fetched from the database and therefore we have no original
558
     * entity data yet. All of the current entity data is stored as the original entity data.
559
     *
560
     * {@link _entityChangeSets}
561
     * The changes detected on all properties of the entity are stored there.
562
     * A change is a tuple array where the first entry is the old value and the second
563
     * entry is the new value of the property. Changesets are used by persisters
564
     * to INSERT/UPDATE the persistent entity state.
565
     *
566
     * {@link _entityUpdates}
567
     * If the entity is already fully MANAGED (has been fetched from the database before)
568
     * and any changes to its properties are detected, then a reference to the entity is stored
569
     * there to mark it for an update.
570
     *
571
     * {@link _collectionDeletions}
572
     * If a PersistentCollection has been de-referenced in a fully MANAGED entity,
573
     * then this collection is marked for deletion.
574
     *
575
     * @ignore
576
     *
577
     * @internal Don't call from the outside.
578
     *
579
     * @param ClassMetadata $class  The class descriptor of the entity.
580
     * @param object        $entity The entity for which to compute the changes.
581
     *
582
     * @return void
583
     */
584 1022
    public function computeChangeSet(ClassMetadata $class, $entity)
585
    {
586 1022
        $oid = spl_object_hash($entity);
587
588 1022
        if (isset($this->readOnlyObjects[$oid])) {
589 2
            return;
590
        }
591
592 1022
        if ( ! $class->isInheritanceTypeNone()) {
593 308
            $class = $this->em->getClassMetadata(get_class($entity));
594
        }
595
596 1022
        $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...
597
598 1022
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
599 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...
600
        }
601
602 1022
        $actualData = array();
603
604 1022
        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...
605 1022
            $value = $refProp->getValue($entity);
606
607 1022
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
608 781
                if ($value instanceof PersistentCollection) {
609 199
                    if ($value->getOwner() === $entity) {
610 199
                        continue;
611
                    }
612
613 5
                    $value = new ArrayCollection($value->getValues());
614
                }
615
616
                // If $value is not a Collection then use an ArrayCollection.
617 776
                if ( ! $value instanceof Collection) {
618 242
                    $value = new ArrayCollection($value);
619
                }
620
621 776
                $assoc = $class->associationMappings[$name];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
631
632 776
                $actualData[$name] = $value;
633
634 776
                continue;
635
            }
636
637 1022
            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...
638 1022
                $actualData[$name] = $value;
639
            }
640
        }
641
642 1022
        if ( ! isset($this->originalEntityData[$oid])) {
643
            // Entity is either NEW or MANAGED but not yet fully persisted (only has an id).
644
            // These result in an INSERT.
645 1018
            $this->originalEntityData[$oid] = $actualData;
646 1018
            $changeSet = array();
647
648 1018
            foreach ($actualData as $propName => $actualValue) {
649 1003
                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...
650 952
                    $changeSet[$propName] = array(null, $actualValue);
651
652 952
                    continue;
653
                }
654
655 898
                $assoc = $class->associationMappings[$propName];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
656
657 898
                if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
658 898
                    $changeSet[$propName] = array(null, $actualValue);
659
                }
660
            }
661
662 1018
            $this->entityChangeSets[$oid] = $changeSet;
663
        } else {
664
            // Entity is "fully" MANAGED: it was already fully persisted before
665
            // and we have a copy of the original data
666 264
            $originalData           = $this->originalEntityData[$oid];
667 264
            $isChangeTrackingNotify = $class->isChangeTrackingNotify();
668 264
            $changeSet              = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid]))
669
                ? $this->entityChangeSets[$oid]
670 264
                : array();
671
672 264
            foreach ($actualData as $propName => $actualValue) {
673
                // skip field, its a partially omitted one!
674 249
                if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) {
675 8
                    continue;
676
                }
677
678 249
                $orgValue = $originalData[$propName];
679
680
                // skip if value haven't changed
681 249
                if ($orgValue === $actualValue) {
682 233
                    continue;
683
                }
684
685
                // if regular field
686 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...
687 58
                    if ($isChangeTrackingNotify) {
688
                        continue;
689
                    }
690
691 58
                    $changeSet[$propName] = array($orgValue, $actualValue);
692
693 58
                    continue;
694
                }
695
696 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...
697
698
                // Persistent collection was exchanged with the "originally"
699
                // created one. This can only mean it was cloned and replaced
700
                // on another entity.
701 58
                if ($actualValue instanceof PersistentCollection) {
702 8
                    $owner = $actualValue->getOwner();
703 8
                    if ($owner === null) { // cloned
704
                        $actualValue->setOwner($entity, $assoc);
705 8
                    } else if ($owner !== $entity) { // no clone, we have to fix
706
                        if (!$actualValue->isInitialized()) {
707
                            $actualValue->initialize(); // we have to do this otherwise the cols share state
708
                        }
709
                        $newValue = clone $actualValue;
710
                        $newValue->setOwner($entity, $assoc);
711
                        $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...
712
                    }
713
                }
714
715 58
                if ($orgValue instanceof PersistentCollection) {
716
                    // A PersistentCollection was de-referenced, so delete it.
717 8
                    $coid = spl_object_hash($orgValue);
718
719 8
                    if (isset($this->collectionDeletions[$coid])) {
720
                        continue;
721
                    }
722
723 8
                    $this->collectionDeletions[$coid] = $orgValue;
724 8
                    $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored.
725
726 8
                    continue;
727
                }
728
729 50
                if ($assoc['type'] & ClassMetadata::TO_ONE) {
730 49
                    if ($assoc['isOwningSide']) {
731 21
                        $changeSet[$propName] = array($orgValue, $actualValue);
732
                    }
733
734 49
                    if ($orgValue !== null && $assoc['orphanRemoval']) {
735 50
                        $this->scheduleOrphanRemoval($orgValue);
736
                    }
737
                }
738
            }
739
740 264
            if ($changeSet) {
741 85
                $this->entityChangeSets[$oid]   = $changeSet;
742 85
                $this->originalEntityData[$oid] = $actualData;
743 85
                $this->entityUpdates[$oid]      = $entity;
744
            }
745
        }
746
747
        // Look for changes in associations of the entity
748 1022
        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...
749 898
            if (($val = $class->reflFields[$field]->getValue($entity)) === null) {
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
750 642
                continue;
751
            }
752
753 869
            $this->computeAssociationChanges($assoc, $val);
754
755 861
            if ( ! isset($this->entityChangeSets[$oid]) &&
756 861
                $assoc['isOwningSide'] &&
757 861
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
758 861
                $val instanceof PersistentCollection &&
759 861
                $val->isDirty()) {
760
761 35
                $this->entityChangeSets[$oid]   = array();
762 35
                $this->originalEntityData[$oid] = $actualData;
763 861
                $this->entityUpdates[$oid]      = $entity;
764
            }
765
        }
766 1014
    }
767
768
    /**
769
     * Computes all the changes that have been done to entities and collections
770
     * since the last commit and stores these changes in the _entityChangeSet map
771
     * temporarily for access by the persisters, until the UoW commit is finished.
772
     *
773
     * @return void
774
     */
775 1011
    public function computeChangeSets()
776
    {
777
        // Compute changes for INSERTed entities first. This must always happen.
778 1011
        $this->entityInsertions = $this->entityInsertions + $this->entityShouldBeInserted;
779 1011
        $this->entityShouldBeInserted = array();
780
781 1011
        $this->computeScheduleInsertsChangeSets();
782
783
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
784 1009
        foreach ($this->identityMap as $className => $entities) {
785 449
            $class = $this->em->getClassMetadata($className);
786
787
            // Skip class if instances are read-only
788 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...
789 1
                continue;
790
            }
791
792
            // If change tracking is explicit or happens through notification, then only compute
793
            // changes on entities of that type that are explicitly marked for synchronization.
794
            switch (true) {
795 448
                case ($class->isChangeTrackingDeferredImplicit()):
796 446
                    $entitiesToProcess = $entities;
797 446
                    break;
798
799 3
                case (isset($this->scheduledForSynchronization[$className])):
800 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
801 3
                    break;
802
803
                default:
804 1
                    $entitiesToProcess = array();
805
806
            }
807
808 448
            foreach ($entitiesToProcess as $entity) {
809
                // Ignore uninitialized proxy objects
810 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...
811 34
                    continue;
812
                }
813
814
                // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
815 427
                $oid = spl_object_hash($entity);
816
817 427
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
818 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...
819
                }
820
            }
821
        }
822 1009
    }
823
824
    /**
825
     * Computes the changes of an association.
826
     *
827
     * @param array $assoc The association mapping.
828
     * @param mixed $value The value of the association.
829
     *
830
     * @throws ORMInvalidArgumentException
831
     * @throws ORMException
832
     *
833
     * @return void
834
     */
835 869
    private function computeAssociationChanges($assoc, $value)
836
    {
837 869
        if ($value instanceof Proxy && ! $value->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
838 27
            return;
839
        }
840
841 868
        if ($value instanceof PersistentCollection && $value->isDirty()) {
842 533
            $coid = spl_object_hash($value);
843
844 533
            $this->collectionUpdates[$coid] = $value;
845 533
            $this->visitedCollections[$coid] = $value;
846
        }
847
848
        // Look through the entities, and in any of their associations,
849
        // for transient (new) entities, recursively. ("Persistence by reachability")
850
        // Unwrap. Uninitialized collections will simply be empty.
851 868
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
852 868
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
853
854 868
        foreach ($unwrappedValue as $key => $entry) {
855 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...
856 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...
857
            }
858
859 716
            $state = $this->getEntityState($entry, self::STATE_NEW);
860
861 716
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
862
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
863
            }
864
865
            switch ($state) {
866 716
                case self::STATE_NEW:
867 39
                    if ( ! $assoc['isCascadePersist']) {
868 4
                        throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
869
                    }
870
871 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...
872 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...
873 35
                    break;
874
875 710
                case self::STATE_REMOVED:
876
                    // Consume the $value as array (it's either an array or an ArrayAccess)
877
                    // and remove the element from Collection.
878 4
                    if ($assoc['type'] & ClassMetadata::TO_MANY) {
879 3
                        unset($value[$key]);
880
                    }
881 4
                    break;
882
883 710
                case self::STATE_DETACHED:
884
                    // Can actually not happen right now as we assume STATE_NEW,
885
                    // so the exception will be raised from the DBAL layer (constraint violation).
886
                    throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
887
                    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...
888
889 713
                default:
890
                    // MANAGED associated entities are already taken into account
891
                    // during changeset calculation anyway, since they are in the identity map.
892
            }
893
        }
894 860
    }
895
896
    /**
897
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
898
     * @param object                              $entity
899
     *
900
     * @return void
901
     */
902 1038
    private function persistNew($class, $entity)
903
    {
904 1038
        $oid    = spl_object_hash($entity);
905 1038
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
906
907 1038
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
908 139
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
909
        }
910
911 1038
        $idGen = $class->idGenerator;
912
913 1038
        if ( ! $idGen->isPostInsertGenerator()) {
914 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...
915
916 269
            if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
917 1
                $idValue = array($class->identifier[0] => $idValue);
918
919 1
                $class->setIdentifierValues($entity, $idValue);
920
            }
921
922 269
            $this->entityIdentifiers[$oid] = $idValue;
923
        }
924
925 1038
        $this->entityStates[$oid] = self::STATE_MANAGED;
926
927 1038
        $this->scheduleForInsert($entity);
928 1038
    }
929
930
    /**
931
     * INTERNAL:
932
     * Computes the changeset of an individual entity, independently of the
933
     * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
934
     *
935
     * The passed entity must be a managed entity. If the entity already has a change set
936
     * because this method is invoked during a commit cycle then the change sets are added.
937
     * whereby changes detected in this method prevail.
938
     *
939
     * @ignore
940
     *
941
     * @param ClassMetadata $class  The class descriptor of the entity.
942
     * @param object        $entity The entity for which to (re)calculate the change set.
943
     *
944
     * @return void
945
     *
946
     * @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
947
     */
948 16
    public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
949
    {
950 16
        $oid = spl_object_hash($entity);
951
952 16
        if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
953
            throw ORMInvalidArgumentException::entityNotManaged($entity);
954
        }
955
956
        // skip if change tracking is "NOTIFY"
957 16
        if ($class->isChangeTrackingNotify()) {
958
            return;
959
        }
960
961 16
        if ( ! $class->isInheritanceTypeNone()) {
962 3
            $class = $this->em->getClassMetadata(get_class($entity));
963
        }
964
965 16
        $actualData = array();
966
967 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...
968 16
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
969 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...
970 16
                && ! $class->isCollectionValuedAssociation($name)) {
971 16
                $actualData[$name] = $refProp->getValue($entity);
972
            }
973
        }
974
975 16
        if ( ! isset($this->originalEntityData[$oid])) {
976
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
977
        }
978
979 16
        $originalData = $this->originalEntityData[$oid];
980 16
        $changeSet = array();
981
982 16
        foreach ($actualData as $propName => $actualValue) {
983 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
984
985 16
            if ($orgValue !== $actualValue) {
986 16
                $changeSet[$propName] = array($orgValue, $actualValue);
987
            }
988
        }
989
990 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...
991 7
            if (isset($this->entityChangeSets[$oid])) {
992 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
993 1
            } else if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityShouldBeInserted[$oid])) {
994 1
                $this->entityChangeSets[$oid] = $changeSet;
995 1
                $this->entityUpdates[$oid]    = $entity;
996
            }
997 7
            $this->originalEntityData[$oid] = $actualData;
998
        }
999 16
    }
1000
1001
    /**
1002
     * Executes all entity insertions for entities of the specified type.
1003
     *
1004
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1005
     *
1006
     * @return void
1007
     */
1008 1010
    private function executeInserts($class)
1009
    {
1010 1010
        $entities   = array();
1011 1010
        $className  = $class->name;
1012 1010
        $persister  = $this->getEntityPersister($className);
1013 1010
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
1014
1015 1010
        foreach ($this->entityInsertions as $oid => $entity) {
1016
1017 1010
            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...
1018 860
                continue;
1019
            }
1020
1021 1010
            $persister->addInsert($entity);
1022
1023 1010
            unset($this->entityInsertions[$oid], $this->entityShouldBeInserted[$oid]);
1024
1025 1010
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1026 1010
                $entities[] = $entity;
1027
            }
1028
        }
1029
1030 1010
        $postInsertIds = $persister->executeInserts();
1031
1032 1010
        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...
1033
            // Persister returned post-insert IDs
1034 923
            foreach ($postInsertIds as $postInsertId) {
1035 923
                $id      = $postInsertId['generatedId'];
1036 923
                $entity  = $postInsertId['entity'];
1037 923
                $oid     = spl_object_hash($entity);
1038 923
                $idField = $class->identifier[0];
1039
1040 923
                $class->reflFields[$idField]->setValue($entity, $id);
1041
1042 923
                $this->entityIdentifiers[$oid] = array($idField => $id);
1043 923
                $this->entityStates[$oid] = self::STATE_MANAGED;
1044 923
                $this->originalEntityData[$oid][$idField] = $id;
1045
1046 923
                $this->addToIdentityMap($entity);
1047
            }
1048
        }
1049
1050 1010
        foreach ($entities as $entity) {
1051 135
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1052
        }
1053 1010
    }
1054
1055
    /**
1056
     * Executes all entity updates for entities of the specified type.
1057
     *
1058
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1059
     *
1060
     * @return void
1061
     */
1062 116
    private function executeUpdates($class)
1063
    {
1064 116
        $className          = $class->name;
1065 116
        $persister          = $this->getEntityPersister($className);
1066 116
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1067 116
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1068
1069 116
        foreach ($this->entityUpdates as $oid => $entity) {
1070 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...
1071 74
                continue;
1072
            }
1073
1074 116
            if ($preUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1075 13
                $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->getEntityChangeSet($entity)), $preUpdateInvoke);
1076
1077 13
                $this->recomputeSingleEntityChangeSet($class, $entity);
1078
            }
1079
1080 116
            if ( ! empty($this->entityChangeSets[$oid])) {
1081 82
                $persister->update($entity);
1082
            }
1083
1084 112
            unset($this->entityUpdates[$oid]);
1085
1086 112
            if ($postUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1087 112
                $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new LifecycleEventArgs($entity, $this->em), $postUpdateInvoke);
1088
            }
1089
        }
1090 112
    }
1091
1092
    /**
1093
     * Executes all entity deletions for entities of the specified type.
1094
     *
1095
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1096
     *
1097
     * @return void
1098
     */
1099 63
    private function executeDeletions($class)
1100
    {
1101 63
        $className  = $class->name;
1102 63
        $persister  = $this->getEntityPersister($className);
1103 63
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove);
1104
1105 63
        foreach ($this->entityDeletions as $oid => $entity) {
1106 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...
1107 26
                continue;
1108
            }
1109
1110 63
            $persister->delete($entity);
1111
1112
            unset(
1113 63
                $this->entityDeletions[$oid],
1114 63
                $this->entityIdentifiers[$oid],
1115 63
                $this->originalEntityData[$oid],
1116 63
                $this->entityStates[$oid]
1117
            );
1118
1119
            // Entity with this $oid after deletion treated as NEW, even if the $oid
1120
            // is obtained by a new entity because the old one went out of scope.
1121
            //$this->entityStates[$oid] = self::STATE_NEW;
1122 63
            if ( ! $class->isIdentifierNatural()) {
1123 53
                $class->reflFields[$class->identifier[0]]->setValue($entity, null);
1124
            }
1125
1126 63
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1127 63
                $this->listenersInvoker->invoke($class, Events::postRemove, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1128
            }
1129
        }
1130 62
    }
1131
1132
    /**
1133
     * Gets the commit order.
1134
     *
1135
     * @param array|null $entityChangeSet
1136
     *
1137
     * @return array
1138
     */
1139 1014
    private function getCommitOrder(array $entityChangeSet = null)
1140
    {
1141 1014
        if ($entityChangeSet === null) {
1142 1014
            $entityChangeSet = array_merge($this->entityInsertions, $this->entityUpdates, $this->entityDeletions);
1143
        }
1144
1145 1014
        $calc = $this->getCommitOrderCalculator();
1146
1147
        // See if there are any new classes in the changeset, that are not in the
1148
        // commit order graph yet (don't have a node).
1149
        // We have to inspect changeSet to be able to correctly build dependencies.
1150
        // It is not possible to use IdentityMap here because post inserted ids
1151
        // are not yet available.
1152 1014
        $newNodes = array();
1153
1154 1014
        foreach ($entityChangeSet as $entity) {
1155 1014
            $class = $this->em->getClassMetadata(get_class($entity));
1156
1157 1014
            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...
1158 627
                continue;
1159
            }
1160
1161 1014
            $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...
1162
1163 1014
            $newNodes[] = $class;
1164
        }
1165
1166
        // Calculate dependencies for new nodes
1167 1014
        while ($class = array_pop($newNodes)) {
1168 1014
            foreach ($class->associationMappings as $assoc) {
1169 890
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1170 850
                    continue;
1171
                }
1172
1173 843
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1174
1175 843
                if ( ! $calc->hasNode($targetClass->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1187 836
                    continue;
1188
                }
1189
1190 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...
1191 217
                    $targetSubClass = $this->em->getClassMetadata($subClassName);
1192
1193 217
                    if ( ! $calc->hasNode($subClassName)) {
1194 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...
1195
1196 189
                        $newNodes[] = $targetSubClass;
1197
                    }
1198
1199 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...
1200
                }
1201
            }
1202
        }
1203
1204 1014
        return $calc->sort();
1205
    }
1206
1207
    /**
1208
     * Schedules an entity for insertion into the database.
1209
     * If the entity already has an identifier, it will be added to the identity map.
1210
     *
1211
     * @param object $entity The entity to schedule for insertion.
1212
     *
1213
     * @return void
1214
     *
1215
     * @throws ORMInvalidArgumentException
1216
     * @throws \InvalidArgumentException
1217
     */
1218 1039
    public function scheduleForInsert($entity)
1219
    {
1220 1039
        $oid = spl_object_hash($entity);
1221
1222 1039
        if (isset($this->entityUpdates[$oid])) {
1223
            throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion.");
1224
        }
1225
1226 1039
        if (isset($this->entityDeletions[$oid])) {
1227 1
            throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
1228
        }
1229 1039
        if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid]) && !isset($this->entityShouldBeInserted[$oid])) {
1230 1
            throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
1231
        }
1232
1233 1039
        if (isset($this->entityInsertions[$oid]) || isset($this->entityShouldBeInserted[$oid])) {
1234 1
            throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
1235
        }
1236
1237 1039
        if ($this->flushing) {
1238 37
            $this->entityInsertions[$oid] = $entity;
1239
        } else {
1240 1039
            $this->entityShouldBeInserted[$oid] = $entity;
1241
        }
1242
1243 1039
        if (isset($this->entityIdentifiers[$oid])) {
1244 269
            $this->addToIdentityMap($entity);
1245
        }
1246
1247 1039
        if ($entity instanceof NotifyPropertyChanged) {
1248 5
            $entity->addPropertyChangedListener($this);
1249
        }
1250 1039
    }
1251
1252
    /**
1253
     * Checks whether an entity is scheduled for insertion.
1254
     *
1255
     * @param object $entity
1256
     *
1257
     * @return boolean
1258
     */
1259 632
    public function isScheduledForInsert($entity)
1260
    {
1261 632
        return isset($this->entityInsertions[spl_object_hash($entity)]) || isset($this->entityShouldBeInserted[spl_object_hash($entity)]);
1262
    }
1263
1264
    /**
1265
     * Schedules an entity for being updated.
1266
     *
1267
     * @param object $entity The entity to schedule for being updated.
1268
     *
1269
     * @return void
1270
     *
1271
     * @throws ORMInvalidArgumentException
1272
     */
1273 1
    public function scheduleForUpdate($entity)
1274
    {
1275 1
        $oid = spl_object_hash($entity);
1276
1277 1
        if ( ! isset($this->entityIdentifiers[$oid])) {
1278
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update");
1279
        }
1280
1281 1
        if (isset($this->entityDeletions[$oid])) {
1282
            throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update");
1283
        }
1284
1285 1
        if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid]) && ! isset($this->entityShouldBeInserted[$oid])) {
1286 1
            $this->entityUpdates[$oid] = $entity;
1287
        }
1288 1
    }
1289
1290
    /**
1291
     * INTERNAL:
1292
     * Schedules an extra update that will be executed immediately after the
1293
     * regular entity updates within the currently running commit cycle.
1294
     *
1295
     * Extra updates for entities are stored as (entity, changeset) tuples.
1296
     *
1297
     * @ignore
1298
     *
1299
     * @param object $entity    The entity for which to schedule an extra update.
1300
     * @param array  $changeset The changeset of the entity (what to update).
1301
     *
1302
     * @return void
1303
     */
1304 40
    public function scheduleExtraUpdate($entity, array $changeset)
1305
    {
1306 40
        $oid         = spl_object_hash($entity);
1307 40
        $extraUpdate = array($entity, $changeset);
1308
1309 40
        if (isset($this->extraUpdates[$oid])) {
1310 1
            list(, $changeset2) = $this->extraUpdates[$oid];
1311
1312 1
            $extraUpdate = array($entity, $changeset + $changeset2);
1313
        }
1314
1315 40
        $this->extraUpdates[$oid] = $extraUpdate;
1316 40
    }
1317
1318
    /**
1319
     * Checks whether an entity is registered as dirty in the unit of work.
1320
     * Note: Is not very useful currently as dirty entities are only registered
1321
     * at commit time.
1322
     *
1323
     * @param object $entity
1324
     *
1325
     * @return boolean
1326
     */
1327
    public function isScheduledForUpdate($entity)
1328
    {
1329
        return isset($this->entityUpdates[spl_object_hash($entity)]);
1330
    }
1331
1332
    /**
1333
     * Checks whether an entity is registered to be checked in the unit of work.
1334
     *
1335
     * @param object $entity
1336
     *
1337
     * @return boolean
1338
     */
1339 1
    public function isScheduledForDirtyCheck($entity)
1340
    {
1341 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...
1342
1343 1
        return isset($this->scheduledForSynchronization[$rootEntityName][spl_object_hash($entity)]);
1344
    }
1345
1346
    /**
1347
     * INTERNAL:
1348
     * Schedules an entity for deletion.
1349
     *
1350
     * @param object $entity
1351
     *
1352
     * @return void
1353
     */
1354 66
    public function scheduleForDelete($entity)
1355
    {
1356 66
        $oid = spl_object_hash($entity);
1357
1358 66
        if (isset($this->entityInsertions[$oid]) || isset($this->entityShouldBeInserted[$oid])) {
1359 1
            if ($this->isInIdentityMap($entity)) {
1360
                $this->removeFromIdentityMap($entity);
1361
            }
1362
1363 1
            unset($this->entityInsertions[$oid], $this->entityShouldBeInserted[$oid], $this->entityStates[$oid]);
1364
1365 1
            return; // entity has not been persisted yet, so nothing more to do.
1366
        }
1367
1368 66
        if ( ! $this->isInIdentityMap($entity)) {
1369 1
            return;
1370
        }
1371
1372 65
        $this->removeFromIdentityMap($entity);
1373
1374 65
        unset($this->entityUpdates[$oid]);
1375
1376 65
        if ( ! isset($this->entityDeletions[$oid])) {
1377 65
            $this->entityDeletions[$oid] = $entity;
1378 65
            $this->entityStates[$oid]    = self::STATE_REMOVED;
1379
        }
1380 65
    }
1381
1382
    /**
1383
     * Checks whether an entity is registered as removed/deleted with the unit
1384
     * of work.
1385
     *
1386
     * @param object $entity
1387
     *
1388
     * @return boolean
1389
     */
1390 15
    public function isScheduledForDelete($entity)
1391
    {
1392 15
        return isset($this->entityDeletions[spl_object_hash($entity)]);
1393
    }
1394
1395
    /**
1396
     * Checks whether an entity is scheduled for insertion, update or deletion.
1397
     *
1398
     * @param object $entity
1399
     *
1400
     * @return boolean
1401
     */
1402
    public function isEntityScheduled($entity)
1403
    {
1404
        $oid = spl_object_hash($entity);
1405
1406
        return isset($this->entityInsertions[$oid])
1407
            || isset($this->entityUpdates[$oid])
1408
            || isset($this->entityDeletions[$oid])
1409
            || isset($this->entityShouldBeInserted[$oid]);
1410
    }
1411
1412
    /**
1413
     * INTERNAL:
1414
     * Registers an entity in the identity map.
1415
     * Note that entities in a hierarchy are registered with the class name of
1416
     * the root entity.
1417
     *
1418
     * @ignore
1419
     *
1420
     * @param object $entity The entity to register.
1421
     *
1422
     * @return boolean TRUE if the registration was successful, FALSE if the identity of
1423
     *                 the entity in question is already managed.
1424
     *
1425
     * @throws ORMInvalidArgumentException
1426
     */
1427 1104
    public function addToIdentityMap($entity)
1428
    {
1429 1104
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1430 1104
        $identifier    = $this->entityIdentifiers[spl_object_hash($entity)];
1431
1432 1104
        if (empty($identifier) || in_array(null, $identifier, true)) {
1433 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...
1434
        }
1435
1436 1098
        $idHash    = implode(' ', $identifier);
1437 1098
        $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...
1438
1439 1098
        if (isset($this->identityMap[$className][$idHash])) {
1440 83
            return false;
1441
        }
1442
1443 1098
        $this->identityMap[$className][$idHash] = $entity;
1444
1445 1098
        return true;
1446
    }
1447
1448
    /**
1449
     * Gets the state of an entity with regard to the current unit of work.
1450
     *
1451
     * @param object   $entity
1452
     * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED).
1453
     *                         This parameter can be set to improve performance of entity state detection
1454
     *                         by potentially avoiding a database lookup if the distinction between NEW and DETACHED
1455
     *                         is either known or does not matter for the caller of the method.
1456
     *
1457
     * @return int The entity state.
1458
     */
1459 1052
    public function getEntityState($entity, $assume = null)
1460
    {
1461 1052
        $oid = spl_object_hash($entity);
1462
1463 1052
        if (isset($this->entityStates[$oid])) {
1464 786
            return $this->entityStates[$oid];
1465
        }
1466
1467 1046
        if ($assume !== null) {
1468 1042
            return $assume;
1469
        }
1470
1471
        // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known.
1472
        // Note that you can not remember the NEW or DETACHED state in _entityStates since
1473
        // the UoW does not hold references to such objects and the object hash can be reused.
1474
        // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it.
1475 13
        $class = $this->em->getClassMetadata(get_class($entity));
1476 13
        $id    = $class->getIdentifierValues($entity);
1477
1478 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...
1479 5
            return self::STATE_NEW;
1480
        }
1481
1482 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...
1483 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...
1484
        }
1485
1486
        switch (true) {
1487 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...
1488
                // Check for a version field, if available, to avoid a db lookup.
1489 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...
1490 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...
1491
                        ? self::STATE_DETACHED
1492 1
                        : self::STATE_NEW;
1493
                }
1494
1495
                // Last try before db lookup: check the identity map.
1496 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...
1497 1
                    return self::STATE_DETACHED;
1498
                }
1499
1500
                // db lookup
1501 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...
1502
                    return self::STATE_DETACHED;
1503
                }
1504
1505 4
                return self::STATE_NEW;
1506
1507 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...
1508
                // if we have a pre insert generator we can't be sure that having an id
1509
                // really means that the entity exists. We have to verify this through
1510
                // the last resort: a db lookup
1511
1512
                // Last try before db lookup: check the identity map.
1513
                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...
1514
                    return self::STATE_DETACHED;
1515
                }
1516
1517
                // db lookup
1518
                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...
1519
                    return self::STATE_DETACHED;
1520
                }
1521
1522
                return self::STATE_NEW;
1523
1524
            default:
1525 5
                return self::STATE_DETACHED;
1526
        }
1527
    }
1528
1529
    /**
1530
     * INTERNAL:
1531
     * Removes an entity from the identity map. This effectively detaches the
1532
     * entity from the persistence management of Doctrine.
1533
     *
1534
     * @ignore
1535
     *
1536
     * @param object $entity
1537
     *
1538
     * @return boolean
1539
     *
1540
     * @throws ORMInvalidArgumentException
1541
     */
1542 77
    public function removeFromIdentityMap($entity)
1543
    {
1544 77
        $oid           = spl_object_hash($entity);
1545 77
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1546 77
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1547
1548 77
        if ($idHash === '') {
1549
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
1550
        }
1551
1552 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...
1553
1554 77
        if (isset($this->identityMap[$className][$idHash])) {
1555 77
            unset($this->identityMap[$className][$idHash]);
1556 77
            unset($this->readOnlyObjects[$oid]);
1557
1558
            //$this->entityStates[$oid] = self::STATE_DETACHED;
1559
1560 77
            return true;
1561
        }
1562
1563
        return false;
1564
    }
1565
1566
    /**
1567
     * INTERNAL:
1568
     * Gets an entity in the identity map by its identifier hash.
1569
     *
1570
     * @ignore
1571
     *
1572
     * @param string $idHash
1573
     * @param string $rootClassName
1574
     *
1575
     * @return object
1576
     */
1577 6
    public function getByIdHash($idHash, $rootClassName)
1578
    {
1579 6
        return $this->identityMap[$rootClassName][$idHash];
1580
    }
1581
1582
    /**
1583
     * INTERNAL:
1584
     * Tries to get an entity by its identifier hash. If no entity is found for
1585
     * the given hash, FALSE is returned.
1586
     *
1587
     * @ignore
1588
     *
1589
     * @param mixed  $idHash        (must be possible to cast it to string)
1590
     * @param string $rootClassName
1591
     *
1592
     * @return object|bool The found entity or FALSE.
1593
     */
1594 34
    public function tryGetByIdHash($idHash, $rootClassName)
1595
    {
1596 34
        $stringIdHash = (string) $idHash;
1597
1598 34
        return isset($this->identityMap[$rootClassName][$stringIdHash])
1599 34
            ? $this->identityMap[$rootClassName][$stringIdHash]
1600 34
            : false;
1601
    }
1602
1603
    /**
1604
     * Checks whether an entity is registered in the identity map of this UnitOfWork.
1605
     *
1606
     * @param object $entity
1607
     *
1608
     * @return boolean
1609
     */
1610 212
    public function isInIdentityMap($entity)
1611
    {
1612 212
        $oid = spl_object_hash($entity);
1613
1614 212
        if ( ! isset($this->entityIdentifiers[$oid])) {
1615 31
            return false;
1616
        }
1617
1618 197
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1619 197
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1620
1621 197
        if ($idHash === '') {
1622
            return false;
1623
        }
1624
1625 197
        return isset($this->identityMap[$classMetadata->rootEntityName][$idHash]);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1626
    }
1627
1628
    /**
1629
     * INTERNAL:
1630
     * Checks whether an identifier hash exists in the identity map.
1631
     *
1632
     * @ignore
1633
     *
1634
     * @param string $idHash
1635
     * @param string $rootClassName
1636
     *
1637
     * @return boolean
1638
     */
1639
    public function containsIdHash($idHash, $rootClassName)
1640
    {
1641
        return isset($this->identityMap[$rootClassName][$idHash]);
1642
    }
1643
1644
    /**
1645
     * Persists an entity as part of the current unit of work.
1646
     *
1647
     * @param object $entity The entity to persist.
1648
     *
1649
     * @return void
1650
     */
1651 1035
    public function persist($entity)
1652
    {
1653 1035
        $visited = array();
1654
1655 1035
        $this->doPersist($entity, $visited);
1656 1028
    }
1657
1658
    /**
1659
     * Persists an entity as part of the current unit of work.
1660
     *
1661
     * This method is internally called during persist() cascades as it tracks
1662
     * the already visited entities to prevent infinite recursions.
1663
     *
1664
     * @param object $entity  The entity to persist.
1665
     * @param array  $visited The already visited entities.
1666
     *
1667
     * @return void
1668
     *
1669
     * @throws ORMInvalidArgumentException
1670
     * @throws UnexpectedValueException
1671
     */
1672 1035
    private function doPersist($entity, array &$visited)
1673
    {
1674 1035
        $oid = spl_object_hash($entity);
1675
1676 1035
        if (isset($visited[$oid])) {
1677 109
            return; // Prevent infinite recursion
1678
        }
1679
1680 1035
        $visited[$oid] = $entity; // Mark visited
1681
1682 1035
        $class = $this->em->getClassMetadata(get_class($entity));
1683
1684
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1685
        // If we would detect DETACHED here we would throw an exception anyway with the same
1686
        // consequences (not recoverable/programming error), so just assuming NEW here
1687
        // lets us avoid some database lookups for entities with natural identifiers.
1688 1035
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1689
1690
        switch ($entityState) {
1691 1035
            case self::STATE_MANAGED:
1692
                // Nothing to do, except if policy is "deferred explicit"
1693 236
                if ($class->isChangeTrackingDeferredExplicit()) {
1694 2
                    $this->scheduleForDirtyCheck($entity);
1695
                }
1696 236
                break;
1697
1698 1035
            case self::STATE_NEW:
1699 1034
                $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...
1700 1034
                break;
1701
1702 1
            case self::STATE_REMOVED:
1703
                // Entity becomes managed again
1704 1
                unset($this->entityDeletions[$oid]);
1705 1
                $this->addToIdentityMap($entity);
1706
1707 1
                $this->entityStates[$oid] = self::STATE_MANAGED;
1708 1
                break;
1709
1710
            case self::STATE_DETACHED:
1711
                // Can actually not happen right now since we assume STATE_NEW.
1712
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
1713
1714
            default:
1715
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1716
        }
1717
1718 1035
        $this->cascadePersist($entity, $visited);
1719 1028
    }
1720
1721
    /**
1722
     * Deletes an entity as part of the current unit of work.
1723
     *
1724
     * @param object $entity The entity to remove.
1725
     *
1726
     * @return void
1727
     */
1728 65
    public function remove($entity)
1729
    {
1730 65
        $visited = array();
1731
1732 65
        $this->doRemove($entity, $visited);
1733 65
    }
1734
1735
    /**
1736
     * Deletes an entity as part of the current unit of work.
1737
     *
1738
     * This method is internally called during delete() cascades as it tracks
1739
     * the already visited entities to prevent infinite recursions.
1740
     *
1741
     * @param object $entity  The entity to delete.
1742
     * @param array  $visited The map of the already visited entities.
1743
     *
1744
     * @return void
1745
     *
1746
     * @throws ORMInvalidArgumentException If the instance is a detached entity.
1747
     * @throws UnexpectedValueException
1748
     */
1749 65
    private function doRemove($entity, array &$visited)
1750
    {
1751 65
        $oid = spl_object_hash($entity);
1752
1753 65
        if (isset($visited[$oid])) {
1754 1
            return; // Prevent infinite recursion
1755
        }
1756
1757 65
        $visited[$oid] = $entity; // mark visited
1758
1759
        // Cascade first, because scheduleForDelete() removes the entity from the identity map, which
1760
        // can cause problems when a lazy proxy has to be initialized for the cascade operation.
1761 65
        $this->cascadeRemove($entity, $visited);
1762
1763 65
        $class       = $this->em->getClassMetadata(get_class($entity));
1764 65
        $entityState = $this->getEntityState($entity);
1765
1766
        switch ($entityState) {
1767 65
            case self::STATE_NEW:
1768 65
            case self::STATE_REMOVED:
1769
                // nothing to do
1770 2
                break;
1771
1772 65
            case self::STATE_MANAGED:
1773 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...
1774
1775 65
                if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1776 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...
1777
                }
1778
1779 65
                $this->scheduleForDelete($entity);
1780 65
                break;
1781
1782
            case self::STATE_DETACHED:
1783
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1784
            default:
1785
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1786
        }
1787
1788 65
    }
1789
1790
    /**
1791
     * Merges the state of the given detached entity into this UnitOfWork.
1792
     *
1793
     * @param object $entity
1794
     *
1795
     * @return object The managed copy of the entity.
1796
     *
1797
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1798
     *         attribute and the version check against the managed copy fails.
1799
     *
1800
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1801
     */
1802 41
    public function merge($entity)
1803
    {
1804 41
        $visited = array();
1805
1806 41
        return $this->doMerge($entity, $visited);
1807
    }
1808
1809
    /**
1810
     * Executes a merge operation on an entity.
1811
     *
1812
     * @param object      $entity
1813
     * @param array       $visited
1814
     * @param object|null $prevManagedCopy
1815
     * @param array|null  $assoc
1816
     *
1817
     * @return object The managed copy of the entity.
1818
     *
1819
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1820
     *         attribute and the version check against the managed copy fails.
1821
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1822
     * @throws EntityNotFoundException
1823
     */
1824 41
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, array $assoc = [])
1825
    {
1826 41
        $oid = spl_object_hash($entity);
1827
1828 41
        if (isset($visited[$oid])) {
1829 4
            $managedCopy = $visited[$oid];
1830
1831 4
            if ($prevManagedCopy !== null) {
1832 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
1833
            }
1834
1835 4
            return $managedCopy;
1836
        }
1837
1838 41
        $class = $this->em->getClassMetadata(get_class($entity));
1839
1840
        // First we assume DETACHED, although it can still be NEW but we can avoid
1841
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1842
        // we need to fetch it from the db anyway in order to merge.
1843
        // MANAGED entities are ignored by the merge operation.
1844 41
        $managedCopy = $entity;
1845
1846 41
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1847
            // Try to look the entity up in the identity map.
1848 40
            $id = $class->getIdentifierValues($entity);
1849
1850
            // If there is no ID, it is actually NEW.
1851 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...
1852 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...
1853
1854 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...
1855
            } else {
1856 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...
1857 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...
1858 35
                    : $id;
1859
1860 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 1924 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1861
1862 35
                if ($managedCopy) {
1863
                    // We have the entity in-memory already, just make sure its not removed.
1864 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 1860 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...
1865 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 1860 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...
1866
                    }
1867
                } else {
1868
                    // We need to fetch the managed copy in order to merge.
1869 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...
1870
                }
1871
1872 35
                if ($managedCopy === null) {
1873
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1874
                    // since the managed entity was not found.
1875 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...
1876 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1877 1
                            $class->getName(),
1878 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...
1879
                        );
1880
                    }
1881
1882 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...
1883 1
                    $class->setIdentifierValues($managedCopy, $id);
1884
1885 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...
1886
                }
1887
            }
1888
1889 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 1860 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...
1890 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...
1891 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1892 4
                $entityVersion      = $reflField->getValue($entity);
1893
1894
                // Throw exception if versions don't match.
1895 4
                if ($managedCopyVersion != $entityVersion) {
1896 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1897
                }
1898
            }
1899
1900 38
            $visited[$oid] = $managedCopy; // mark visited
1901
1902 38
            if ($this->isLoaded($entity)) {
1903 31
                if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) {
1904 4
                    $managedCopy->__load();
1905
                }
1906
1907 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 1860 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...
1908
            }
1909
1910 38
            if ($class->isChangeTrackingDeferredExplicit()) {
1911
                $this->scheduleForDirtyCheck($entity);
1912
            }
1913
        }
1914
1915 39
        if ($prevManagedCopy !== null) {
1916 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 1860 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...
1917
        }
1918
1919
        // Mark the managed copy visited as well
1920 39
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1921
1922 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 1860 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...
1923
1924 39
        return $managedCopy;
1925
    }
1926
1927
    /**
1928
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1929
     *
1930
     * @param object $entity
1931
     *
1932
     * @return bool
1933
     */
1934 39
    private function isLoaded($entity)
1935
    {
1936 39
        return !($entity instanceof Proxy) || $entity->__isInitialized();
1937
    }
1938
1939
    /**
1940
     * Sets/adds associated managed copies into the previous entity's association field
1941
     *
1942
     * @param object $entity
1943
     * @param array  $association
1944
     * @param object $previousManagedCopy
1945
     * @param object $managedCopy
1946
     *
1947
     * @return void
1948
     */
1949 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1950
    {
1951 6
        $assocField = $association['fieldName'];
1952 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1953
1954 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1955 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...
1956
1957 6
            return;
1958
        }
1959
1960 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...
1961 1
        $value[] = $managedCopy;
1962
1963 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1964 1
            $class = $this->em->getClassMetadata(get_class($entity));
1965
1966 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...
1967
        }
1968 1
    }
1969
1970
    /**
1971
     * Detaches an entity from the persistence management. It's persistence will
1972
     * no longer be managed by Doctrine.
1973
     *
1974
     * @param object $entity The entity to detach.
1975
     *
1976
     * @return void
1977
     */
1978 12
    public function detach($entity)
1979
    {
1980 12
        $visited = array();
1981
1982 12
        $this->doDetach($entity, $visited);
1983 12
    }
1984
1985
    /**
1986
     * Executes a detach operation on the given entity.
1987
     *
1988
     * @param object  $entity
1989
     * @param array   $visited
1990
     * @param boolean $noCascade if true, don't cascade detach operation.
1991
     *
1992
     * @return void
1993
     */
1994 15
    private function doDetach($entity, array &$visited, $noCascade = false)
1995
    {
1996 15
        $oid = spl_object_hash($entity);
1997
1998 15
        if (isset($visited[$oid])) {
1999
            return; // Prevent infinite recursion
2000
        }
2001
2002 15
        $visited[$oid] = $entity; // mark visited
2003
2004 15
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
2005 15
            case self::STATE_MANAGED:
2006 13
                if ($this->isInIdentityMap($entity)) {
2007 12
                    $this->removeFromIdentityMap($entity);
2008
                }
2009
2010
                unset(
2011 13
                    $this->entityInsertions[$oid],
2012 13
                    $this->entityUpdates[$oid],
2013 13
                    $this->entityDeletions[$oid],
2014 13
                    $this->entityIdentifiers[$oid],
2015 13
                    $this->entityStates[$oid],
2016 13
                    $this->originalEntityData[$oid],
2017 13
                    $this->entityShouldBeInserted[$oid]
2018
                );
2019 13
                break;
2020 3
            case self::STATE_NEW:
2021 3
            case self::STATE_DETACHED:
2022 3
                return;
2023
        }
2024
2025 13
        if ( ! $noCascade) {
2026 13
            $this->cascadeDetach($entity, $visited);
2027
        }
2028 13
    }
2029
2030
    /**
2031
     * Refreshes the state of the given entity from the database, overwriting
2032
     * any local, unpersisted changes.
2033
     *
2034
     * @param object $entity The entity to refresh.
2035
     *
2036
     * @return void
2037
     *
2038
     * @throws InvalidArgumentException If the entity is not MANAGED.
2039
     */
2040 17
    public function refresh($entity)
2041
    {
2042 17
        $visited = array();
2043
2044 17
        $this->doRefresh($entity, $visited);
2045 17
    }
2046
2047
    /**
2048
     * Executes a refresh operation on an entity.
2049
     *
2050
     * @param object $entity  The entity to refresh.
2051
     * @param array  $visited The already visited entities during cascades.
2052
     *
2053
     * @return void
2054
     *
2055
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2056
     */
2057 17
    private function doRefresh($entity, array &$visited)
2058
    {
2059 17
        $oid = spl_object_hash($entity);
2060
2061 17
        if (isset($visited[$oid])) {
2062
            return; // Prevent infinite recursion
2063
        }
2064
2065 17
        $visited[$oid] = $entity; // mark visited
2066
2067 17
        $class = $this->em->getClassMetadata(get_class($entity));
2068
2069 17
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2070
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2071
        }
2072
2073 17
        if (isset($this->entityIdentifiers[$oid])) {
2074 16
            $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...
2075 16
                array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2076
                $entity
2077
            );
2078
2079 16
            $this->cascadeRefresh($entity, $visited);
2080
        }
2081
2082 17
    }
2083
2084
    /**
2085
     * Cascades a refresh operation to associated entities.
2086
     *
2087
     * @param object $entity
2088
     * @param array  $visited
2089
     *
2090
     * @return void
2091
     */
2092 16
    private function cascadeRefresh($entity, array &$visited)
2093
    {
2094 16
        $class = $this->em->getClassMetadata(get_class($entity));
2095
2096 16
        $associationMappings = array_filter(
2097 16
            $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...
2098
            function ($assoc) { return $assoc['isCascadeRefresh']; }
2099
        );
2100
2101 16
        foreach ($associationMappings as $assoc) {
2102 4
            $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...
2103
2104
            switch (true) {
2105 4
                case ($relatedEntities instanceof PersistentCollection):
2106
                    // Unwrap so that foreach() does not initialize
2107 4
                    $relatedEntities = $relatedEntities->unwrap();
2108
                    // break; is commented intentionally!
2109
2110
                case ($relatedEntities instanceof Collection):
2111
                case (is_array($relatedEntities)):
2112 4
                    foreach ($relatedEntities as $relatedEntity) {
2113
                        $this->doRefresh($relatedEntity, $visited);
2114
                    }
2115 4
                    break;
2116
2117
                case ($relatedEntities !== null):
2118
                    $this->doRefresh($relatedEntities, $visited);
2119
                    break;
2120
2121 4
                default:
2122
                    // Do nothing
2123
            }
2124
        }
2125 16
    }
2126
2127
    /**
2128
     * Cascades a detach operation to associated entities.
2129
     *
2130
     * @param object $entity
2131
     * @param array  $visited
2132
     *
2133
     * @return void
2134
     */
2135 13
    private function cascadeDetach($entity, array &$visited)
2136
    {
2137 13
        $class = $this->em->getClassMetadata(get_class($entity));
2138
2139 13
        $associationMappings = array_filter(
2140 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...
2141
            function ($assoc) { return $assoc['isCascadeDetach']; }
2142
        );
2143
2144 13
        foreach ($associationMappings as $assoc) {
2145 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...
2146
2147
            switch (true) {
2148 3
                case ($relatedEntities instanceof PersistentCollection):
2149
                    // Unwrap so that foreach() does not initialize
2150 2
                    $relatedEntities = $relatedEntities->unwrap();
2151
                    // break; is commented intentionally!
2152
2153
                case ($relatedEntities instanceof Collection):
2154
                case (is_array($relatedEntities)):
2155 3
                    foreach ($relatedEntities as $relatedEntity) {
2156 1
                        $this->doDetach($relatedEntity, $visited);
2157
                    }
2158 3
                    break;
2159
2160
                case ($relatedEntities !== null):
2161
                    $this->doDetach($relatedEntities, $visited);
2162
                    break;
2163
2164 3
                default:
2165
                    // Do nothing
2166
            }
2167
        }
2168 13
    }
2169
2170
    /**
2171
     * Cascades a merge operation to associated entities.
2172
     *
2173
     * @param object $entity
2174
     * @param object $managedCopy
2175
     * @param array  $visited
2176
     *
2177
     * @return void
2178
     */
2179 39
    private function cascadeMerge($entity, $managedCopy, array &$visited)
2180
    {
2181 39
        $class = $this->em->getClassMetadata(get_class($entity));
2182
2183 39
        $associationMappings = array_filter(
2184 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...
2185
            function ($assoc) { return $assoc['isCascadeMerge']; }
2186
        );
2187
2188 39
        foreach ($associationMappings as $assoc) {
2189 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...
2190
2191 16
            if ($relatedEntities instanceof Collection) {
2192 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...
2193 1
                    continue;
2194
                }
2195
2196 9
                if ($relatedEntities instanceof PersistentCollection) {
2197
                    // Unwrap so that foreach() does not initialize
2198 5
                    $relatedEntities = $relatedEntities->unwrap();
2199
                }
2200
2201 9
                foreach ($relatedEntities as $relatedEntity) {
2202 9
                    $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
2203
                }
2204 7
            } else if ($relatedEntities !== null) {
2205 15
                $this->doMerge($relatedEntities, $visited, $managedCopy, $assoc);
2206
            }
2207
        }
2208 39
    }
2209
2210
    /**
2211
     * Cascades the save operation to associated entities.
2212
     *
2213
     * @param object $entity
2214
     * @param array  $visited
2215
     *
2216
     * @return void
2217
     */
2218 1035
    private function cascadePersist($entity, array &$visited)
2219
    {
2220 1035
        $class = $this->em->getClassMetadata(get_class($entity));
2221
2222 1035
        $associationMappings = array_filter(
2223 1035
            $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...
2224
            function ($assoc) { return $assoc['isCascadePersist']; }
2225
        );
2226
2227 1035
        foreach ($associationMappings as $assoc) {
2228 654
            $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...
2229
2230
            switch (true) {
2231 654
                case ($relatedEntities instanceof PersistentCollection):
2232
                    // Unwrap so that foreach() does not initialize
2233 21
                    $relatedEntities = $relatedEntities->unwrap();
2234
                    // break; is commented intentionally!
2235
2236
                case ($relatedEntities instanceof Collection):
2237 594
                case (is_array($relatedEntities)):
2238 558
                    if (($assoc['type'] & ClassMetadata::TO_MANY) <= 0) {
2239 3
                        throw ORMInvalidArgumentException::invalidAssociation(
2240 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...
2241
                            $assoc,
2242
                            $relatedEntities
2243
                        );
2244
                    }
2245
2246 555
                    foreach ($relatedEntities as $relatedEntity) {
2247 282
                        $this->doPersist($relatedEntity, $visited);
2248
                    }
2249
2250 555
                    break;
2251
2252 584
                case ($relatedEntities !== null):
2253 246
                    if (! $relatedEntities instanceof $assoc['targetEntity']) {
2254 4
                        throw ORMInvalidArgumentException::invalidAssociation(
2255 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...
2256
                            $assoc,
2257
                            $relatedEntities
2258
                        );
2259
                    }
2260
2261 242
                    $this->doPersist($relatedEntities, $visited);
2262 242
                    break;
2263
2264 648
                default:
2265
                    // Do nothing
2266
            }
2267
        }
2268 1028
    }
2269
2270
    /**
2271
     * Cascades the delete operation to associated entities.
2272
     *
2273
     * @param object $entity
2274
     * @param array  $visited
2275
     *
2276
     * @return void
2277
     */
2278 65
    private function cascadeRemove($entity, array &$visited)
2279
    {
2280 65
        $class = $this->em->getClassMetadata(get_class($entity));
2281
2282 65
        $associationMappings = array_filter(
2283 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...
2284
            function ($assoc) { return $assoc['isCascadeRemove']; }
2285
        );
2286
2287 65
        $entitiesToCascade = array();
2288
2289 65
        foreach ($associationMappings as $assoc) {
2290 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...
2291 6
                $entity->__load();
2292
            }
2293
2294 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...
2295
2296
            switch (true) {
2297 26
                case ($relatedEntities instanceof Collection):
2298 19
                case (is_array($relatedEntities)):
2299
                    // If its a PersistentCollection initialization is intended! No unwrap!
2300 20
                    foreach ($relatedEntities as $relatedEntity) {
2301 10
                        $entitiesToCascade[] = $relatedEntity;
2302
                    }
2303 20
                    break;
2304
2305 19
                case ($relatedEntities !== null):
2306 7
                    $entitiesToCascade[] = $relatedEntities;
2307 7
                    break;
2308
2309 26
                default:
2310
                    // Do nothing
2311
            }
2312
        }
2313
2314 65
        foreach ($entitiesToCascade as $relatedEntity) {
2315 16
            $this->doRemove($relatedEntity, $visited);
2316
        }
2317 65
    }
2318
2319
    /**
2320
     * Acquire a lock on the given entity.
2321
     *
2322
     * @param object $entity
2323
     * @param int    $lockMode
2324
     * @param int    $lockVersion
2325
     *
2326
     * @return void
2327
     *
2328
     * @throws ORMInvalidArgumentException
2329
     * @throws TransactionRequiredException
2330
     * @throws OptimisticLockException
2331
     */
2332 11
    public function lock($entity, $lockMode, $lockVersion = null)
2333
    {
2334 11
        if ($entity === null) {
2335 1
            throw new \InvalidArgumentException("No entity passed to UnitOfWork#lock().");
2336
        }
2337
2338 10
        if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
2339 1
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2340
        }
2341
2342 9
        $class = $this->em->getClassMetadata(get_class($entity));
2343
2344
        switch (true) {
2345 9
            case LockMode::OPTIMISTIC === $lockMode:
2346 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...
2347 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...
2348
                }
2349
2350 4
                if ($lockVersion === null) {
2351
                    return;
2352
                }
2353
2354 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...
2355 1
                    $entity->__load();
2356
                }
2357
2358 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...
2359
2360 4
                if ($entityVersion != $lockVersion) {
2361 2
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion);
2362
                }
2363
2364 2
                break;
2365
2366 3
            case LockMode::NONE === $lockMode:
2367 3
            case LockMode::PESSIMISTIC_READ === $lockMode:
2368 1
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
2369 3
                if (!$this->em->getConnection()->isTransactionActive()) {
2370 2
                    throw TransactionRequiredException::transactionRequired();
2371
                }
2372
2373 1
                $oid = spl_object_hash($entity);
2374
2375 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...
2376 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2377
                    $lockMode
2378
                );
2379 1
                break;
2380
2381
            default:
2382
                // Do nothing
2383
        }
2384 3
    }
2385
2386
    /**
2387
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2388
     *
2389
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2390
     */
2391 1014
    public function getCommitOrderCalculator()
2392
    {
2393 1014
        return new Internal\CommitOrderCalculator();
2394
    }
2395
2396
    /**
2397
     * Clears the UnitOfWork.
2398
     *
2399
     * @param string|null $entityName if given, only entities of this type will get detached.
2400
     *
2401
     * @return void
2402
     */
2403 1226
    public function clear($entityName = null)
2404
    {
2405 1226
        if ($entityName === null) {
2406 1225
            $this->identityMap =
2407 1225
            $this->entityIdentifiers =
2408 1225
            $this->originalEntityData =
2409 1225
            $this->entityChangeSets =
2410 1225
            $this->entityStates =
2411 1225
            $this->scheduledForSynchronization =
2412 1225
            $this->entityShouldBeInserted =
2413 1225
            $this->entityInsertions =
2414 1225
            $this->entityUpdates =
2415 1225
            $this->entityDeletions =
2416 1225
            $this->collectionDeletions =
2417 1225
            $this->collectionUpdates =
2418 1225
            $this->extraUpdates =
2419 1225
            $this->readOnlyObjects =
2420 1225
            $this->visitedCollections =
2421 1225
            $this->orphanRemovals = array();
2422
        } else {
2423 3
            $this->clearIdentityMapForEntityName($entityName);
2424 3
            $this->clearEntityInsertionsForEntityName($entityName);
2425
        }
2426
2427 1226
        if ($this->evm->hasListeners(Events::onClear)) {
2428 7
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2429
        }
2430 1226
    }
2431
2432
    /**
2433
     * INTERNAL:
2434
     * Schedules an orphaned entity for removal. The remove() operation will be
2435
     * invoked on that entity at the beginning of the next commit of this
2436
     * UnitOfWork.
2437
     *
2438
     * @ignore
2439
     *
2440
     * @param object $entity
2441
     *
2442
     * @return void
2443
     */
2444 17
    public function scheduleOrphanRemoval($entity)
2445
    {
2446 17
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2447 17
    }
2448
2449
    /**
2450
     * INTERNAL:
2451
     * Cancels a previously scheduled orphan removal.
2452
     *
2453
     * @ignore
2454
     *
2455
     * @param object $entity
2456
     *
2457
     * @return void
2458
     */
2459 112
    public function cancelOrphanRemoval($entity)
2460
    {
2461 112
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2462 112
    }
2463
2464
    /**
2465
     * INTERNAL:
2466
     * Schedules a complete collection for removal when this UnitOfWork commits.
2467
     *
2468
     * @param PersistentCollection $coll
2469
     *
2470
     * @return void
2471
     */
2472 13
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2473
    {
2474 13
        $coid = spl_object_hash($coll);
2475
2476
        // TODO: if $coll is already scheduled for recreation ... what to do?
2477
        // Just remove $coll from the scheduled recreations?
2478 13
        unset($this->collectionUpdates[$coid]);
2479
2480 13
        $this->collectionDeletions[$coid] = $coll;
2481 13
    }
2482
2483
    /**
2484
     * @param PersistentCollection $coll
2485
     *
2486
     * @return bool
2487
     */
2488
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2489
    {
2490
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2491
    }
2492
2493
    /**
2494
     * @param ClassMetadata $class
2495
     *
2496
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2497
     */
2498 674
    private function newInstance($class)
2499
    {
2500 674
        $entity = $class->newInstance();
2501
2502 674
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2503 4
            $entity->injectObjectManager($this->em, $class);
2504
        }
2505
2506 674
        return $entity;
2507
    }
2508
2509
    /**
2510
     * INTERNAL:
2511
     * Creates an entity. Used for reconstitution of persistent entities.
2512
     *
2513
     * Internal note: Highly performance-sensitive method.
2514
     *
2515
     * @ignore
2516
     *
2517
     * @param string $className The name of the entity class.
2518
     * @param array  $data      The data for the entity.
2519
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2520
     *
2521
     * @return object The managed entity instance.
2522
     *
2523
     * @todo Rename: getOrCreateEntity
2524
     */
2525 811
    public function createEntity($className, array $data, &$hints = array())
2526
    {
2527 811
        $class = $this->em->getClassMetadata($className);
2528
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2529
2530 811
        $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...
2531 811
        $idHash = implode(' ', $id);
2532
2533 811
        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...
2534 311
            $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...
2535 311
            $oid = spl_object_hash($entity);
2536
2537
            if (
2538 311
                isset($hints[Query::HINT_REFRESH])
2539 311
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2540 311
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2541 311
                && $unmanagedProxy instanceof Proxy
2542 311
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2543
            ) {
2544
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2545
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2546
                // refreshed object may be anything
2547
2548 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...
2549 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...
2550
                }
2551
2552 2
                return $unmanagedProxy;
2553
            }
2554
2555 309
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2556 22
                $entity->__setInitialized(true);
2557
2558 22
                $overrideLocalValues = true;
2559
2560 22
                if ($entity instanceof NotifyPropertyChanged) {
2561 22
                    $entity->addPropertyChangedListener($this);
2562
                }
2563
            } else {
2564 289
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2565
2566
                // If only a specific entity is set to refresh, check that it's the one
2567 289
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2568 71
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2569
                }
2570
            }
2571
2572 309
            if ($overrideLocalValues) {
2573
                // inject ObjectManager upon refresh.
2574 112
                if ($entity instanceof ObjectManagerAware) {
2575 3
                    $entity->injectObjectManager($this->em, $class);
2576
                }
2577
2578 309
                $this->originalEntityData[$oid] = $data;
2579
            }
2580
        } else {
2581 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...
2582 670
            $oid    = spl_object_hash($entity);
2583
2584 670
            $this->entityIdentifiers[$oid]  = $id;
2585 670
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2586 670
            $this->originalEntityData[$oid] = $data;
2587
2588 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...
2589
2590 670
            if ($entity instanceof NotifyPropertyChanged) {
2591 2
                $entity->addPropertyChangedListener($this);
2592
            }
2593
2594 670
            $overrideLocalValues = true;
2595
        }
2596
2597 810
        if ( ! $overrideLocalValues) {
2598 220
            return $entity;
2599
        }
2600
2601 707
        foreach ($data as $field => $value) {
2602 707
            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...
2603 707
                $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...
2604
            }
2605
        }
2606
2607
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2608 707
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2609
2610 707
        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...
2611
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2612
        }
2613
2614
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2615 707
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2616 33
            return $entity;
2617
        }
2618
2619 674
        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...
2620
            // Check if the association is not among the fetch-joined associations already.
2621 587
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2622 260
                continue;
2623
            }
2624
2625 565
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2626
2627
            switch (true) {
2628 565
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2629 485
                    if ( ! $assoc['isOwningSide']) {
2630
2631
                        // use the given entity association
2632 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2633
2634 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2635
2636 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...
2637 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...
2638
2639 2
                            continue 2;
2640
                        }
2641
2642
                        // Inverse side of x-to-one can never be lazy
2643 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...
2644
2645 62
                        continue 2;
2646
                    }
2647
2648
                    // use the entity association
2649 485
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2650 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...
2651 38
                        $this->originalEntityData[$oid][$field] = $data[$field];
2652
2653 38
                        continue;
2654
                    }
2655
2656 478
                    $associatedId = array();
2657
2658
                    // TODO: Is this even computed right in all cases of composite keys?
2659 478
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2660 478
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2661
2662 478
                        if ($joinColumnValue !== null) {
2663 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...
2664 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2665
                            } else {
2666 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...
2667
                            }
2668 286
                        } 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...
2669 286
                            && 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...
2670
                        ) {
2671
                            // the missing key is part of target's entity primary key
2672 7
                            $associatedId = array();
2673 478
                            break;
2674
                        }
2675
                    }
2676
2677 478
                    if ( ! $associatedId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $associatedId of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2678
                        // Foreign key is NULL
2679 286
                        $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...
2680 286
                        $this->originalEntityData[$oid][$field] = null;
2681
2682 286
                        continue;
2683
                    }
2684
2685 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...
2686 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...
2687
                    }
2688
2689
                    // Foreign key is set
2690
                    // Check identity map first
2691
                    // FIXME: Can break easily with composite keys if join column values are in
2692
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2693 284
                    $relatedIdHash = implode(' ', $associatedId);
2694
2695
                    switch (true) {
2696 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...
2697 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...
2698
2699
                            // If this is an uninitialized proxy, we are deferring eager loads,
2700
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2701
                            // then we can append this entity for eager loading!
2702 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...
2703 166
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2704 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...
2705 166
                                $newValue instanceof Proxy &&
2706 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...
2707
2708
                                $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...
2709
                            }
2710
2711 166
                            break;
2712
2713 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...
2714
                            // If it might be a subtype, it can not be lazy. There isn't even
2715
                            // a way to solve this with deferred eager loading, which means putting
2716
                            // an entity with subclasses at a *-to-one location is really bad! (performance-wise)
2717 30
                            $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
2718 30
                            break;
2719
2720
                        default:
2721
                            switch (true) {
2722
                                // We are negating the condition here. Other cases will assume it is valid!
2723 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...
2724 155
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2725 155
                                    break;
2726
2727
                                // Deferred eager load only works for single identifier classes
2728 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...
2729
                                    // TODO: Is there a faster approach?
2730 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...
2731
2732 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2733 7
                                    break;
2734
2735
                                default:
2736
                                    // TODO: This is very imperformant, ignore it?
2737
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2738
                                    break;
2739
                            }
2740
2741
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2742 162
                            $newValueOid = spl_object_hash($newValue);
2743 162
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2744 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...
2745
2746
                            if (
2747 162
                                $newValue instanceof NotifyPropertyChanged &&
2748 162
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2749
                            ) {
2750
                                $newValue->addPropertyChangedListener($this);
2751
                            }
2752 162
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2753
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2754 162
                            break;
2755
                    }
2756
2757 284
                    $this->originalEntityData[$oid][$field] = $newValue;
2758 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...
2759
2760 284
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2761 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...
2762 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...
2763
                    }
2764
2765 284
                    break;
2766
2767
                default:
2768
                    // Ignore if its a cached collection
2769 487
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2770
                        break;
2771
                    }
2772
2773
                    // use the given collection
2774 487
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2775
2776 3
                        $data[$field]->setOwner($entity, $assoc);
2777
2778 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...
2779 3
                        $this->originalEntityData[$oid][$field] = $data[$field];
2780
2781 3
                        break;
2782
                    }
2783
2784
                    // Inject collection
2785 487
                    $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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