Completed
Pull Request — master (#5850)
by Rico
68:47 queued 03:40
created

UnitOfWork::recomputeSingleEntityChangeSet()   C

Complexity

Conditions 17
Paths 128

Size

Total Lines 52
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 17.289

Importance

Changes 0
Metric Value
dl 0
loc 52
c 0
b 0
f 0
ccs 27
cts 30
cp 0.9
rs 5.4376
cc 17
eloc 29
nc 128
nop 2
crap 17.289

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM;
21
22
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
23
use Doctrine\DBAL\LockMode;
24
use Doctrine\ORM\Internal\HydrationCompleteHandler;
25
use Doctrine\ORM\Mapping\Reflection\ReflectionPropertiesGetter;
26
use Exception;
27
use InvalidArgumentException;
28
use UnexpectedValueException;
29
30
use Doctrine\Common\Collections\ArrayCollection;
31
use Doctrine\Common\Collections\Collection;
32
use Doctrine\Common\NotifyPropertyChanged;
33
use Doctrine\Common\PropertyChangedListener;
34
use Doctrine\Common\Persistence\ObjectManagerAware;
35
use Doctrine\ORM\Mapping\ClassMetadata;
36
use Doctrine\ORM\Proxy\Proxy;
37
38
use Doctrine\ORM\Event\LifecycleEventArgs;
39
use Doctrine\ORM\Event\PreUpdateEventArgs;
40
use Doctrine\ORM\Event\PreFlushEventArgs;
41
use Doctrine\ORM\Event\OnFlushEventArgs;
42
use Doctrine\ORM\Event\PostFlushEventArgs;
43
use Doctrine\ORM\Event\ListenersInvoker;
44
45
use Doctrine\ORM\Cache\Persister\CachedPersister;
46
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
47
use Doctrine\ORM\Persisters\Entity\SingleTablePersister;
48
use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
49
use Doctrine\ORM\Persisters\Collection\OneToManyPersister;
50
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
51
use Doctrine\ORM\Utility\IdentifierFlattener;
52
53
/**
54
 * The UnitOfWork is responsible for tracking changes to objects during an
55
 * "object-level" transaction and for writing out changes to the database
56
 * in the correct order.
57
 *
58
 * Internal note: This class contains highly performance-sensitive code.
59
 *
60
 * @since       2.0
61
 * @author      Benjamin Eberlei <[email protected]>
62
 * @author      Guilherme Blanco <[email protected]>
63
 * @author      Jonathan Wage <[email protected]>
64
 * @author      Roman Borschel <[email protected]>
65
 * @author      Rob Caiger <[email protected]>
66
 */
67
class UnitOfWork implements PropertyChangedListener
68
{
69
    /**
70
     * An entity is in MANAGED state when its persistence is managed by an EntityManager.
71
     */
72
    const STATE_MANAGED = 1;
73
74
    /**
75
     * An entity is new if it has just been instantiated (i.e. using the "new" operator)
76
     * and is not (yet) managed by an EntityManager.
77
     */
78
    const STATE_NEW = 2;
79
80
    /**
81
     * A detached entity is an instance with persistent state and identity that is not
82
     * (or no longer) associated with an EntityManager (and a UnitOfWork).
83
     */
84
    const STATE_DETACHED = 3;
85
86
    /**
87
     * A removed entity instance is an instance with a persistent identity,
88
     * associated with an EntityManager, whose persistent state will be deleted
89
     * on commit.
90
     */
91
    const STATE_REMOVED = 4;
92
93
    /**
94
     * Hint used to collect all primary keys of associated entities during hydration
95
     * and execute it in a dedicated query afterwards
96
     * @see https://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html?highlight=eager#temporarily-change-fetch-mode-in-dql
97
     */
98
    const HINT_DEFEREAGERLOAD = 'deferEagerLoad';
99
100
    /**
101
     * The identity map that holds references to all managed entities that have
102
     * an identity. The entities are grouped by their class name.
103
     * Since all classes in a hierarchy must share the same identifier set,
104
     * we always take the root class name of the hierarchy.
105
     *
106
     * @var array
107
     */
108
    private $identityMap = array();
109
110
    /**
111
     * Map of all identifiers of managed entities.
112
     * Keys are object ids (spl_object_hash).
113
     *
114
     * @var array
115
     */
116
    private $entityIdentifiers = array();
117
118
    /**
119
     * Map of the original entity data of managed entities.
120
     * Keys are object ids (spl_object_hash). This is used for calculating changesets
121
     * at commit time.
122
     *
123
     * Internal note: Note that PHPs "copy-on-write" behavior helps a lot with memory usage.
124
     *                A value will only really be copied if the value in the entity is modified
125
     *                by the user.
126
     *
127
     * @var array
128
     */
129
    private $originalEntityData = array();
130
131
    /**
132
     * Map of entity changes. Keys are object ids (spl_object_hash).
133
     * Filled at the beginning of a commit of the UnitOfWork and cleaned at the end.
134
     *
135
     * @var array
136
     */
137
    private $entityChangeSets = array();
138
139
    /**
140
     * The (cached) states of any known entities.
141
     * Keys are object ids (spl_object_hash).
142
     *
143
     * @var array
144
     */
145
    private $entityStates = array();
146
147
    /**
148
     * Map of entities that are scheduled for dirty checking at commit time.
149
     * This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT.
150
     * Keys are object ids (spl_object_hash).
151
     *
152
     * @var array
153
     */
154
    private $scheduledForSynchronization = array();
155
156
    /**
157
     * A list of all pending entity insertions.
158
     *
159
     * @var array
160
     */
161
    private $entityInsertions = array();
162
163
    /**
164
     * A list of all pending entity updates.
165
     *
166
     * @var array
167
     */
168
    private $entityUpdates = array();
169
170
    /**
171
     * Any pending extra updates that have been scheduled by persisters.
172
     *
173
     * @var array
174
     */
175
    private $extraUpdates = array();
176
177
    /**
178
     * A list of all pending entity deletions.
179
     *
180
     * @var array
181
     */
182
    private $entityDeletions = array();
183
184
    /**
185
     * All pending collection deletions.
186
     *
187
     * @var array
188
     */
189
    private $collectionDeletions = array();
190
191
    /**
192
     * All pending collection updates.
193
     *
194
     * @var array
195
     */
196
    private $collectionUpdates = array();
197
198
    /**
199
     * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork.
200
     * At the end of the UnitOfWork all these collections will make new snapshots
201
     * of their data.
202
     *
203
     * @var array
204
     */
205
    private $visitedCollections = array();
206
207
    /**
208
     * The EntityManager that "owns" this UnitOfWork instance.
209
     *
210
     * @var EntityManagerInterface
211
     */
212
    private $em;
213
214
    /**
215
     * The entity persister instances used to persist entity instances.
216
     *
217
     * @var array
218
     */
219
    private $persisters = array();
220
221
    /**
222
     * The collection persister instances used to persist collections.
223
     *
224
     * @var array
225
     */
226
    private $collectionPersisters = array();
227
228
    /**
229
     * The EventManager used for dispatching events.
230
     *
231
     * @var \Doctrine\Common\EventManager
232
     */
233
    private $evm;
234
235
    /**
236
     * The ListenersInvoker used for dispatching events.
237
     *
238
     * @var \Doctrine\ORM\Event\ListenersInvoker
239
     */
240
    private $listenersInvoker;
241
242
    /**
243
     * The IdentifierFlattener used for manipulating identifiers
244
     *
245
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
246
     */
247
    private $identifierFlattener;
248
249
    /**
250
     * Orphaned entities that are scheduled for removal.
251
     *
252
     * @var array
253
     */
254
    private $orphanRemovals = array();
255
256
    /**
257
     * Read-Only objects are never evaluated
258
     *
259
     * @var array
260
     */
261
    private $readOnlyObjects = array();
262
263
    /**
264
     * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
265
     *
266
     * @var array
267
     */
268
    private $eagerLoadingEntities = array();
269
270
    /**
271
     * @var boolean
272
     */
273
    protected $hasCache = false;
274
275
    /**
276
     * Helper for handling completion of hydration
277
     *
278
     * @var HydrationCompleteHandler
279
     */
280
    private $hydrationCompleteHandler;
281
282
    /**
283
     * @var ReflectionPropertiesGetter
284
     */
285
    private $reflectionPropertiesGetter;
286
287
    /**
288
     * Initializes a new UnitOfWork instance, bound to the given EntityManager.
289
     *
290
     * @param EntityManagerInterface $em
291
     */
292 2323
    public function __construct(EntityManagerInterface $em)
293
    {
294 2323
        $this->em                         = $em;
295 2323
        $this->evm                        = $em->getEventManager();
296 2323
        $this->listenersInvoker           = new ListenersInvoker($em);
297 2323
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
298 2323
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
299 2323
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
300 2323
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
301 2323
    }
302
303
    /**
304
     * Commits the UnitOfWork, executing all operations that have been postponed
305
     * up to this point. The state of all managed entities will be synchronized with
306
     * the database.
307
     *
308
     * The operations are executed in the following order:
309
     *
310
     * 1) All entity insertions
311
     * 2) All entity updates
312
     * 3) All collection deletions
313
     * 4) All collection updates
314
     * 5) All entity deletions
315
     *
316
     * @param null|object|array $entity
317
     *
318
     * @return void
319
     *
320
     * @throws \Exception
321
     */
322 1012
    public function commit($entity = null)
323
    {
324
        // Raise preFlush
325 1012
        if ($this->evm->hasListeners(Events::preFlush)) {
326 2
            $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em));
327
        }
328
329
        // Compute changes done since last commit.
330 1012
        if ($entity === null) {
331 1004
            $this->computeChangeSets();
332 16
        } elseif (is_object($entity)) {
333 15
            $this->computeSingleEntityChangeSet($entity);
334 1
        } elseif (is_array($entity)) {
335 1
            foreach ($entity as $object) {
336 1
                $this->computeSingleEntityChangeSet($object);
337
            }
338
        }
339
340 1009
        if ( ! ($this->entityInsertions ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityInsertions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
341 166
                $this->entityDeletions ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityDeletions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
342 130
                $this->entityUpdates ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityUpdates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
343 40
                $this->collectionUpdates ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->collectionUpdates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
344 37
                $this->collectionDeletions ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->collectionDeletions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
345 1009
                $this->orphanRemovals)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->orphanRemovals of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
346 25
            $this->dispatchOnFlushEvent();
347 25
            $this->dispatchPostFlushEvent();
348
349 25
            return; // Nothing to do.
350
        }
351
352 1005
        if ($this->orphanRemovals) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->orphanRemovals of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
353 16
            foreach ($this->orphanRemovals as $orphan) {
354 16
                $this->remove($orphan);
355
            }
356
        }
357
358 1005
        $this->dispatchOnFlushEvent();
359
360
        // Now we need a commit order to maintain referential integrity
361 1005
        $commitOrder = $this->getCommitOrder();
362
363 1005
        $conn = $this->em->getConnection();
364 1005
        $conn->beginTransaction();
365
366
        try {
367
            // Collection deletions (deletions of complete collections)
368 1005
            foreach ($this->collectionDeletions as $collectionToDelete) {
369 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
370
            }
371
372 1005
            if ($this->entityInsertions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityInsertions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
373 1001
                foreach ($commitOrder as $class) {
374 1001
                    $this->executeInserts($class);
375
                }
376
            }
377
378 1004
            if ($this->entityUpdates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityUpdates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
379 116
                foreach ($commitOrder as $class) {
380 116
                    $this->executeUpdates($class);
381
                }
382
            }
383
384
            // Extra updates that were requested by persisters.
385 1000
            if ($this->extraUpdates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->extraUpdates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
386 40
                $this->executeExtraUpdates();
387
            }
388
389
            // Collection updates (deleteRows, updateRows, insertRows)
390 1000
            foreach ($this->collectionUpdates as $collectionToUpdate) {
391 529
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
392
            }
393
394
            // Entity deletions come last and need to be in reverse commit order
395 1000
            if ($this->entityDeletions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityDeletions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
396 63
                for ($count = count($commitOrder), $i = $count - 1; $i >= 0 && $this->entityDeletions; --$i) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityDeletions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
397 63
                    $this->executeDeletions($commitOrder[$i]);
398
                }
399
            }
400
401 1000
            $conn->commit();
402 11
        } catch (Exception $e) {
403 11
            $this->em->close();
404 11
            $conn->rollBack();
405
406 11
            $this->afterTransactionRolledBack();
407
408 11
            throw $e;
409
        }
410
411 1000
        $this->afterTransactionComplete();
412
413
        // Take new snapshots from visited collections
414 1000
        foreach ($this->visitedCollections as $coll) {
415 528
            $coll->takeSnapshot();
416
        }
417
418 1000
        $this->dispatchPostFlushEvent();
419
420
        // Clear up
421 999
        $this->entityInsertions =
422 999
        $this->entityUpdates =
423 999
        $this->entityDeletions =
424 999
        $this->extraUpdates =
425 999
        $this->entityChangeSets =
426 999
        $this->collectionUpdates =
427 999
        $this->collectionDeletions =
428 999
        $this->visitedCollections =
429 999
        $this->scheduledForSynchronization =
430 999
        $this->orphanRemovals = array();
431 999
    }
432
433
    /**
434
     * Computes the changesets of all entities scheduled for insertion.
435
     *
436
     * @return void
437
     */
438 1011
    private function computeScheduleInsertsChangeSets()
439
    {
440 1011
        foreach ($this->entityInsertions as $entity) {
441 1003
            $class = $this->em->getClassMetadata(get_class($entity));
442
443 1003
            $this->computeChangeSet($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return false;
}

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1138
1139 1005
            $newNodes[] = $class;
1140
        }
1141
1142
        // Calculate dependencies for new nodes
1143 1005
        while ($class = array_pop($newNodes)) {
1144 1005
            foreach ($class->associationMappings as $assoc) {
1145 884
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1146 844
                    continue;
1147
                }
1148
1149 837
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1150
1151 837
                if ( ! $calc->hasNode($targetClass->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1153
1154 648
                    $newNodes[] = $targetClass;
1155
                }
1156
1157 837
                $joinColumns = reset($assoc['joinColumns']);
1158 837
                $isNullable  = isset($joinColumns['nullable']) ? $joinColumns['nullable'] : false;
1159
1160 837
                $calc->addDependency($targetClass->name, $class->name, $isNullable ? 0 : 1);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1164 830
                    continue;
1165
                }
1166
1167 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...
1168 217
                    $targetSubClass = $this->em->getClassMetadata($subClassName);
1169
1170 217
                    if ( ! $calc->hasNode($subClassName)) {
1171 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...
1172
1173 189
                        $newNodes[] = $targetSubClass;
1174
                    }
1175
1176 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...
1177
                }
1178
            }
1179
        }
1180
1181 1005
        return $calc->sort();
1182
    }
1183
1184
    /**
1185
     * Schedules an entity for insertion into the database.
1186
     * If the entity already has an identifier, it will be added to the identity map.
1187
     *
1188
     * @param object $entity The entity to schedule for insertion.
1189
     *
1190
     * @return void
1191
     *
1192
     * @throws ORMInvalidArgumentException
1193
     * @throws \InvalidArgumentException
1194
     */
1195 1022
    public function scheduleForInsert($entity)
1196
    {
1197 1022
        $oid = spl_object_hash($entity);
1198
1199 1022
        if (isset($this->entityUpdates[$oid])) {
1200
            throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion.");
1201
        }
1202
1203 1022
        if (isset($this->entityDeletions[$oid])) {
1204 1
            throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
1205
        }
1206 1022
        if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) {
1207 1
            throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
1208
        }
1209
1210 1022
        if (isset($this->entityInsertions[$oid])) {
1211 1
            throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
1212
        }
1213
1214 1022
        $this->entityInsertions[$oid] = $entity;
1215
1216 1022
        if (isset($this->entityIdentifiers[$oid])) {
1217 260
            $this->addToIdentityMap($entity);
1218
        }
1219
1220 1022
        if ($entity instanceof NotifyPropertyChanged) {
1221 5
            $entity->addPropertyChangedListener($this);
1222
        }
1223 1022
    }
1224
1225
    /**
1226
     * Checks whether an entity is scheduled for insertion.
1227
     *
1228
     * @param object $entity
1229
     *
1230
     * @return boolean
1231
     */
1232 628
    public function isScheduledForInsert($entity)
1233
    {
1234 628
        return isset($this->entityInsertions[spl_object_hash($entity)]);
1235
    }
1236
1237
    /**
1238
     * Schedules an entity for being updated.
1239
     *
1240
     * @param object $entity The entity to schedule for being updated.
1241
     *
1242
     * @return void
1243
     *
1244
     * @throws ORMInvalidArgumentException
1245
     */
1246 1
    public function scheduleForUpdate($entity)
1247
    {
1248 1
        $oid = spl_object_hash($entity);
1249
1250 1
        if ( ! isset($this->entityIdentifiers[$oid])) {
1251
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update");
1252
        }
1253
1254 1
        if (isset($this->entityDeletions[$oid])) {
1255
            throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update");
1256
        }
1257
1258 1
        if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) {
1259 1
            $this->entityUpdates[$oid] = $entity;
1260
        }
1261 1
    }
1262
1263
    /**
1264
     * INTERNAL:
1265
     * Schedules an extra update that will be executed immediately after the
1266
     * regular entity updates within the currently running commit cycle.
1267
     *
1268
     * Extra updates for entities are stored as (entity, changeset) tuples.
1269
     *
1270
     * @ignore
1271
     *
1272
     * @param object $entity    The entity for which to schedule an extra update.
1273
     * @param array  $changeset The changeset of the entity (what to update).
1274
     *
1275
     * @return void
1276
     */
1277 40
    public function scheduleExtraUpdate($entity, array $changeset)
1278
    {
1279 40
        $oid         = spl_object_hash($entity);
1280 40
        $extraUpdate = array($entity, $changeset);
1281
1282 40
        if (isset($this->extraUpdates[$oid])) {
1283 1
            list(, $changeset2) = $this->extraUpdates[$oid];
1284
1285 1
            $extraUpdate = array($entity, $changeset + $changeset2);
1286
        }
1287
1288 40
        $this->extraUpdates[$oid] = $extraUpdate;
1289 40
    }
1290
1291
    /**
1292
     * Checks whether an entity is registered as dirty in the unit of work.
1293
     * Note: Is not very useful currently as dirty entities are only registered
1294
     * at commit time.
1295
     *
1296
     * @param object $entity
1297
     *
1298
     * @return boolean
1299
     */
1300
    public function isScheduledForUpdate($entity)
1301
    {
1302
        return isset($this->entityUpdates[spl_object_hash($entity)]);
1303
    }
1304
1305
    /**
1306
     * Checks whether an entity is registered to be checked in the unit of work.
1307
     *
1308
     * @param object $entity
1309
     *
1310
     * @return boolean
1311
     */
1312 1
    public function isScheduledForDirtyCheck($entity)
1313
    {
1314 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...
1315
1316 1
        return isset($this->scheduledForSynchronization[$rootEntityName][spl_object_hash($entity)]);
1317
    }
1318
1319
    /**
1320
     * INTERNAL:
1321
     * Schedules an entity for deletion.
1322
     *
1323
     * @param object $entity
1324
     *
1325
     * @return void
1326
     */
1327 66
    public function scheduleForDelete($entity)
1328
    {
1329 66
        $oid = spl_object_hash($entity);
1330
1331 66
        if (isset($this->entityInsertions[$oid])) {
1332 1
            if ($this->isInIdentityMap($entity)) {
1333
                $this->removeFromIdentityMap($entity);
1334
            }
1335
1336 1
            unset($this->entityInsertions[$oid], $this->entityStates[$oid]);
1337
1338 1
            return; // entity has not been persisted yet, so nothing more to do.
1339
        }
1340
1341 66
        if ( ! $this->isInIdentityMap($entity)) {
1342 1
            return;
1343
        }
1344
1345 65
        $this->removeFromIdentityMap($entity);
1346
1347 65
        if (isset($this->entityUpdates[$oid])) {
1348 2
            unset($this->entityUpdates[$oid]);
1349
        }
1350
1351 65
        if ( ! isset($this->entityDeletions[$oid])) {
1352 65
            $this->entityDeletions[$oid] = $entity;
1353 65
            $this->entityStates[$oid]    = self::STATE_REMOVED;
1354
        }
1355 65
    }
1356
1357
    /**
1358
     * Checks whether an entity is registered as removed/deleted with the unit
1359
     * of work.
1360
     *
1361
     * @param object $entity
1362
     *
1363
     * @return boolean
1364
     */
1365 17
    public function isScheduledForDelete($entity)
1366
    {
1367 17
        return isset($this->entityDeletions[spl_object_hash($entity)]);
1368
    }
1369
1370
    /**
1371
     * Checks whether an entity is scheduled for insertion, update or deletion.
1372
     *
1373
     * @param object $entity
1374
     *
1375
     * @return boolean
1376
     */
1377
    public function isEntityScheduled($entity)
1378
    {
1379
        $oid = spl_object_hash($entity);
1380
1381
        return isset($this->entityInsertions[$oid])
1382
            || isset($this->entityUpdates[$oid])
1383
            || isset($this->entityDeletions[$oid]);
1384
    }
1385
1386
    /**
1387
     * INTERNAL:
1388
     * Registers an entity in the identity map.
1389
     * Note that entities in a hierarchy are registered with the class name of
1390
     * the root entity.
1391
     *
1392
     * @ignore
1393
     *
1394
     * @param object $entity The entity to register.
1395
     *
1396
     * @return boolean TRUE if the registration was successful, FALSE if the identity of
1397
     *                 the entity in question is already managed.
1398
     *
1399
     * @throws ORMInvalidArgumentException
1400
     */
1401 1083
    public function addToIdentityMap($entity)
1402
    {
1403 1083
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1404 1083
        $idHash        = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]);
1405
1406 1083
        if ($idHash === '') {
1407 1
            throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1408
        }
1409
1410 1082
        $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...
1411
1412 1082
        if (isset($this->identityMap[$className][$idHash])) {
1413 78
            return false;
1414
        }
1415
1416 1082
        $this->identityMap[$className][$idHash] = $entity;
1417
1418 1082
        return true;
1419
    }
1420
1421
    /**
1422
     * Gets the state of an entity with regard to the current unit of work.
1423
     *
1424
     * @param object   $entity
1425
     * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED).
1426
     *                         This parameter can be set to improve performance of entity state detection
1427
     *                         by potentially avoiding a database lookup if the distinction between NEW and DETACHED
1428
     *                         is either known or does not matter for the caller of the method.
1429
     *
1430
     * @return int The entity state.
1431
     */
1432 1035
    public function getEntityState($entity, $assume = null)
1433
    {
1434 1035
        $oid = spl_object_hash($entity);
1435
1436 1035
        if (isset($this->entityStates[$oid])) {
1437 781
            return $this->entityStates[$oid];
1438
        }
1439
1440 1029
        if ($assume !== null) {
1441 1025
            return $assume;
1442
        }
1443
1444
        // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known.
1445
        // Note that you can not remember the NEW or DETACHED state in _entityStates since
1446
        // the UoW does not hold references to such objects and the object hash can be reused.
1447
        // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it.
1448 13
        $class = $this->em->getClassMetadata(get_class($entity));
1449 13
        $id    = $class->getIdentifierValues($entity);
1450
1451 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...
1452 5
            return self::STATE_NEW;
1453
        }
1454
1455 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...
1456 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...
1457
        }
1458
1459
        switch (true) {
1460 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...
1461
                // Check for a version field, if available, to avoid a db lookup.
1462 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...
1463 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...
1464
                        ? self::STATE_DETACHED
1465 1
                        : self::STATE_NEW;
1466
                }
1467
1468
                // Last try before db lookup: check the identity map.
1469 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...
1470 1
                    return self::STATE_DETACHED;
1471
                }
1472
1473
                // db lookup
1474 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...
1475
                    return self::STATE_DETACHED;
1476
                }
1477
1478 4
                return self::STATE_NEW;
1479
1480 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...
1481
                // if we have a pre insert generator we can't be sure that having an id
1482
                // really means that the entity exists. We have to verify this through
1483
                // the last resort: a db lookup
1484
1485
                // Last try before db lookup: check the identity map.
1486
                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...
1487
                    return self::STATE_DETACHED;
1488
                }
1489
1490
                // db lookup
1491
                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...
1492
                    return self::STATE_DETACHED;
1493
                }
1494
1495
                return self::STATE_NEW;
1496
1497
            default:
1498 5
                return self::STATE_DETACHED;
1499
        }
1500
    }
1501
1502
    /**
1503
     * INTERNAL:
1504
     * Removes an entity from the identity map. This effectively detaches the
1505
     * entity from the persistence management of Doctrine.
1506
     *
1507
     * @ignore
1508
     *
1509
     * @param object $entity
1510
     *
1511
     * @return boolean
1512
     *
1513
     * @throws ORMInvalidArgumentException
1514
     */
1515 76
    public function removeFromIdentityMap($entity)
1516
    {
1517 76
        $oid           = spl_object_hash($entity);
1518 76
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1519 76
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1520
1521 76
        if ($idHash === '') {
1522
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
1523
        }
1524
1525 76
        $className = $classMetadata->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1526
1527 76
        if (isset($this->identityMap[$className][$idHash])) {
1528 76
            unset($this->identityMap[$className][$idHash]);
1529 76
            unset($this->readOnlyObjects[$oid]);
1530
1531
            //$this->entityStates[$oid] = self::STATE_DETACHED;
1532
1533 76
            return true;
1534
        }
1535
1536
        return false;
1537
    }
1538
1539
    /**
1540
     * INTERNAL:
1541
     * Gets an entity in the identity map by its identifier hash.
1542
     *
1543
     * @ignore
1544
     *
1545
     * @param string $idHash
1546
     * @param string $rootClassName
1547
     *
1548
     * @return object
1549
     */
1550
    public function getByIdHash($idHash, $rootClassName)
1551
    {
1552
        return $this->identityMap[$rootClassName][$idHash];
1553
    }
1554
1555
    /**
1556
     * INTERNAL:
1557
     * Tries to get an entity by its identifier hash. If no entity is found for
1558
     * the given hash, FALSE is returned.
1559
     *
1560
     * @ignore
1561
     *
1562
     * @param mixed  $idHash        (must be possible to cast it to string)
1563
     * @param string $rootClassName
1564
     *
1565
     * @return object|bool The found entity or FALSE.
1566
     */
1567 34
    public function tryGetByIdHash($idHash, $rootClassName)
1568
    {
1569 34
        $stringIdHash = (string) $idHash;
1570
1571 34
        if (isset($this->identityMap[$rootClassName][$stringIdHash])) {
1572 34
            return $this->identityMap[$rootClassName][$stringIdHash];
1573
        }
1574
1575 2
        return false;
1576
    }
1577
1578
    /**
1579
     * Checks whether an entity is registered in the identity map of this UnitOfWork.
1580
     *
1581
     * @param object $entity
1582
     *
1583
     * @return boolean
1584
     */
1585 212
    public function isInIdentityMap($entity)
1586
    {
1587 212
        $oid = spl_object_hash($entity);
1588
1589 212
        if ( ! isset($this->entityIdentifiers[$oid])) {
1590 30
            return false;
1591
        }
1592
1593 197
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1594 197
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1595
1596 197
        if ($idHash === '') {
1597
            return false;
1598
        }
1599
1600 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...
1601
    }
1602
1603
    /**
1604
     * INTERNAL:
1605
     * Checks whether an identifier hash exists in the identity map.
1606
     *
1607
     * @ignore
1608
     *
1609
     * @param string $idHash
1610
     * @param string $rootClassName
1611
     *
1612
     * @return boolean
1613
     */
1614
    public function containsIdHash($idHash, $rootClassName)
1615
    {
1616
        return isset($this->identityMap[$rootClassName][$idHash]);
1617
    }
1618
1619
    /**
1620
     * Persists an entity as part of the current unit of work.
1621
     *
1622
     * @param object $entity The entity to persist.
1623
     *
1624
     * @return void
1625
     */
1626 1018
    public function persist($entity)
1627
    {
1628 1018
        $visited = array();
1629
1630 1018
        $this->doPersist($entity, $visited);
1631 1011
    }
1632
1633
    /**
1634
     * Persists an entity as part of the current unit of work.
1635
     *
1636
     * This method is internally called during persist() cascades as it tracks
1637
     * the already visited entities to prevent infinite recursions.
1638
     *
1639
     * @param object $entity  The entity to persist.
1640
     * @param array  $visited The already visited entities.
1641
     *
1642
     * @return void
1643
     *
1644
     * @throws ORMInvalidArgumentException
1645
     * @throws UnexpectedValueException
1646
     */
1647 1018
    private function doPersist($entity, array &$visited)
1648
    {
1649 1018
        $oid = spl_object_hash($entity);
1650
1651 1018
        if (isset($visited[$oid])) {
1652 109
            return; // Prevent infinite recursion
1653
        }
1654
1655 1018
        $visited[$oid] = $entity; // Mark visited
1656
1657 1018
        $class = $this->em->getClassMetadata(get_class($entity));
1658
1659
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1660
        // If we would detect DETACHED here we would throw an exception anyway with the same
1661
        // consequences (not recoverable/programming error), so just assuming NEW here
1662
        // lets us avoid some database lookups for entities with natural identifiers.
1663 1018
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1664
1665
        switch ($entityState) {
1666 1018
            case self::STATE_MANAGED:
1667
                // Nothing to do, except if policy is "deferred explicit"
1668 234
                if ($class->isChangeTrackingDeferredExplicit()) {
1669 2
                    $this->scheduleForDirtyCheck($entity);
1670
                }
1671 234
                break;
1672
1673 1018
            case self::STATE_NEW:
1674 1017
                $this->persistNew($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

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

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

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

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

Loading history...
1752
                }
1753
1754 65
                $this->scheduleForDelete($entity);
1755 65
                break;
1756
1757
            case self::STATE_DETACHED:
1758
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1759
            default:
1760
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1761
        }
1762
1763 65
    }
1764
1765
    /**
1766
     * Merges the state of the given detached entity into this UnitOfWork.
1767
     *
1768
     * @param object $entity
1769
     *
1770
     * @return object The managed copy of the entity.
1771
     *
1772
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1773
     *         attribute and the version check against the managed copy fails.
1774
     *
1775
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1776
     */
1777 40
    public function merge($entity)
1778
    {
1779 40
        $visited = array();
1780
1781 40
        return $this->doMerge($entity, $visited);
1782
    }
1783
1784
    /**
1785
     * Executes a merge operation on an entity.
1786
     *
1787
     * @param object      $entity
1788
     * @param array       $visited
1789
     * @param object|null $prevManagedCopy
1790
     * @param array|null  $assoc
1791
     *
1792
     * @return object The managed copy of the entity.
1793
     *
1794
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1795
     *         attribute and the version check against the managed copy fails.
1796
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1797
     * @throws EntityNotFoundException
1798
     */
1799 40
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, $assoc = null)
1800
    {
1801 40
        $oid = spl_object_hash($entity);
1802
1803 40
        if (isset($visited[$oid])) {
1804 4
            $managedCopy = $visited[$oid];
1805
1806 4
            if ($prevManagedCopy !== null) {
1807 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $assoc defined by parameter $assoc on line 1799 can also be of type null; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

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

An additional type check may prevent trouble.

Loading history...
1808
            }
1809
1810 4
            return $managedCopy;
1811
        }
1812
1813 40
        $class = $this->em->getClassMetadata(get_class($entity));
1814
1815
        // First we assume DETACHED, although it can still be NEW but we can avoid
1816
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1817
        // we need to fetch it from the db anyway in order to merge.
1818
        // MANAGED entities are ignored by the merge operation.
1819 40
        $managedCopy = $entity;
1820
1821 40
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1822
            // Try to look the entity up in the identity map.
1823 39
            $id = $class->getIdentifierValues($entity);
1824
1825
            // If there is no ID, it is actually NEW.
1826 39
            if ( ! $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

    return array();
}

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

    return array();
}

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

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

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

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

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

An additional type check may prevent trouble.

Loading history...
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1835 can also be of type boolean; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept object, maybe add an additional type check?

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2347 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2348
                    $lockMode
2349
                );
2350 1
                break;
2351
2352
            default:
2353
                // Do nothing
2354
        }
2355 3
    }
2356
2357
    /**
2358
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2359
     *
2360
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2361
     */
2362 1005
    public function getCommitOrderCalculator()
2363
    {
2364 1005
        return new Internal\CommitOrderCalculator();
2365
    }
2366
2367
    /**
2368
     * Clears the UnitOfWork.
2369
     *
2370
     * @param string|null $entityName if given, only entities of this type will get detached.
2371
     *
2372
     * @return void
2373
     */
2374 1215
    public function clear($entityName = null)
2375
    {
2376 1215
        if ($entityName === null) {
2377 1215
            $this->identityMap =
2378 1215
            $this->entityIdentifiers =
2379 1215
            $this->originalEntityData =
2380 1215
            $this->entityChangeSets =
2381 1215
            $this->entityStates =
2382 1215
            $this->scheduledForSynchronization =
2383 1215
            $this->entityInsertions =
2384 1215
            $this->entityUpdates =
2385 1215
            $this->entityDeletions =
2386 1215
            $this->collectionDeletions =
2387 1215
            $this->collectionUpdates =
2388 1215
            $this->extraUpdates =
2389 1215
            $this->readOnlyObjects =
2390 1215
            $this->visitedCollections =
2391 1215
            $this->orphanRemovals = array();
2392
        } else {
2393 2
            $this->clearIdentityMap($entityName);
2394
            $this->clearIdentityInsertions($entityName);
2395 2
        }
2396 2
2397 1
        if ($this->evm->hasListeners(Events::onClear)) {
2398
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2399
        }
2400 2
    }
2401 2
2402
    /**
2403
     * INTERNAL:
2404
     * Schedules an orphaned entity for removal. The remove() operation will be
2405
     * invoked on that entity at the beginning of the next commit of this
2406 1215
     * UnitOfWork.
2407 7
     *
2408
     * @ignore
2409 1215
     *
2410
     * @param object $entity
2411
     *
2412
     * @return void
2413
     */
2414
    public function scheduleOrphanRemoval($entity)
2415
    {
2416
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2417
    }
2418
2419
    /**
2420
     * INTERNAL:
2421
     * Cancels a previously scheduled orphan removal.
2422
     *
2423 17
     * @ignore
2424
     *
2425 17
     * @param object $entity
2426 17
     *
2427
     * @return void
2428
     */
2429
    public function cancelOrphanRemoval($entity)
2430
    {
2431
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2432
    }
2433
2434
    /**
2435
     * INTERNAL:
2436
     * Schedules a complete collection for removal when this UnitOfWork commits.
2437
     *
2438 111
     * @param PersistentCollection $coll
2439
     *
2440 111
     * @return void
2441 111
     */
2442
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2443
    {
2444
        $coid = spl_object_hash($coll);
2445
2446
        // TODO: if $coll is already scheduled for recreation ... what to do?
2447
        // Just remove $coll from the scheduled recreations?
2448
        if (isset($this->collectionUpdates[$coid])) {
2449
            unset($this->collectionUpdates[$coid]);
2450
        }
2451 13
2452
        $this->collectionDeletions[$coid] = $coll;
2453 13
    }
2454
2455
    /**
2456
     * @param PersistentCollection $coll
2457 13
     *
2458
     * @return bool
2459
     */
2460
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2461 13
    {
2462 13
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2463
    }
2464
2465
    /**
2466
     * @param ClassMetadata $class
2467
     *
2468
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2469
     */
2470
    private function newInstance($class)
2471
    {
2472
        $entity = $class->newInstance();
2473
2474
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2475
            $entity->injectObjectManager($this->em, $class);
2476
        }
2477
2478
        return $entity;
2479 667
    }
2480
2481 667
    /**
2482
     * INTERNAL:
2483 667
     * Creates an entity. Used for reconstitution of persistent entities.
2484 4
     *
2485
     * Internal note: Highly performance-sensitive method.
2486
     *
2487 667
     * @ignore
2488
     *
2489
     * @param string $className The name of the entity class.
2490
     * @param array  $data      The data for the entity.
2491
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2492
     *
2493
     * @return object The managed entity instance.
2494
     *
2495
     * @todo Rename: getOrCreateEntity
2496
     */
2497
    public function createEntity($className, array $data, &$hints = array())
2498
    {
2499
        $class = $this->em->getClassMetadata($className);
2500
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2501
2502
        $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...
2503
        $idHash = implode(' ', $id);
2504
2505
        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...
2506 806
            $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...
2507
            $oid = spl_object_hash($entity);
2508 806
2509
            if (
2510
                isset($hints[Query::HINT_REFRESH])
2511 806
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2512 806
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2513
                && $unmanagedProxy instanceof Proxy
2514 806
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2515 312
            ) {
2516 312
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2517
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2518
                // refreshed object may be anything
2519 312
2520 312
                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...
2521 312
                    $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...
2522 312
                }
2523 312
2524
                return $unmanagedProxy;
2525
            }
2526
2527
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2528
                $entity->__setInitialized(true);
2529 2
2530 2
                $overrideLocalValues = true;
2531
2532
                if ($entity instanceof NotifyPropertyChanged) {
2533 2
                    $entity->addPropertyChangedListener($this);
2534
                }
2535
            } else {
2536 310
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2537 21
2538
                // If only a specific entity is set to refresh, check that it's the one
2539 21
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2540
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2541 21
                }
2542 21
            }
2543
2544
            if ($overrideLocalValues) {
2545 291
                // inject ObjectManager upon refresh.
2546
                if ($entity instanceof ObjectManagerAware) {
2547
                    $entity->injectObjectManager($this->em, $class);
2548 291
                }
2549 72
2550
                $this->originalEntityData[$oid] = $data;
2551
            }
2552
        } else {
2553 310
            $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...
2554
            $oid    = spl_object_hash($entity);
2555 113
2556 3
            $this->entityIdentifiers[$oid]  = $id;
2557
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2558
            $this->originalEntityData[$oid] = $data;
2559 310
2560
            $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...
2561
2562 664
            if ($entity instanceof NotifyPropertyChanged) {
2563 664
                $entity->addPropertyChangedListener($this);
2564
            }
2565 664
2566 664
            $overrideLocalValues = true;
2567 664
        }
2568
2569 664
        if ( ! $overrideLocalValues) {
2570
            return $entity;
2571 664
        }
2572 2
2573
        foreach ($data as $field => $value) {
2574
            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...
2575 664
                $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...
2576
            }
2577
        }
2578 805
2579 220
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2580
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2581
2582 702
        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...
2583 702
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2584 702
        }
2585
2586
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2587
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2588
            return $entity;
2589 702
        }
2590
2591 702
        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...
2592
            // Check if the association is not among the fetch-joined associations already.
2593
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2594
                continue;
2595
            }
2596 702
2597 33
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2598
2599
            switch (true) {
2600 669
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2601
                    if ( ! $assoc['isOwningSide']) {
2602 586
2603 259
                        // use the given entity association
2604
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2605
2606 564
                            $this->originalEntityData[$oid][$field] = $data[$field];
2607
2608
                            $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...
2609 564
                            $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...
2610 484
2611
                            continue 2;
2612
                        }
2613 64
2614
                        // Inverse side of x-to-one can never be lazy
2615 2
                        $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...
2616
2617 2
                        continue 2;
2618 2
                    }
2619
2620 2
                    // use the entity association
2621
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2622
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2623
                        $this->originalEntityData[$oid][$field] = $data[$field];
2624 62
2625
                        continue;
2626 62
                    }
2627
2628
                    $associatedId = array();
2629
2630 484
                    // TODO: Is this even computed right in all cases of composite keys?
2631 37
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2632 37
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2633
2634 37
                        if ($joinColumnValue !== null) {
2635
                            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...
2636
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2637 477
                            } else {
2638
                                $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...
2639
                            }
2640 477
                        } 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...
2641 477
                            && 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...
2642
                        ) {
2643 477
                            // the missing key is part of target's entity primary key
2644 282
                            $associatedId = array();
2645 11
                            break;
2646
                        }
2647 282
                    }
2648
2649 287
                    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...
2650 287
                        // Foreign key is NULL
2651
                        $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...
2652
                        $this->originalEntityData[$oid][$field] = null;
2653 7
2654 477
                        continue;
2655
                    }
2656
2657
                    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...
2658 477
                        $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...
2659
                    }
2660 287
2661 287
                    // Foreign key is set
2662
                    // Check identity map first
2663 287
                    // FIXME: Can break easily with composite keys if join column values are in
2664
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2665
                    $relatedIdHash = implode(' ', $associatedId);
2666 282
2667 279
                    switch (true) {
2668
                        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...
2669
                            $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...
2670
2671
                            // If this is an uninitialized proxy, we are deferring eager loads,
2672
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2673
                            // then we can append this entity for eager loading!
2674 282
                            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...
2675
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2676
                                !$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...
2677 282
                                $newValue instanceof Proxy &&
2678 164
                                $newValue->__isInitialized__ === false) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2679
2680
                                $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...
2681
                            }
2682
2683 164
                            break;
2684 164
2685 164
                        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...
2686 164
                            // If it might be a subtype, it can not be lazy. There isn't even
2687 164
                            // a way to solve this with deferred eager loading, which means putting
2688
                            // an entity with subclasses at a *-to-one location is really bad! (performance-wise)
2689
                            $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
2690
                            break;
2691
2692 164
                        default:
2693
                            switch (true) {
2694 191
                                // We are negating the condition here. Other cases will assume it is valid!
2695
                                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...
2696
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2697
                                    break;
2698 30
2699 30
                                // Deferred eager load only works for single identifier classes
2700
                                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...
2701
                                    // TODO: Is there a faster approach?
2702
                                    $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...
2703
2704 162
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2705 155
                                    break;
2706 155
2707
                                default:
2708
                                    // TODO: This is very imperformant, ignore it?
2709 7
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2710
                                    break;
2711 7
                            }
2712
2713 7
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2714 7
                            $newValueOid = spl_object_hash($newValue);
2715
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2716
                            $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...
2717
2718
                            if (
2719
                                $newValue instanceof NotifyPropertyChanged &&
2720
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2721
                            ) {
2722
                                $newValue->addPropertyChangedListener($this);
2723 162
                            }
2724 162
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2725 162
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2726
                            break;
2727
                    }
2728 162
2729 162
                    $this->originalEntityData[$oid][$field] = $newValue;
2730
                    $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...
2731
2732
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2733 162
                        $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...
2734
                        $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...
2735 162
                    }
2736
2737
                    break;
2738 282
2739 282
                default:
2740
                    // Ignore if its a cached collection
2741 282
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2742 50
                        break;
2743 50
                    }
2744
2745
                    // use the given collection
2746 282
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2747
2748
                        $data[$field]->setOwner($entity, $assoc);
2749
2750 486
                        $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...
2751
                        $this->originalEntityData[$oid][$field] = $data[$field];
2752
2753
                        break;
2754
                    }
2755 486
2756
                    // Inject collection
2757 2
                    $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...
2758
                    $pColl->setOwner($entity, $assoc);
2759 2
                    $pColl->setInitialized(false);
2760 2
2761
                    $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...
2762 2
                    $reflField->setValue($entity, $pColl);
2763
2764
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2765
                        $this->loadCollection($pColl);
2766 486
                        $pColl->takeSnapshot();
2767 486
                    }
2768 486
2769
                    $this->originalEntityData[$oid][$field] = $pColl;
2770 486
                    break;
2771 486
            }
2772
        }
2773 486
2774 4
        if ($overrideLocalValues) {
2775 4
            // defer invoking of postLoad event to hydration complete step
2776
            $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...
2777
        }
2778 486
2779 564
        return $entity;
2780
    }
2781
2782
    /**
2783 669
     * @return void
2784
     */
2785 669
    public function triggerEagerLoads()
2786
    {
2787
        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...
2788 669
            return;
2789
        }
2790
2791
        // avoid infinite recursion
2792
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2793
        $this->eagerLoadingEntities = array();
2794 863
2795
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2796 863
            if ( ! $ids) {
2797 863
                continue;
2798
            }
2799
2800
            $class = $this->em->getClassMetadata($entityName);
2801 7
2802 7
            $this->getEntityPersister($entityName)->loadAll(
2803
                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...
2804 7
            );
2805 7
        }
2806
    }
2807
2808
    /**
2809 7
     * Initializes (loads) an uninitialized persistent collection of an entity.
2810
     *
2811 7
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2812 7
     *
2813
     * @return void
2814
     *
2815 7
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2816
     */
2817
    public function loadCollection(PersistentCollection $collection)
2818
    {
2819
        $assoc     = $collection->getMapping();
2820
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2821
2822
        switch ($assoc['type']) {
2823
            case ClassMetadata::ONE_TO_MANY:
2824
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2825
                break;
2826 142
2827
            case ClassMetadata::MANY_TO_MANY:
2828 142
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2829 142
                break;
2830
        }
2831 142
2832 142
        $collection->setInitialized(true);
2833 75
    }
2834 75
2835
    /**
2836 81
     * Gets the identity map of the UnitOfWork.
2837 81
     *
2838 81
     * @return array
2839
     */
2840
    public function getIdentityMap()
2841 142
    {
2842 142
        return $this->identityMap;
2843
    }
2844
2845
    /**
2846
     * Gets the original data of an entity. The original data is the data that was
2847
     * present at the time the entity was reconstituted from the database.
2848
     *
2849 2
     * @param object $entity
2850
     *
2851 2
     * @return array
2852
     */
2853
    public function getOriginalEntityData($entity)
2854
    {
2855
        $oid = spl_object_hash($entity);
2856
2857
        if (isset($this->originalEntityData[$oid])) {
2858
            return $this->originalEntityData[$oid];
2859
        }
2860
2861
        return array();
2862 114
    }
2863
2864 114
    /**
2865
     * @ignore
2866 114
     *
2867 111
     * @param object $entity
2868
     * @param array  $data
2869
     *
2870 4
     * @return void
2871
     */
2872
    public function setOriginalEntityData($entity, array $data)
2873
    {
2874
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2875
    }
2876
2877
    /**
2878
     * INTERNAL:
2879
     * Sets a property value of the original data array of an entity.
2880
     *
2881
     * @ignore
2882
     *
2883
     * @param string $oid
2884
     * @param string $property
2885
     * @param mixed  $value
2886
     *
2887
     * @return void
2888
     */
2889
    public function setOriginalEntityProperty($oid, $property, $value)
2890
    {
2891
        $this->originalEntityData[$oid][$property] = $value;
2892
    }
2893
2894
    /**
2895
     * Gets the identifier of an entity.
2896
     * The returned value is always an array of identifier values. If the entity
2897
     * has a composite identifier then the identifier values are in the same
2898 312
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2899
     *
2900 312
     * @param object $entity
2901 312
     *
2902
     * @return array The identifier values.
2903
     */
2904
    public function getEntityIdentifier($entity)
2905
    {
2906
        return $this->entityIdentifiers[spl_object_hash($entity)];
2907
    }
2908
2909
    /**
2910
     * Processes an entity instance to extract their identifier values.
2911
     *
2912
     * @param object $entity The entity instance.
2913 842
     *
2914
     * @return mixed A scalar value.
2915 842
     *
2916
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2917
     */
2918
    public function getSingleIdentifierValue($entity)
2919
    {
2920
        $class = $this->em->getClassMetadata(get_class($entity));
2921
2922
        if ($class->isIdentifierComposite) {
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3363
                if ( ! $class->isIdentifier($name)) {
3364 30
                    $prop->setValue($managedCopy, $prop->getValue($entity));
3365
                }
3366 30
            } else {
3367 30
                $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...
3368
3369 30
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3370
                    $other = $prop->getValue($entity);
3371 30
                    if ($other === null) {
3372 30
                        $prop->setValue($managedCopy, null);
3373 30
                    } else {
3374
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3375
                            // do not merge fields marked lazy that have not been fetched.
3376 28
                            continue;
3377
                        }
3378 28
3379 24
                        if ( ! $assoc2['isCascadeMerge']) {
3380 24
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3381 11
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3382
                                $relatedId   = $targetClass->getIdentifierValues($other);
3383 16
3384
                                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...
3385 4
                                    $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...
3386
                                } else {
3387
                                    $other = $this->em->getProxyFactory()->getProxy(
3388 12
                                        $assoc2['targetEntity'],
3389 6
                                        $relatedId
3390 3
                                    );
3391 3
                                    $this->registerManaged($other, $relatedId, array());
3392
                                }
3393 3
                            }
3394 2
3395
                            $prop->setValue($managedCopy, $other);
3396 1
                        }
3397 1
                    }
3398
                } else {
3399
                    $mergeCol = $prop->getValue($entity);
3400 1
3401
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3402
                        // do not merge fields marked lazy that have not been fetched.
3403
                        // keep the lazy persistent collection of the managed copy.
3404 20
                        continue;
3405
                    }
3406
3407
                    $managedCol = $prop->getValue($managedCopy);
3408 16
3409
                    if ( ! $managedCol) {
3410 16
                        $managedCol = new PersistentCollection(
3411
                            $this->em,
3412
                            $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...
3413 5
                            new ArrayCollection
3414
                        );
3415
                        $managedCol->setOwner($managedCopy, $assoc2);
3416 13
                        $prop->setValue($managedCopy, $managedCol);
3417
3418 13
                        $this->originalEntityData[spl_object_hash($entity)][$name] = $managedCol;
3419 3
                    }
3420 3
3421 3
                    if ($assoc2['isCascadeMerge']) {
3422 3
                        $managedCol->initialize();
3423
3424 3
                        // clear and set dirty a managed collection if its not also the same collection to merge from.
3425 3
                        if ( ! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
3426
                            $managedCol->unwrap()->clear();
3427 3
                            $managedCol->setDirty(true);
3428
3429
                            if ($assoc2['isOwningSide']
3430 13
                                && $assoc2['type'] == ClassMetadata::MANY_TO_MANY
3431 8
                                && $class->isChangeTrackingNotify()
3432
                            ) {
3433
                                $this->scheduleForDirtyCheck($managedCopy);
3434 8
                            }
3435 1
                        }
3436 1
                    }
3437
                }
3438 1
            }
3439 1
3440 1
            if ($class->isChangeTrackingNotify()) {
3441
                // Just treat all properties as changed, there is no other choice.
3442
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
3443
            }
3444
        }
3445
    }
3446
3447
    /**
3448
     * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
3449 30
     * Unit of work able to fire deferred events, related to loading events here.
3450
     *
3451 30
     * @internal should be called internally from object hydrators
3452
     */
3453
    public function hydrationComplete()
3454 30
    {
3455
        $this->hydrationCompleteHandler->hydrationComplete();
3456
    }
3457
3458
    /**
3459
     * @param $entityName
3460
     */
3461
    private function clearIdentityMap($entityName)
3462 874
    {
3463
        $visited = array();
3464 874
3465 874
        foreach ($this->identityMap as $className => $entities) {
3466
            if ($className !== $entityName) {
3467
                continue;
3468
            }
3469
3470
            foreach ($entities as $entity) {
3471
                $this->doDetach($entity, $visited, false);
3472
            }
3473
        }
3474
    }
3475
3476
    /**
3477
     * @param $entityName
3478
     */
3479
    private function clearIdentityInsertions($entityName)
3480
    {
3481
        foreach ($this->entityInsertions as $hash => $entity) {
3482
            if (get_class($entity) === $entityName) {
3483
                unset($this->entityInsertions[$hash]);
3484
            }
3485
        }
3486
    }
3487
}
3488