Completed
Pull Request — master (#6074)
by Šimon
09:24
created

UnitOfWork::executeDeletions()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 32
c 0
b 0
f 0
ccs 17
cts 17
cp 1
rs 8.439
cc 5
eloc 17
nc 6
nop 1
crap 5
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 2347
    public function __construct(EntityManagerInterface $em)
293
    {
294 2347
        $this->em                         = $em;
295 2347
        $this->evm                        = $em->getEventManager();
296 2347
        $this->listenersInvoker           = new ListenersInvoker($em);
297 2347
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
298 2347
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
299 2347
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
300 2347
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
301 2347
    }
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 1019
    public function commit($entity = null)
323
    {
324
        // Raise preFlush
325 1019
        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 1019
        if ($entity === null) {
331 1011
            $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 1016
        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 1016
                $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 1012
        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 1012
        $this->dispatchOnFlushEvent();
359
360
        // Now we need a commit order to maintain referential integrity
361 1012
        $commitOrder = $this->getCommitOrder();
362
363 1012
        $conn = $this->em->getConnection();
364 1012
        $conn->beginTransaction();
365
366
        try {
367
            // Collection deletions (deletions of complete collections)
368 1012
            foreach ($this->collectionDeletions as $collectionToDelete) {
369 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
370
            }
371
372 1012
            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 1008
                foreach ($commitOrder as $class) {
374 1008
                    $this->executeInserts($class);
375
                }
376
            }
377
378 1011
            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 1007
            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 1007
            foreach ($this->collectionUpdates as $collectionToUpdate) {
391 531
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
392
            }
393
394
            // Entity deletions come last and need to be in reverse commit order
395 1007
            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 1007
            $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 1007
        $this->afterTransactionComplete();
412
413
        // Take new snapshots from visited collections
414 1007
        foreach ($this->visitedCollections as $coll) {
415 530
            $coll->takeSnapshot();
416
        }
417
418 1007
        $this->dispatchPostFlushEvent();
419
420
        // Clear up
421 1006
        $this->entityInsertions =
422 1006
        $this->entityUpdates =
423 1006
        $this->entityDeletions =
424 1006
        $this->extraUpdates =
425 1006
        $this->entityChangeSets =
426 1006
        $this->collectionUpdates =
427 1006
        $this->collectionDeletions =
428 1006
        $this->visitedCollections =
429 1006
        $this->scheduledForSynchronization =
430 1006
        $this->orphanRemovals = array();
431
432 1006
        $this->dispatchAfterFlush();
433 1006
    }
434
435
    /**
436
     * Computes the changesets of all entities scheduled for insertion.
437
     *
438
     * @return void
439
     */
440 1018
    private function computeScheduleInsertsChangeSets()
441
    {
442 1018
        foreach ($this->entityInsertions as $entity) {
443 1010
            $class = $this->em->getClassMetadata(get_class($entity));
444
445 1010
            $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...
446
        }
447 1016
    }
448
449
    /**
450
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
451
     *
452
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
453
     * 2. Read Only entities are skipped.
454
     * 3. Proxies are skipped.
455
     * 4. Only if entity is properly managed.
456
     *
457
     * @param object $entity
458
     *
459
     * @return void
460
     *
461
     * @throws \InvalidArgumentException
462
     */
463 16
    private function computeSingleEntityChangeSet($entity)
464
    {
465 16
        $state = $this->getEntityState($entity);
466
467 16
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
468 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
469
        }
470
471 15
        $class = $this->em->getClassMetadata(get_class($entity));
472
473 15
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
474 14
            $this->persist($entity);
475
        }
476
477
        // Compute changes for INSERTed entities first. This must always happen even in this case.
478 15
        $this->computeScheduleInsertsChangeSets();
479
480 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...
481
            return;
482
        }
483
484
        // Ignore uninitialized proxy objects
485 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...
486 2
            return;
487
        }
488
489
        // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
490 13
        $oid = spl_object_hash($entity);
491
492 13
        if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
493 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...
494
        }
495 12
    }
496
497
    /**
498
     * Executes any extra updates that have been scheduled.
499
     */
500 40
    private function executeExtraUpdates()
501
    {
502 40
        foreach ($this->extraUpdates as $oid => $update) {
503 40
            list ($entity, $changeset) = $update;
504
505 40
            $this->entityChangeSets[$oid] = $changeset;
506 40
            $this->getEntityPersister(get_class($entity))->update($entity);
507
        }
508
509 40
        $this->extraUpdates = array();
510 40
    }
511
512
    /**
513
     * Gets the changeset for an entity.
514
     *
515
     * @param object $entity
516
     *
517
     * @return array
518
     */
519 1010
    public function & getEntityChangeSet($entity)
520
    {
521 1010
        $oid  = spl_object_hash($entity);
522 1010
        $data = array();
523
524 1010
        if (!isset($this->entityChangeSets[$oid])) {
525 1
            return $data;
526
        }
527
528 1010
        return $this->entityChangeSets[$oid];
529
    }
530
531
    /**
532
     * Computes the changes that happened to a single entity.
533
     *
534
     * Modifies/populates the following properties:
535
     *
536
     * {@link _originalEntityData}
537
     * If the entity is NEW or MANAGED but not yet fully persisted (only has an id)
538
     * then it was not fetched from the database and therefore we have no original
539
     * entity data yet. All of the current entity data is stored as the original entity data.
540
     *
541
     * {@link _entityChangeSets}
542
     * The changes detected on all properties of the entity are stored there.
543
     * A change is a tuple array where the first entry is the old value and the second
544
     * entry is the new value of the property. Changesets are used by persisters
545
     * to INSERT/UPDATE the persistent entity state.
546
     *
547
     * {@link _entityUpdates}
548
     * If the entity is already fully MANAGED (has been fetched from the database before)
549
     * and any changes to its properties are detected, then a reference to the entity is stored
550
     * there to mark it for an update.
551
     *
552
     * {@link _collectionDeletions}
553
     * If a PersistentCollection has been de-referenced in a fully MANAGED entity,
554
     * then this collection is marked for deletion.
555
     *
556
     * @ignore
557
     *
558
     * @internal Don't call from the outside.
559
     *
560
     * @param ClassMetadata $class  The class descriptor of the entity.
561
     * @param object        $entity The entity for which to compute the changes.
562
     *
563
     * @return void
564
     */
565 1020
    public function computeChangeSet(ClassMetadata $class, $entity)
566
    {
567 1020
        $oid = spl_object_hash($entity);
568
569 1020
        if (isset($this->readOnlyObjects[$oid])) {
570 2
            return;
571
        }
572
573 1020
        if ( ! $class->isInheritanceTypeNone()) {
574 308
            $class = $this->em->getClassMetadata(get_class($entity));
575
        }
576
577 1020
        $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...
578
579 1020
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
580 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...
581
        }
582
583 1020
        $actualData = array();
584
585 1020
        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...
586 1020
            $value = $refProp->getValue($entity);
587
588 1020
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
589 779
                if ($value instanceof PersistentCollection) {
590 199
                    if ($value->getOwner() === $entity) {
591 199
                        continue;
592
                    }
593
594 5
                    $value = new ArrayCollection($value->getValues());
595
                }
596
597
                // If $value is not a Collection then use an ArrayCollection.
598 774
                if ( ! $value instanceof Collection) {
599 242
                    $value = new ArrayCollection($value);
600
                }
601
602 774
                $assoc = $class->associationMappings[$name];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
612
613 774
                $actualData[$name] = $value;
614
615 774
                continue;
616
            }
617
618 1020
            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...
619 1020
                $actualData[$name] = $value;
620
            }
621
        }
622
623 1020
        if ( ! isset($this->originalEntityData[$oid])) {
624
            // Entity is either NEW or MANAGED but not yet fully persisted (only has an id).
625
            // These result in an INSERT.
626 1016
            $this->originalEntityData[$oid] = $actualData;
627 1016
            $changeSet = array();
628
629 1016
            foreach ($actualData as $propName => $actualValue) {
630 1001
                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...
631 950
                    $changeSet[$propName] = array(null, $actualValue);
632
633 950
                    continue;
634
                }
635
636 896
                $assoc = $class->associationMappings[$propName];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
834 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...
835
            }
836
837 716
            $state = $this->getEntityState($entry, self::STATE_NEW);
838
839 716
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
840
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
841
            }
842
843
            switch ($state) {
844 716
                case self::STATE_NEW:
845 39
                    if ( ! $assoc['isCascadePersist']) {
846 4
                        throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
847
                    }
848
849 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...
850 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...
851 35
                    break;
852
853 710
                case self::STATE_REMOVED:
854
                    // Consume the $value as array (it's either an array or an ArrayAccess)
855
                    // and remove the element from Collection.
856 4
                    if ($assoc['type'] & ClassMetadata::TO_MANY) {
857 3
                        unset($value[$key]);
858
                    }
859 4
                    break;
860
861 710
                case self::STATE_DETACHED:
862
                    // Can actually not happen right now as we assume STATE_NEW,
863
                    // so the exception will be raised from the DBAL layer (constraint violation).
864
                    throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
865
                    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...
866
867 713
                default:
868
                    // MANAGED associated entities are already taken into account
869
                    // during changeset calculation anyway, since they are in the identity map.
870
            }
871
        }
872 858
    }
873
874
    /**
875
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
876
     * @param object                              $entity
877
     *
878
     * @return void
879
     */
880 1036
    private function persistNew($class, $entity)
881
    {
882 1036
        $oid    = spl_object_hash($entity);
883 1036
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
884
885 1036
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
886 139
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
887
        }
888
889 1036
        $idGen = $class->idGenerator;
890
891 1036
        if ( ! $idGen->isPostInsertGenerator()) {
892 269
            $idValue = $idGen->generate($this->em, $entity);
0 ignored issues
show
Compatibility introduced by
$this->em of type object<Doctrine\ORM\EntityManagerInterface> is not a sub-type of object<Doctrine\ORM\EntityManager>. It seems like you assume a concrete implementation of the interface Doctrine\ORM\EntityManagerInterface to be always present.

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

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

Loading history...
893
894 269
            if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
895 1
                $idValue = array($class->identifier[0] => $idValue);
896
897 1
                $class->setIdentifierValues($entity, $idValue);
898
            }
899
900 269
            $this->entityIdentifiers[$oid] = $idValue;
901
        }
902
903 1036
        $this->entityStates[$oid] = self::STATE_MANAGED;
904
905 1036
        $this->scheduleForInsert($entity);
906 1036
    }
907
908
    /**
909
     * INTERNAL:
910
     * Computes the changeset of an individual entity, independently of the
911
     * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
912
     *
913
     * The passed entity must be a managed entity. If the entity already has a change set
914
     * because this method is invoked during a commit cycle then the change sets are added.
915
     * whereby changes detected in this method prevail.
916
     *
917
     * @ignore
918
     *
919
     * @param ClassMetadata $class  The class descriptor of the entity.
920
     * @param object        $entity The entity for which to (re)calculate the change set.
921
     *
922
     * @return void
923
     *
924
     * @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
925
     */
926 16
    public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
927
    {
928 16
        $oid = spl_object_hash($entity);
929
930 16
        if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
931
            throw ORMInvalidArgumentException::entityNotManaged($entity);
932
        }
933
934
        // skip if change tracking is "NOTIFY"
935 16
        if ($class->isChangeTrackingNotify()) {
936
            return;
937
        }
938
939 16
        if ( ! $class->isInheritanceTypeNone()) {
940 3
            $class = $this->em->getClassMetadata(get_class($entity));
941
        }
942
943 16
        $actualData = array();
944
945 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...
946 16
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
947 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...
948 16
                && ! $class->isCollectionValuedAssociation($name)) {
949 16
                $actualData[$name] = $refProp->getValue($entity);
950
            }
951
        }
952
953 16
        if ( ! isset($this->originalEntityData[$oid])) {
954
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
955
        }
956
957 16
        $originalData = $this->originalEntityData[$oid];
958 16
        $changeSet = array();
959
960 16
        foreach ($actualData as $propName => $actualValue) {
961 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
962
963 16
            if ($orgValue !== $actualValue) {
964 16
                $changeSet[$propName] = array($orgValue, $actualValue);
965
            }
966
        }
967
968 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...
969 7
            if (isset($this->entityChangeSets[$oid])) {
970 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
971 1
            } else if ( ! isset($this->entityInsertions[$oid])) {
972 1
                $this->entityChangeSets[$oid] = $changeSet;
973 1
                $this->entityUpdates[$oid]    = $entity;
974
            }
975 7
            $this->originalEntityData[$oid] = $actualData;
976
        }
977 16
    }
978
979
    /**
980
     * Executes all entity insertions for entities of the specified type.
981
     *
982
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
983
     *
984
     * @return void
985
     */
986 1008
    private function executeInserts($class)
987
    {
988 1008
        $entities   = array();
989 1008
        $className  = $class->name;
990 1008
        $persister  = $this->getEntityPersister($className);
991 1008
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
992
993 1008
        foreach ($this->entityInsertions as $oid => $entity) {
994
995 1008
            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...
996 858
                continue;
997
            }
998
999 1008
            $persister->addInsert($entity);
1000
1001 1008
            unset($this->entityInsertions[$oid]);
1002
1003 1008
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1004 1008
                $entities[] = $entity;
1005
            }
1006
        }
1007
1008 1008
        $postInsertIds = $persister->executeInserts();
1009
1010 1008
        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...
1011
            // Persister returned post-insert IDs
1012 921
            foreach ($postInsertIds as $postInsertId) {
1013 921
                $id      = $postInsertId['generatedId'];
1014 921
                $entity  = $postInsertId['entity'];
1015 921
                $oid     = spl_object_hash($entity);
1016 921
                $idField = $class->identifier[0];
1017
1018 921
                $class->reflFields[$idField]->setValue($entity, $id);
1019
1020 921
                $this->entityIdentifiers[$oid] = array($idField => $id);
1021 921
                $this->entityStates[$oid] = self::STATE_MANAGED;
1022 921
                $this->originalEntityData[$oid][$idField] = $id;
1023
1024 921
                $this->addToIdentityMap($entity);
1025
            }
1026
        }
1027
1028 1008
        foreach ($entities as $entity) {
1029 135
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1030
        }
1031 1008
    }
1032
1033
    /**
1034
     * Executes all entity updates for entities of the specified type.
1035
     *
1036
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1037
     *
1038
     * @return void
1039
     */
1040 116
    private function executeUpdates($class)
1041
    {
1042 116
        $className          = $class->name;
1043 116
        $persister          = $this->getEntityPersister($className);
1044 116
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1045 116
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1046
1047 116
        foreach ($this->entityUpdates as $oid => $entity) {
1048 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...
1049 74
                continue;
1050
            }
1051
1052 116
            if ($preUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1053 13
                $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->getEntityChangeSet($entity)), $preUpdateInvoke);
1054
1055 13
                $this->recomputeSingleEntityChangeSet($class, $entity);
1056
            }
1057
1058 116
            if ( ! empty($this->entityChangeSets[$oid])) {
1059 82
                $persister->update($entity);
1060
            }
1061
1062 112
            unset($this->entityUpdates[$oid]);
1063
1064 112
            if ($postUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1065 112
                $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new LifecycleEventArgs($entity, $this->em), $postUpdateInvoke);
1066
            }
1067
        }
1068 112
    }
1069
1070
    /**
1071
     * Executes all entity deletions for entities of the specified type.
1072
     *
1073
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1074
     *
1075
     * @return void
1076
     */
1077 63
    private function executeDeletions($class)
1078
    {
1079 63
        $className  = $class->name;
1080 63
        $persister  = $this->getEntityPersister($className);
1081 63
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove);
1082
1083 63
        foreach ($this->entityDeletions as $oid => $entity) {
1084 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...
1085 26
                continue;
1086
            }
1087
1088 63
            $persister->delete($entity);
1089
1090
            unset(
1091 63
                $this->entityDeletions[$oid],
1092 63
                $this->entityIdentifiers[$oid],
1093 63
                $this->originalEntityData[$oid],
1094 63
                $this->entityStates[$oid]
1095
            );
1096
1097
            // Entity with this $oid after deletion treated as NEW, even if the $oid
1098
            // is obtained by a new entity because the old one went out of scope.
1099
            //$this->entityStates[$oid] = self::STATE_NEW;
1100 63
            if ( ! $class->isIdentifierNatural()) {
1101 53
                $class->reflFields[$class->identifier[0]]->setValue($entity, null);
1102
            }
1103
1104 63
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1105 63
                $this->listenersInvoker->invoke($class, Events::postRemove, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1106
            }
1107
        }
1108 62
    }
1109
1110
    /**
1111
     * Gets the commit order.
1112
     *
1113
     * @param array|null $entityChangeSet
1114
     *
1115
     * @return array
1116
     */
1117 1012
    private function getCommitOrder(array $entityChangeSet = null)
1118
    {
1119 1012
        if ($entityChangeSet === null) {
1120 1012
            $entityChangeSet = array_merge($this->entityInsertions, $this->entityUpdates, $this->entityDeletions);
1121
        }
1122
1123 1012
        $calc = $this->getCommitOrderCalculator();
1124
1125
        // See if there are any new classes in the changeset, that are not in the
1126
        // commit order graph yet (don't have a node).
1127
        // We have to inspect changeSet to be able to correctly build dependencies.
1128
        // It is not possible to use IdentityMap here because post inserted ids
1129
        // are not yet available.
1130 1012
        $newNodes = array();
1131
1132 1012
        foreach ($entityChangeSet as $entity) {
1133 1012
            $class = $this->em->getClassMetadata(get_class($entity));
1134
1135 1012
            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...
1136 628
                continue;
1137
            }
1138
1139 1012
            $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...
1140
1141 1012
            $newNodes[] = $class;
1142
        }
1143
1144
        // Calculate dependencies for new nodes
1145 1012
        while ($class = array_pop($newNodes)) {
1146 1012
            foreach ($class->associationMappings as $assoc) {
1147 888
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1148 848
                    continue;
1149
                }
1150
1151 841
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1152
1153 841
                if ( ! $calc->hasNode($targetClass->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1407
        }
1408
1409 1096
        $idHash    = implode(' ', $identifier);
1410 1096
        $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 1096
        if (isset($this->identityMap[$className][$idHash])) {
1413 83
            return false;
1414
        }
1415
1416 1096
        $this->identityMap[$className][$idHash] = $entity;
1417
1418 1096
        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 1050
    public function getEntityState($entity, $assume = null)
1433
    {
1434 1050
        $oid = spl_object_hash($entity);
1435
1436 1050
        if (isset($this->entityStates[$oid])) {
1437 784
            return $this->entityStates[$oid];
1438
        }
1439
1440 1044
        if ($assume !== null) {
1441 1040
            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 77
    public function removeFromIdentityMap($entity)
1516
    {
1517 77
        $oid           = spl_object_hash($entity);
1518 77
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1519 77
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1520
1521 77
        if ($idHash === '') {
1522
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
1523
        }
1524
1525 77
        $className = $classMetadata->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1526
1527 77
        if (isset($this->identityMap[$className][$idHash])) {
1528 77
            unset($this->identityMap[$className][$idHash]);
1529 77
            unset($this->readOnlyObjects[$oid]);
1530
1531
            //$this->entityStates[$oid] = self::STATE_DETACHED;
1532
1533 77
            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 6
    public function getByIdHash($idHash, $rootClassName)
1551
    {
1552 6
        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
        return isset($this->identityMap[$rootClassName][$stringIdHash])
1572 34
            ? $this->identityMap[$rootClassName][$stringIdHash]
1573 34
            : false;
1574
    }
1575
1576
    /**
1577
     * Checks whether an entity is registered in the identity map of this UnitOfWork.
1578
     *
1579
     * @param object $entity
1580
     *
1581
     * @return boolean
1582
     */
1583 214
    public function isInIdentityMap($entity)
1584
    {
1585 214
        $oid = spl_object_hash($entity);
1586
1587 214
        if ( ! isset($this->entityIdentifiers[$oid])) {
1588 31
            return false;
1589
        }
1590
1591 199
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1592 199
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1593
1594 199
        if ($idHash === '') {
1595
            return false;
1596
        }
1597
1598 199
        return isset($this->identityMap[$classMetadata->rootEntityName][$idHash]);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

Loading history...
2499 812
        $idHash = implode(' ', $id);
2500
2501 812
        if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2502 312
            $entity = $this->identityMap[$class->rootEntityName][$idHash];
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2503 312
            $oid = spl_object_hash($entity);
2504
2505
            if (
2506 312
                isset($hints[Query::HINT_REFRESH])
2507 312
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2508 312
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2509 312
                && $unmanagedProxy instanceof Proxy
2510 312
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2511
            ) {
2512
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2513
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2514
                // refreshed object may be anything
2515
2516 2
                foreach ($class->identifier as $fieldName) {
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2518
                }
2519
2520 2
                return $unmanagedProxy;
2521
            }
2522
2523 310
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2524 22
                $entity->__setInitialized(true);
2525
2526 22
                $overrideLocalValues = true;
2527
2528 22
                if ($entity instanceof NotifyPropertyChanged) {
2529 22
                    $entity->addPropertyChangedListener($this);
2530
                }
2531
            } else {
2532 290
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2533
2534
                // If only a specific entity is set to refresh, check that it's the one
2535 290
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2536 71
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2537
                }
2538
            }
2539
2540 310
            if ($overrideLocalValues) {
2541
                // inject ObjectManager upon refresh.
2542 113
                if ($entity instanceof ObjectManagerAware) {
2543 3
                    $entity->injectObjectManager($this->em, $class);
2544
                }
2545
2546 310
                $this->originalEntityData[$oid] = $data;
2547
            }
2548
        } else {
2549 670
            $entity = $this->newInstance($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
2550 670
            $oid    = spl_object_hash($entity);
2551
2552 670
            $this->entityIdentifiers[$oid]  = $id;
2553 670
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2554 670
            $this->originalEntityData[$oid] = $data;
2555
2556 670
            $this->identityMap[$class->rootEntityName][$idHash] = $entity;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2557
2558 670
            if ($entity instanceof NotifyPropertyChanged) {
2559 2
                $entity->addPropertyChangedListener($this);
2560
            }
2561
2562 670
            $overrideLocalValues = true;
2563
        }
2564
2565 811
        if ( ! $overrideLocalValues) {
2566 220
            return $entity;
2567
        }
2568
2569 708
        foreach ($data as $field => $value) {
2570 708
            if (isset($class->fieldMappings[$field])) {
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2572
            }
2573
        }
2574
2575
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2576 708
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2577
2578 708
        if (isset($this->eagerLoadingEntities[$class->rootEntityName]) && ! $this->eagerLoadingEntities[$class->rootEntityName]) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2579
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2580
        }
2581
2582
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2583 708
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2584 33
            return $entity;
2585
        }
2586
2587 675
        foreach ($class->associationMappings as $field => $assoc) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2588
            // Check if the association is not among the fetch-joined associations already.
2589 588
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2590 261
                continue;
2591
            }
2592
2593 566
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2594
2595
            switch (true) {
2596 566
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2597 486
                    if ( ! $assoc['isOwningSide']) {
2598
2599
                        // use the given entity association
2600 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2601
2602 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2603
2604 2
                            $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2605 2
                            $targetClass->reflFields[$assoc['mappedBy']]->setValue($data[$field], $entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2606
2607 2
                            continue 2;
2608
                        }
2609
2610
                        // Inverse side of x-to-one can never be lazy
2611 62
                        $class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity));
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2612
2613 62
                        continue 2;
2614
                    }
2615
2616
                    // use the entity association
2617 486
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2618 38
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2619 38
                        $this->originalEntityData[$oid][$field] = $data[$field];
2620
2621 38
                        continue;
2622
                    }
2623
2624 479
                    $associatedId = array();
2625
2626
                    // TODO: Is this even computed right in all cases of composite keys?
2627 479
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2628 479
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2629
2630 479
                        if ($joinColumnValue !== null) {
2631 284
                            if ($targetClass->containsForeignIdentifier) {
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2632 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2633
                            } else {
2634 284
                                $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
0 ignored issues
show
Bug introduced by
Accessing fieldNames on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2638
                        ) {
2639
                            // the missing key is part of target's entity primary key
2640 7
                            $associatedId = array();
2641 479
                            break;
2642
                        }
2643
                    }
2644
2645 479
                    if ( ! $associatedId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $associatedId of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2646
                        // Foreign key is NULL
2647 287
                        $class->reflFields[$field]->setValue($entity, null);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2648 287
                        $this->originalEntityData[$oid][$field] = null;
2649
2650 287
                        continue;
2651
                    }
2652
2653 284
                    if ( ! isset($hints['fetchMode'][$class->name][$field])) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2654 281
                        $hints['fetchMode'][$class->name][$field] = $assoc['fetch'];
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2655
                    }
2656
2657
                    // Foreign key is set
2658
                    // Check identity map first
2659
                    // FIXME: Can break easily with composite keys if join column values are in
2660
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2661 284
                    $relatedIdHash = implode(' ', $associatedId);
2662
2663
                    switch (true) {
2664 284
                        case (isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash])):
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2665 166
                            $newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash];
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2666
2667
                            // If this is an uninitialized proxy, we are deferring eager loads,
2668
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2669
                            // then we can append this entity for eager loading!
2670 166
                            if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER &&
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2671 166
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2672 166
                                !$targetClass->isIdentifierComposite &&
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2673 166
                                $newValue instanceof Proxy &&
2674 166
                                $newValue->__isInitialized__ === false) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2675
2676
                                $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...
2677
                            }
2678
2679 166
                            break;
2680
2681 191
                        case ($targetClass->subClasses):
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2692 155
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2693 155
                                    break;
2694
2695
                                // Deferred eager load only works for single identifier classes
2696 7
                                case (isset($hints[self::HINT_DEFEREAGERLOAD]) && ! $targetClass->isIdentifierComposite):
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2697
                                    // TODO: Is there a faster approach?
2698 7
                                    $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2713
2714
                            if (
2715 162
                                $newValue instanceof NotifyPropertyChanged &&
2716 162
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2717
                            ) {
2718
                                $newValue->addPropertyChangedListener($this);
2719
                            }
2720 162
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2721
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2722 162
                            break;
2723
                    }
2724
2725 284
                    $this->originalEntityData[$oid][$field] = $newValue;
2726 284
                    $class->reflFields[$field]->setValue($entity, $newValue);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2727
2728 284
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2729 50
                        $inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2730 50
                        $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2731
                    }
2732
2733 284
                    break;
2734
2735
                default:
2736
                    // Ignore if its a cached collection
2737 488
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2738
                        break;
2739
                    }
2740
2741
                    // use the given collection
2742 488
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2743
2744 3
                        $data[$field]->setOwner($entity, $assoc);
2745
2746 3
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2747 3
                        $this->originalEntityData[$oid][$field] = $data[$field];
2748
2749 3
                        break;
2750
                    }
2751
2752
                    // Inject collection
2753 488
                    $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2758 488
                    $reflField->setValue($entity, $pColl);
2759
2760 488
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2761 4
                        $this->loadCollection($pColl);
2762 4
                        $pColl->takeSnapshot();
2763
                    }
2764
2765 488
                    $this->originalEntityData[$oid][$field] = $pColl;
2766 566
                    break;
2767
            }
2768
        }
2769
2770 675
        if ($overrideLocalValues) {
2771
            // defer invoking of postLoad event to hydration complete step
2772 675
            $this->hydrationCompleteHandler->deferPostLoadInvoking($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
2773
        }
2774
2775 675
        return $entity;
2776
    }
2777
2778
    /**
2779
     * @return void
2780
     */
2781 868
    public function triggerEagerLoads()
2782
    {
2783 868
        if ( ! $this->eagerLoadingEntities) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->eagerLoadingEntities of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2784 868
            return;
2785
        }
2786
2787
        // avoid infinite recursion
2788 7
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2789 7
        $this->eagerLoadingEntities = array();
2790
2791 7
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2792 7
            if ( ! $ids) {
2793
                continue;
2794
            }
2795
2796 7
            $class = $this->em->getClassMetadata($entityName);
2797
2798 7
            $this->getEntityPersister($entityName)->loadAll(
2799 7
                array_combine($class->identifier, array(array_values($ids)))
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2800
            );
2801
        }
2802 7
    }
2803
2804
    /**
2805
     * Initializes (loads) an uninitialized persistent collection of an entity.
2806
     *
2807
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2808
     *
2809
     * @return void
2810
     *
2811
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2812
     */
2813 143
    public function loadCollection(PersistentCollection $collection)
2814
    {
2815 143
        $assoc     = $collection->getMapping();
2816 143
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2817
2818 143
        switch ($assoc['type']) {
2819 143
            case ClassMetadata::ONE_TO_MANY:
2820 76
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2821 76
                break;
2822
2823 81
            case ClassMetadata::MANY_TO_MANY:
2824 81
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2825 81
                break;
2826
        }
2827
2828 143
        $collection->setInitialized(true);
2829 143
    }
2830
2831
    /**
2832
     * Gets the identity map of the UnitOfWork.
2833
     *
2834
     * @return array
2835
     */
2836 2
    public function getIdentityMap()
2837
    {
2838 2
        return $this->identityMap;
2839
    }
2840
2841
    /**
2842
     * Gets the original data of an entity. The original data is the data that was
2843
     * present at the time the entity was reconstituted from the database.
2844
     *
2845
     * @param object $entity
2846
     *
2847
     * @return array
2848
     */
2849 117
    public function getOriginalEntityData($entity)
2850
    {
2851 117
        $oid = spl_object_hash($entity);
2852
2853 117
        return isset($this->originalEntityData[$oid])
2854 113
            ? $this->originalEntityData[$oid]
2855 117
            : [];
2856
    }
2857
2858
    /**
2859
     * @ignore
2860
     *
2861
     * @param object $entity
2862
     * @param array  $data
2863
     *
2864
     * @return void
2865
     */
2866
    public function setOriginalEntityData($entity, array $data)
2867
    {
2868
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2869
    }
2870
2871
    /**
2872
     * INTERNAL:
2873
     * Sets a property value of the original data array of an entity.
2874
     *
2875
     * @ignore
2876
     *
2877
     * @param string $oid
2878
     * @param string $property
2879
     * @param mixed  $value
2880
     *
2881
     * @return void
2882
     */
2883 314
    public function setOriginalEntityProperty($oid, $property, $value)
2884
    {
2885 314
        $this->originalEntityData[$oid][$property] = $value;
2886 314
    }
2887
2888
    /**
2889
     * Gets the identifier of an entity.
2890
     * The returned value is always an array of identifier values. If the entity
2891
     * has a composite identifier then the identifier values are in the same
2892
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2893
     *
2894
     * @param object $entity
2895
     *
2896
     * @return array The identifier values.
2897
     */
2898 845
    public function getEntityIdentifier($entity)
2899
    {
2900 845
        return $this->entityIdentifiers[spl_object_hash($entity)];
2901
    }
2902
2903
    /**
2904
     * Processes an entity instance to extract their identifier values.
2905
     *
2906
     * @param object $entity The entity instance.
2907
     *
2908
     * @return mixed A scalar value.
2909
     *
2910
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2911
     */
2912 127
    public function getSingleIdentifierValue($entity)
2913
    {
2914 127
        $class = $this->em->getClassMetadata(get_class($entity));
2915
2916 127
        if ($class->isIdentifierComposite) {
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2925
    }
2926
2927
    /**
2928
     * Tries to find an entity with the given identifier in the identity map of
2929
     * this UnitOfWork.
2930
     *
2931
     * @param mixed  $id            The entity identifier to look for.
2932
     * @param string $rootClassName The name of the root class of the mapped entity hierarchy.
2933
     *
2934
     * @return object|bool Returns the entity with the specified identifier if it exists in
2935
     *                     this UnitOfWork, FALSE otherwise.
2936
     */
2937 523
    public function tryGetById($id, $rootClassName)
2938
    {
2939 523
        $idHash = implode(' ', (array) $id);
2940
2941 523
        return isset($this->identityMap[$rootClassName][$idHash])
2942 79
            ? $this->identityMap[$rootClassName][$idHash]
2943 523
            : false;
2944
    }
2945
2946
    /**
2947
     * Schedules an entity for dirty-checking at commit-time.
2948
     *
2949
     * @param object $entity The entity to schedule for dirty-checking.
2950
     *
2951
     * @return void
2952
     *
2953
     * @todo Rename: scheduleForSynchronization
2954
     */
2955 5
    public function scheduleForDirtyCheck($entity)
2956
    {
2957 5
        $rootClassName = $this->em->getClassMetadata(get_class($entity))->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2958
2959 5
        $this->scheduledForSynchronization[$rootClassName][spl_object_hash($entity)] = $entity;
2960 5
    }
2961
2962
    /**
2963
     * Checks whether the UnitOfWork has any pending insertions.
2964
     *
2965
     * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise.
2966
     */
2967
    public function hasPendingInsertions()
2968
    {
2969
        return ! empty($this->entityInsertions);
2970
    }
2971
2972
    /**
2973
     * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the
2974
     * number of entities in the identity map.
2975
     *
2976
     * @return integer
2977
     */
2978 1
    public function size()
2979
    {
2980 1
        $countArray = array_map('count', $this->identityMap);
2981
2982 1
        return array_sum($countArray);
2983
    }
2984
2985
    /**
2986
     * Gets the EntityPersister for an Entity.
2987
     *
2988
     * @param string $entityName The name of the Entity.
2989
     *
2990
     * @return \Doctrine\ORM\Persisters\Entity\EntityPersister
2991
     */
2992 1074
    public function getEntityPersister($entityName)
2993
    {
2994 1074
        if (isset($this->persisters[$entityName])) {
2995 849
            return $this->persisters[$entityName];
2996
        }
2997
2998 1074
        $class = $this->em->getClassMetadata($entityName);
2999
3000
        switch (true) {
3001 1074
            case ($class->isInheritanceTypeNone()):
3002 1036
                $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...
3003 1036
                break;
3004
3005 360
            case ($class->isInheritanceTypeSingleTable()):
3006 213
                $persister = new SingleTablePersister($this->em, $class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
3007 213
                break;
3008
3009 339
            case ($class->isInheritanceTypeJoined()):
3010 339
                $persister = new JoinedSubclassPersister($this->em, $class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
3011 339
                break;
3012
3013
            default:
3014
                throw new \RuntimeException('No persister found for entity.');
3015
        }
3016
3017 1074
        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...
3018 120
            $persister = $this->em->getConfiguration()
3019 120
                ->getSecondLevelCacheConfiguration()
3020 120
                ->getCacheFactory()
3021 120
                ->buildCachedEntityPersister($this->em, $persister, $class);
3022
        }
3023
3024 1074
        $this->persisters[$entityName] = $persister;
3025
3026 1074
        return $this->persisters[$entityName];
3027
    }
3028
3029
    /**
3030
     * Gets a collection persister for a collection-valued association.
3031
     *
3032
     * @param array $association
3033
     *
3034
     * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister
3035
     */
3036 570
    public function getCollectionPersister(array $association)
3037
    {
3038 570
        $role = isset($association['cache'])
3039 76
            ? $association['sourceEntity'] . '::' . $association['fieldName']
3040 570
            : $association['type'];
3041
3042 570
        if (isset($this->collectionPersisters[$role])) {
3043 449
            return $this->collectionPersisters[$role];
3044
        }
3045
3046 570
        $persister = ClassMetadata::ONE_TO_MANY === $association['type']
3047 404
            ? new OneToManyPersister($this->em)
3048 570
            : new ManyToManyPersister($this->em);
3049
3050 570
        if ($this->hasCache && isset($association['cache'])) {
3051 75
            $persister = $this->em->getConfiguration()
3052 75
                ->getSecondLevelCacheConfiguration()
3053 75
                ->getCacheFactory()
3054 75
                ->buildCachedCollectionPersister($this->em, $persister, $association);
3055
        }
3056
3057 570
        $this->collectionPersisters[$role] = $persister;
3058
3059 570
        return $this->collectionPersisters[$role];
3060
    }
3061
3062
    /**
3063
     * INTERNAL:
3064
     * Registers an entity as managed.
3065
     *
3066
     * @param object $entity The entity.
3067
     * @param array  $id     The identifier values.
3068
     * @param array  $data   The original entity data.
3069
     *
3070
     * @return void
3071
     */
3072 206
    public function registerManaged($entity, array $id, array $data)
3073
    {
3074 206
        $oid = spl_object_hash($entity);
3075
3076 206
        $this->entityIdentifiers[$oid]  = $id;
3077 206
        $this->entityStates[$oid]       = self::STATE_MANAGED;
3078 206
        $this->originalEntityData[$oid] = $data;
3079
3080 206
        $this->addToIdentityMap($entity);
3081
3082 200
        if ($entity instanceof NotifyPropertyChanged && ( ! $entity instanceof Proxy || $entity->__isInitialized())) {
3083 2
            $entity->addPropertyChangedListener($this);
3084
        }
3085 200
    }
3086
3087
    /**
3088
     * INTERNAL:
3089
     * Clears the property changeset of the entity with the given OID.
3090
     *
3091
     * @param string $oid The entity's OID.
3092
     *
3093
     * @return void
3094
     */
3095
    public function clearEntityChangeSet($oid)
3096
    {
3097
        $this->entityChangeSets[$oid] = array();
3098
    }
3099
3100
    /* PropertyChangedListener implementation */
3101
3102
    /**
3103
     * Notifies this UnitOfWork of a property change in an entity.
3104
     *
3105
     * @param object $entity       The entity that owns the property.
3106
     * @param string $propertyName The name of the property that changed.
3107
     * @param mixed  $oldValue     The old value of the property.
3108
     * @param mixed  $newValue     The new value of the property.
3109
     *
3110
     * @return void
3111
     */
3112 3
    public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
3113
    {
3114 3
        $oid   = spl_object_hash($entity);
3115 3
        $class = $this->em->getClassMetadata(get_class($entity));
3116
3117 3
        $isAssocField = isset($class->associationMappings[$propertyName]);
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3118
3119 3
        if ( ! $isAssocField && ! isset($class->fieldMappings[$propertyName])) {
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3120 1
            return; // ignore non-persistent fields
3121
        }
3122
3123
        // Update changeset and mark entity for synchronization
3124 3
        $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
3125
3126 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...
3127 3
            $this->scheduleForDirtyCheck($entity);
3128
        }
3129 3
    }
3130
3131
    /**
3132
     * Gets the currently scheduled entity insertions in this UnitOfWork.
3133
     *
3134
     * @return array
3135
     */
3136 2
    public function getScheduledEntityInsertions()
3137
    {
3138 2
        return $this->entityInsertions;
3139
    }
3140
3141
    /**
3142
     * Gets the currently scheduled entity updates in this UnitOfWork.
3143
     *
3144
     * @return array
3145
     */
3146 2
    public function getScheduledEntityUpdates()
3147
    {
3148 2
        return $this->entityUpdates;
3149
    }
3150
3151
    /**
3152
     * Gets the currently scheduled entity deletions in this UnitOfWork.
3153
     *
3154
     * @return array
3155
     */
3156 1
    public function getScheduledEntityDeletions()
3157
    {
3158 1
        return $this->entityDeletions;
3159
    }
3160
3161
    /**
3162
     * Gets the currently scheduled complete collection deletions
3163
     *
3164
     * @return array
3165
     */
3166 1
    public function getScheduledCollectionDeletions()
3167
    {
3168 1
        return $this->collectionDeletions;
3169
    }
3170
3171
    /**
3172
     * Gets the currently scheduled collection inserts, updates and deletes.
3173
     *
3174
     * @return array
3175
     */
3176
    public function getScheduledCollectionUpdates()
3177
    {
3178
        return $this->collectionUpdates;
3179
    }
3180
3181
    /**
3182
     * Helper method to initialize a lazy loading proxy or persistent collection.
3183
     *
3184
     * @param object $obj
3185
     *
3186
     * @return void
3187
     */
3188 2
    public function initializeObject($obj)
3189
    {
3190 2
        if ($obj instanceof Proxy) {
3191 1
            $obj->__load();
3192
3193 1
            return;
3194
        }
3195
3196 1
        if ($obj instanceof PersistentCollection) {
3197 1
            $obj->initialize();
3198
        }
3199 1
    }
3200
3201
    /**
3202
     * Helper method to show an object as string.
3203
     *
3204
     * @param object $obj
3205
     *
3206
     * @return string
3207
     */
3208 1
    private static function objToStr($obj)
3209
    {
3210 1
        return method_exists($obj, '__toString') ? (string) $obj : get_class($obj).'@'.spl_object_hash($obj);
3211
    }
3212
3213
    /**
3214
     * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit().
3215
     *
3216
     * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information
3217
     * on this object that might be necessary to perform a correct update.
3218
     *
3219
     * @param object $object
3220
     *
3221
     * @return void
3222
     *
3223
     * @throws ORMInvalidArgumentException
3224
     */
3225 6
    public function markReadOnly($object)
3226
    {
3227 6
        if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
3228 1
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3229
        }
3230
3231 5
        $this->readOnlyObjects[spl_object_hash($object)] = true;
3232 5
    }
3233
3234
    /**
3235
     * Is this entity read only?
3236
     *
3237
     * @param object $object
3238
     *
3239
     * @return bool
3240
     *
3241
     * @throws ORMInvalidArgumentException
3242
     */
3243 3
    public function isReadOnly($object)
3244
    {
3245 3
        if ( ! is_object($object)) {
3246
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3247
        }
3248
3249 3
        return isset($this->readOnlyObjects[spl_object_hash($object)]);
3250
    }
3251
3252
    /**
3253
     * Perform whatever processing is encapsulated here after completion of the transaction.
3254
     */
3255 1007
    private function afterTransactionComplete()
3256
    {
3257
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3258 90
            $persister->afterTransactionComplete();
3259 1007
        });
3260 1007
    }
3261
3262
    /**
3263
     * Perform whatever processing is encapsulated here after completion of the rolled-back.
3264
     */
3265
    private function afterTransactionRolledBack()
3266
    {
3267 11
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3268 3
            $persister->afterTransactionRolledBack();
3269 11
        });
3270 11
    }
3271
3272
    /**
3273
     * Performs an action after the transaction.
3274
     *
3275
     * @param callable $callback
3276
     */
3277 1012
    private function performCallbackOnCachedPersister(callable $callback)
3278
    {
3279 1012
        if ( ! $this->hasCache) {
3280 922
            return;
3281
        }
3282
3283 90
        foreach (array_merge($this->persisters, $this->collectionPersisters) as $persister) {
3284 90
            if ($persister instanceof CachedPersister) {
3285 90
                $callback($persister);
3286
            }
3287
        }
3288 90
    }
3289
3290 1016
    private function dispatchOnFlushEvent()
3291
    {
3292 1016
        if ($this->evm->hasListeners(Events::onFlush)) {
3293 4
            $this->evm->dispatchEvent(Events::onFlush, new OnFlushEventArgs($this->em));
3294
        }
3295 1016
    }
3296
3297 1011
    private function dispatchPostFlushEvent()
3298
    {
3299 1011
        if ($this->evm->hasListeners(Events::postFlush)) {
3300 5
            $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
3301
        }
3302 1010
    }
3303
3304 1006
    private function dispatchAfterFlush()
3305
    {
3306 1006
        if($this->evm->hasListeners(Events::afterFlush)) {
3307
            $this->evm->dispatchEvent(Events::afterFlush);
3308
        }
3309 1006
    }
3310
3311
    /**
3312
     * Verifies if two given entities actually are the same based on identifier comparison
3313
     *
3314
     * @param object $entity1
3315
     * @param object $entity2
3316
     *
3317
     * @return bool
3318
     */
3319 14
    private function isIdentifierEquals($entity1, $entity2)
3320
    {
3321 14
        if ($entity1 === $entity2) {
3322
            return true;
3323
        }
3324
3325 14
        $class = $this->em->getClassMetadata(get_class($entity1));
3326
3327 14
        if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
3328 11
            return false;
3329
        }
3330
3331 3
        $oid1 = spl_object_hash($entity1);
3332 3
        $oid2 = spl_object_hash($entity2);
3333
3334 3
        $id1 = isset($this->entityIdentifiers[$oid1])
3335 3
            ? $this->entityIdentifiers[$oid1]
3336 3
            : $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity1));
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
3337 3
        $id2 = isset($this->entityIdentifiers[$oid2])
3338 3
            ? $this->entityIdentifiers[$oid2]
3339 3
            : $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity2));
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
3340
3341 3
        return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
3342
    }
3343
3344
    /**
3345
     * @param object $entity
3346
     * @param object $managedCopy
3347
     *
3348
     * @throws ORMException
3349
     * @throws OptimisticLockException
3350
     * @throws TransactionRequiredException
3351
     */
3352 31
    private function mergeEntityStateIntoManagedCopy($entity, $managedCopy)
3353
    {
3354 31
        $class = $this->em->getClassMetadata(get_class($entity));
3355
3356 31
        foreach ($this->reflectionPropertiesGetter->getProperties($class->name) as $prop) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3367
3368 29
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3369 25
                    $other = $prop->getValue($entity);
3370 25
                    if ($other === null) {
3371 12
                        $prop->setValue($managedCopy, null);
3372
                    } else {
3373 16
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3374
                            // do not merge fields marked lazy that have not been fetched.
3375 4
                            continue;
3376
                        }
3377
3378 12
                        if ( ! $assoc2['isCascadeMerge']) {
3379 6
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3380 3
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3381 3
                                $relatedId   = $targetClass->getIdentifierValues($other);
3382
3383 3
                                if ($targetClass->subClasses) {
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3385
                                } else {
3386 1
                                    $other = $this->em->getProxyFactory()->getProxy(
3387 1
                                        $assoc2['targetEntity'],
3388
                                        $relatedId
3389
                                    );
3390 1
                                    $this->registerManaged($other, $relatedId, array());
3391
                                }
3392
                            }
3393
3394 21
                            $prop->setValue($managedCopy, $other);
3395
                        }
3396
                    }
3397
                } else {
3398 17
                    $mergeCol = $prop->getValue($entity);
3399
3400 17
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3401
                        // do not merge fields marked lazy that have not been fetched.
3402
                        // keep the lazy persistent collection of the managed copy.
3403 5
                        continue;
3404
                    }
3405
3406 14
                    $managedCol = $prop->getValue($managedCopy);
3407
3408 14
                    if ( ! $managedCol) {
3409 4
                        $managedCol = new PersistentCollection(
3410 4
                            $this->em,
3411 4
                            $this->em->getClassMetadata($assoc2['targetEntity']),
0 ignored issues
show
Compatibility introduced by
$this->em->getClassMetad...assoc2['targetEntity']) of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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