Completed
Pull Request — master (#1261)
by Huberty
13:53
created

UnitOfWork::lock()   C

Complexity

Conditions 13
Paths 15

Size

Total Lines 53
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 13.0086
Metric Value
dl 0
loc 53
ccs 26
cts 27
cp 0.963
rs 6.3327
cc 13
eloc 29
nc 15
nop 3
crap 13.0086

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM;
21
22
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
23
use Doctrine\DBAL\LockMode;
24
use Doctrine\ORM\Internal\HydrationCompleteHandler;
25
use Doctrine\ORM\Mapping\Reflection\ReflectionPropertiesGetter;
26
use Exception;
27
use InvalidArgumentException;
28
use UnexpectedValueException;
29
30
use Doctrine\Common\Collections\ArrayCollection;
31
use Doctrine\Common\Collections\Collection;
32
use Doctrine\Common\NotifyPropertyChanged;
33
use Doctrine\Common\PropertyChangedListener;
34
use Doctrine\Common\Persistence\ObjectManagerAware;
35
use Doctrine\ORM\Mapping\ClassMetadata;
36
use Doctrine\ORM\Proxy\Proxy;
37
38
use Doctrine\ORM\Event\LifecycleEventArgs;
39
use Doctrine\ORM\Event\PreUpdateEventArgs;
40
use Doctrine\ORM\Event\PreFlushEventArgs;
41
use Doctrine\ORM\Event\OnFlushEventArgs;
42
use Doctrine\ORM\Event\PostFlushEventArgs;
43
use Doctrine\ORM\Event\ListenersInvoker;
44
45
use Doctrine\ORM\Cache\Persister\CachedPersister;
46
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
47
use Doctrine\ORM\Persisters\Entity\SingleTablePersister;
48
use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
49
use Doctrine\ORM\Persisters\Collection\OneToManyPersister;
50
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
51
use Doctrine\ORM\Utility\IdentifierFlattener;
52
use Doctrine\ORM\Cache\AssociationCacheEntry;
53
54
/**
55
 * The UnitOfWork is responsible for tracking changes to objects during an
56
 * "object-level" transaction and for writing out changes to the database
57
 * in the correct order.
58
 *
59
 * Internal note: This class contains highly performance-sensitive code.
60
 *
61
 * @since       2.0
62
 * @author      Benjamin Eberlei <[email protected]>
63
 * @author      Guilherme Blanco <[email protected]>
64
 * @author      Jonathan Wage <[email protected]>
65
 * @author      Roman Borschel <[email protected]>
66
 * @author      Rob Caiger <[email protected]>
67
 */
68
class UnitOfWork implements PropertyChangedListener
69
{
70
    /**
71
     * An entity is in MANAGED state when its persistence is managed by an EntityManager.
72
     */
73
    const STATE_MANAGED = 1;
74
75
    /**
76
     * An entity is new if it has just been instantiated (i.e. using the "new" operator)
77
     * and is not (yet) managed by an EntityManager.
78
     */
79
    const STATE_NEW = 2;
80
81
    /**
82
     * A detached entity is an instance with persistent state and identity that is not
83
     * (or no longer) associated with an EntityManager (and a UnitOfWork).
84
     */
85
    const STATE_DETACHED = 3;
86
87
    /**
88
     * A removed entity instance is an instance with a persistent identity,
89
     * associated with an EntityManager, whose persistent state will be deleted
90
     * on commit.
91
     */
92
    const STATE_REMOVED = 4;
93
94
    /**
95
     * Hint used to collect all primary keys of associated entities during hydration
96
     * and execute it in a dedicated query afterwards
97
     * @see https://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html?highlight=eager#temporarily-change-fetch-mode-in-dql
98
     */
99
    const HINT_DEFEREAGERLOAD = 'deferEagerLoad';
100
101
    /**
102
     * The identity map that holds references to all managed entities that have
103
     * an identity. The entities are grouped by their class name.
104
     * Since all classes in a hierarchy must share the same identifier set,
105
     * we always take the root class name of the hierarchy.
106
     *
107
     * @var array
108
     */
109
    private $identityMap = array();
110
111
    /**
112
     * Map of all identifiers of managed entities.
113
     * Keys are object ids (spl_object_hash).
114
     *
115
     * @var array
116
     */
117
    private $entityIdentifiers = array();
118
119
    /**
120
     * Map of the original entity data of managed entities.
121
     * Keys are object ids (spl_object_hash). This is used for calculating changesets
122
     * at commit time.
123
     *
124
     * Internal note: Note that PHPs "copy-on-write" behavior helps a lot with memory usage.
125
     *                A value will only really be copied if the value in the entity is modified
126
     *                by the user.
127
     *
128
     * @var array
129
     */
130
    private $originalEntityData = array();
131
132
    /**
133
     * Map of entity changes. Keys are object ids (spl_object_hash).
134
     * Filled at the beginning of a commit of the UnitOfWork and cleaned at the end.
135
     *
136
     * @var array
137
     */
138
    private $entityChangeSets = array();
139
140
    /**
141
     * The (cached) states of any known entities.
142
     * Keys are object ids (spl_object_hash).
143
     *
144
     * @var array
145
     */
146
    private $entityStates = array();
147
148
    /**
149
     * Map of entities that are scheduled for dirty checking at commit time.
150
     * This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT.
151
     * Keys are object ids (spl_object_hash).
152
     *
153
     * @var array
154
     */
155
    private $scheduledForSynchronization = array();
156
157
    /**
158
     * A list of all pending entity insertions.
159
     *
160
     * @var array
161
     */
162
    private $entityInsertions = array();
163
164
    /**
165
     * A list of all pending entity updates.
166
     *
167
     * @var array
168
     */
169
    private $entityUpdates = array();
170
171
    /**
172
     * Any pending extra updates that have been scheduled by persisters.
173
     *
174
     * @var array
175
     */
176
    private $extraUpdates = array();
177
178
    /**
179
     * A list of all pending entity deletions.
180
     *
181
     * @var array
182
     */
183
    private $entityDeletions = array();
184
185
    /**
186
     * All pending collection deletions.
187
     *
188
     * @var array
189
     */
190
    private $collectionDeletions = array();
191
192
    /**
193
     * All pending collection updates.
194
     *
195
     * @var array
196
     */
197
    private $collectionUpdates = array();
198
199
    /**
200
     * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork.
201
     * At the end of the UnitOfWork all these collections will make new snapshots
202
     * of their data.
203
     *
204
     * @var array
205
     */
206
    private $visitedCollections = array();
207
208
    /**
209
     * The EntityManager that "owns" this UnitOfWork instance.
210
     *
211
     * @var EntityManagerInterface
212
     */
213
    private $em;
214
215
    /**
216
     * The entity persister instances used to persist entity instances.
217
     *
218
     * @var array
219
     */
220
    private $persisters = array();
221
222
    /**
223
     * The collection persister instances used to persist collections.
224
     *
225
     * @var array
226
     */
227
    private $collectionPersisters = array();
228
229
    /**
230
     * The EventManager used for dispatching events.
231
     *
232
     * @var \Doctrine\Common\EventManager
233
     */
234
    private $evm;
235
236
    /**
237
     * The ListenersInvoker used for dispatching events.
238
     *
239
     * @var \Doctrine\ORM\Event\ListenersInvoker
240
     */
241
    private $listenersInvoker;
242
243
    /**
244
     * The IdentifierFlattener used for manipulating identifiers
245
     *
246
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
247
     */
248
    private $identifierFlattener;
249
250
    /**
251
     * Orphaned entities that are scheduled for removal.
252
     *
253
     * @var array
254
     */
255
    private $orphanRemovals = array();
256
257
    /**
258
     * Read-Only objects are never evaluated
259
     *
260
     * @var array
261
     */
262
    private $readOnlyObjects = array();
263
264
    /**
265
     * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
266
     *
267
     * @var array
268
     */
269
    private $eagerLoadingEntities = array();
270
271
    /**
272
     * @var boolean
273
     */
274
    protected $hasCache = false;
275
276
    /**
277
     * Helper for handling completion of hydration
278
     *
279
     * @var HydrationCompleteHandler
280
     */
281
    private $hydrationCompleteHandler;
282
283
    /**
284
     * @var ReflectionPropertiesGetter
285
     */
286
    private $reflectionPropertiesGetter;
287
288
    /**
289
     * Initializes a new UnitOfWork instance, bound to the given EntityManager.
290
     *
291
     * @param EntityManagerInterface $em
292
     */
293 2313
    public function __construct(EntityManagerInterface $em)
294
    {
295 2313
        $this->em                         = $em;
296 2313
        $this->evm                        = $em->getEventManager();
297 2313
        $this->listenersInvoker           = new ListenersInvoker($em);
298 2313
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
299 2313
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
300 2313
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
301 2313
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
302 2313
    }
303
304
    /**
305
     * Commits the UnitOfWork, executing all operations that have been postponed
306
     * up to this point. The state of all managed entities will be synchronized with
307
     * the database.
308
     *
309
     * The operations are executed in the following order:
310
     *
311
     * 1) All entity insertions
312
     * 2) All entity updates
313
     * 3) All collection deletions
314
     * 4) All collection updates
315
     * 5) All entity deletions
316
     *
317
     * @param null|object|array $entity
318
     *
319
     * @return void
320
     *
321
     * @throws \Exception
322
     */
323 1006
    public function commit($entity = null)
324
    {
325
        // Raise preFlush
326 1006
        if ($this->evm->hasListeners(Events::preFlush)) {
327 2
            $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em));
328
        }
329
330
        // Compute changes done since last commit.
331 1006
        if (null === $entity) {
332 998
            $this->computeChangeSets();
333 17
        } elseif (is_object($entity)) {
334 16
            $this->computeSingleEntityChangeSet($entity);
335 2
        } elseif (is_array($entity)) {
336 2
            foreach ($entity as $object) {
337 2
                $this->computeSingleEntityChangeSet($object);
338
            }
339
        }
340
341 1003
        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...
342 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...
343 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...
344 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...
345 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...
346 1003
                $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...
347 25
            $this->dispatchOnFlushEvent();
348 25
            $this->dispatchPostFlushEvent();
349
350 25
            return; // Nothing to do.
351
        }
352
353 999
        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...
354 16
            foreach ($this->orphanRemovals as $orphan) {
355 16
                $this->remove($orphan);
356
            }
357
        }
358
359 999
        $this->dispatchOnFlushEvent();
360
361
        // Now we need a commit order to maintain referential integrity
362 999
        $commitOrder = $this->getCommitOrder();
363
364 999
        $conn = $this->em->getConnection();
365 999
        $conn->beginTransaction();
366
367
        try {
368
            // Collection deletions (deletions of complete collections)
369 999
            foreach ($this->collectionDeletions as $collectionToDelete) {
370 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
371
            }
372
373 999
            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...
374 995
                foreach ($commitOrder as $class) {
375 995
                    $this->executeInserts($class);
376
                }
377
            }
378
379 998
            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...
380 115
                foreach ($commitOrder as $class) {
381 115
                    $this->executeUpdates($class);
382
                }
383
            }
384
385
            // Extra updates that were requested by persisters.
386 994
            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...
387 40
                $this->executeExtraUpdates();
388
            }
389
390
            // Collection updates (deleteRows, updateRows, insertRows)
391 994
            foreach ($this->collectionUpdates as $collectionToUpdate) {
392 523
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
393
            }
394
395
            // Entity deletions come last and need to be in reverse commit order
396 994
            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...
397 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...
398 63
                    $this->executeDeletions($commitOrder[$i]);
399
                }
400
            }
401
402 994
            $conn->commit();
403 11
        } catch (Exception $e) {
404 11
            $this->em->close();
405 11
            $conn->rollBack();
406
407 11
            $this->afterTransactionRolledBack();
408
409 11
            throw $e;
410
        }
411
412 994
        $this->afterTransactionComplete();
413
414
        // Take new snapshots from visited collections
415 994
        foreach ($this->visitedCollections as $coll) {
416 522
            $coll->takeSnapshot();
417
        }
418
419 994
        $this->dispatchPostFlushEvent();
420
421 993
        $this->postCommitClear($entity);
422 993
    }
423
424
    /**
425
     * @param null|object|array $entity
426
     */
427 993
    private function postCommitClear($entity = null)
428
    {
429
430
        // Clear up
431 993
        $this->entityInsertions =
432 993
        $this->entityUpdates =
433 993
        $this->entityDeletions =
434 993
        $this->extraUpdates =
435 993
        $this->collectionUpdates =
436 993
        $this->collectionDeletions =
437 993
        $this->visitedCollections =
438 993
        $this->orphanRemovals = array();
439
440 993
        if (null === $entity) {
441 986
            $this->entityChangeSets = $this->scheduledForSynchronization = array();
442 986
            return;
443
        }
444
445 14
        if (is_object($entity)) {
446 13
            $entity = [$entity];
447
        }
448
449 14
        foreach ($entity as $object) {
450 14
            $oid = spl_object_hash($object);
451 14
            $class = $this->em->getClassMetadata(get_class($object));
452 14
            $this->clearEntityChangeSet($oid);
453 14
            $this->clearScheduledForSynchronization($class, $oid);
454
        }
455 14
    }
456
457
    /**
458
     * Computes the changesets of all entities scheduled for insertion.
459
     *
460
     * @return void
461
     */
462 1005
    private function computeScheduleInsertsChangeSets()
463
    {
464 1005
        foreach ($this->entityInsertions as $entity) {
465 997
            $class = $this->em->getClassMetadata(get_class($entity));
466
467 997
            $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...
468
        }
469 1003
    }
470
471
    /**
472
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
473
     *
474
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
475
     * 2. Read Only entities are skipped.
476
     * 3. Proxies are skipped.
477
     * 4. Only if entity is properly managed.
478
     *
479
     * @param object $entity
480
     *
481
     * @return void
482
     *
483
     * @throws \InvalidArgumentException
484
     */
485 17
    private function computeSingleEntityChangeSet($entity)
486
    {
487 17
        $state = $this->getEntityState($entity);
488
489 17
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
490 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
491
        }
492
493 16
        $class = $this->em->getClassMetadata(get_class($entity));
494
495 16
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
496 15
            $this->persist($entity);
497
        }
498
499
        // Compute changes for INSERTed entities first. This must always happen even in this case.
500 16
        $this->computeScheduleInsertsChangeSets();
501
502 16
        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...
503
            return;
504
        }
505
506
        // Ignore uninitialized proxy objects
507 16
        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...
508 2
            return;
509
        }
510
511
        // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
512 14
        $oid = spl_object_hash($entity);
513
514 14
        if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
515 7
            $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...
516
        }
517 13
    }
518
519
    /**
520
     * Executes any extra updates that have been scheduled.
521
     */
522 40
    private function executeExtraUpdates()
523
    {
524 40
        foreach ($this->extraUpdates as $oid => $update) {
525 40
            list ($entity, $changeset) = $update;
526
527 40
            $this->entityChangeSets[$oid] = $changeset;
528 40
            $this->getEntityPersister(get_class($entity))->update($entity);
529
        }
530
531 40
        $this->extraUpdates = array();
532 40
    }
533
534
    /**
535
     * Gets the changeset for an entity.
536
     *
537
     * @param object $entity
538
     *
539
     * @return array
540
     */
541 997
    public function getEntityChangeSet($entity)
542
    {
543 997
        $oid = spl_object_hash($entity);
544
545 997
        if (isset($this->entityChangeSets[$oid])) {
546 997
            return $this->entityChangeSets[$oid];
547
        }
548
549 1
        return array();
550
    }
551
552
    /**
553
     * Computes the changes that happened to a single entity.
554
     *
555
     * Modifies/populates the following properties:
556
     *
557
     * {@link _originalEntityData}
558
     * If the entity is NEW or MANAGED but not yet fully persisted (only has an id)
559
     * then it was not fetched from the database and therefore we have no original
560
     * entity data yet. All of the current entity data is stored as the original entity data.
561
     *
562
     * {@link _entityChangeSets}
563
     * The changes detected on all properties of the entity are stored there.
564
     * A change is a tuple array where the first entry is the old value and the second
565
     * entry is the new value of the property. Changesets are used by persisters
566
     * to INSERT/UPDATE the persistent entity state.
567
     *
568
     * {@link _entityUpdates}
569
     * If the entity is already fully MANAGED (has been fetched from the database before)
570
     * and any changes to its properties are detected, then a reference to the entity is stored
571
     * there to mark it for an update.
572
     *
573
     * {@link _collectionDeletions}
574
     * If a PersistentCollection has been de-referenced in a fully MANAGED entity,
575
     * then this collection is marked for deletion.
576
     *
577
     * @ignore
578
     *
579
     * @internal Don't call from the outside.
580
     *
581
     * @param ClassMetadata $class  The class descriptor of the entity.
582
     * @param object        $entity The entity for which to compute the changes.
583
     *
584
     * @return void
585
     */
586 1007
    public function computeChangeSet(ClassMetadata $class, $entity)
587
    {
588 1007
        $oid = spl_object_hash($entity);
589
590 1007
        if (isset($this->readOnlyObjects[$oid])) {
591 2
            return;
592
        }
593
594 1007
        if ( ! $class->isInheritanceTypeNone()) {
595 305
            $class = $this->em->getClassMetadata(get_class($entity));
596
        }
597
598 1007
        $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...
599
600 1007
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
601 136
            $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...
602
        }
603
604 1007
        $actualData = array();
605
606 1007
        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...
607 1007
            $value = $refProp->getValue($entity);
608
609 1007
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
610 769
                if ($value instanceof PersistentCollection) {
611 197
                    if ($value->getOwner() === $entity) {
612 197
                        continue;
613
                    }
614
615 5
                    $value = new ArrayCollection($value->getValues());
616
                }
617
618
                // If $value is not a Collection then use an ArrayCollection.
619 764
                if ( ! $value instanceof Collection) {
620 236
                    $value = new ArrayCollection($value);
621
                }
622
623 764
                $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...
624
625
                // Inject PersistentCollection
626 764
                $value = new PersistentCollection(
627 764
                    $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...
628
                );
629 764
                $value->setOwner($entity, $assoc);
630 764
                $value->setDirty( ! $value->isEmpty());
631
632 764
                $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...
633
634 764
                $actualData[$name] = $value;
635
636 764
                continue;
637
            }
638
639 1007
            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...
640 1007
                $actualData[$name] = $value;
641
            }
642
        }
643
644 1007
        if ( ! isset($this->originalEntityData[$oid])) {
645
            // Entity is either NEW or MANAGED but not yet fully persisted (only has an id).
646
            // These result in an INSERT.
647 1003
            $this->originalEntityData[$oid] = $actualData;
648 1003
            $changeSet = array();
649
650 1003
            foreach ($actualData as $propName => $actualValue) {
651 988
                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...
652 937
                    $changeSet[$propName] = array(null, $actualValue);
653
654 937
                    continue;
655
                }
656
657 886
                $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...
658
659 886
                if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
660 886
                    $changeSet[$propName] = array(null, $actualValue);
661
                }
662
            }
663
664 1003
            $this->entityChangeSets[$oid] = $changeSet;
665
        } else {
666
            // Entity is "fully" MANAGED: it was already fully persisted before
667
            // and we have a copy of the original data
668 261
            $originalData           = $this->originalEntityData[$oid];
669 261
            $isChangeTrackingNotify = $class->isChangeTrackingNotify();
670 261
            $changeSet              = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid]))
671
                ? $this->entityChangeSets[$oid]
672 261
                : array();
673
674 261
            foreach ($actualData as $propName => $actualValue) {
675
                // skip field, its a partially omitted one!
676 246
                if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) {
677 8
                    continue;
678
                }
679
680 246
                $orgValue = $originalData[$propName];
681
682
                // skip if value haven't changed
683 246
                if ($orgValue === $actualValue) {
684 230
                    continue;
685
                }
686
687
                // if regular field
688 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...
689 58
                    if ($isChangeTrackingNotify) {
690
                        continue;
691
                    }
692
693 58
                    $changeSet[$propName] = array($orgValue, $actualValue);
694
695 58
                    continue;
696
                }
697
698 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...
699
700
                // Persistent collection was exchanged with the "originally"
701
                // created one. This can only mean it was cloned and replaced
702
                // on another entity.
703 58
                if ($actualValue instanceof PersistentCollection) {
704 8
                    $owner = $actualValue->getOwner();
705 8
                    if ($owner === null) { // cloned
706
                        $actualValue->setOwner($entity, $assoc);
707 8
                    } else if ($owner !== $entity) { // no clone, we have to fix
708
                        if (!$actualValue->isInitialized()) {
709
                            $actualValue->initialize(); // we have to do this otherwise the cols share state
710
                        }
711
                        $newValue = clone $actualValue;
712
                        $newValue->setOwner($entity, $assoc);
713
                        $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...
714
                    }
715
                }
716
717 58
                if ($orgValue instanceof PersistentCollection) {
718
                    // A PersistentCollection was de-referenced, so delete it.
719 8
                    $coid = spl_object_hash($orgValue);
720
721 8
                    if (isset($this->collectionDeletions[$coid])) {
722
                        continue;
723
                    }
724
725 8
                    $this->collectionDeletions[$coid] = $orgValue;
726 8
                    $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored.
727
728 8
                    continue;
729
                }
730
731 50
                if ($assoc['type'] & ClassMetadata::TO_ONE) {
732 49
                    if ($assoc['isOwningSide']) {
733 21
                        $changeSet[$propName] = array($orgValue, $actualValue);
734
                    }
735
736 49
                    if ($orgValue !== null && $assoc['orphanRemoval']) {
737 50
                        $this->scheduleOrphanRemoval($orgValue);
738
                    }
739
                }
740
            }
741
742 261
            if ($changeSet) {
743 85
                $this->entityChangeSets[$oid]   = $changeSet;
744 85
                $this->originalEntityData[$oid] = $actualData;
745 85
                $this->entityUpdates[$oid]      = $entity;
746
            }
747
        }
748
749
        // Look for changes in associations of the entity
750 1007
        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...
751 886
            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...
752 632
                continue;
753
            }
754
755 857
            $this->computeAssociationChanges($assoc, $val);
756
757 849
            if ( ! isset($this->entityChangeSets[$oid]) &&
758 849
                $assoc['isOwningSide'] &&
759 849
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
760 849
                $val instanceof PersistentCollection &&
761 849
                $val->isDirty()) {
762
763 34
                $this->entityChangeSets[$oid]   = array();
764 34
                $this->originalEntityData[$oid] = $actualData;
765 849
                $this->entityUpdates[$oid]      = $entity;
766
            }
767
        }
768 999
    }
769
770
    /**
771
     * Computes all the changes that have been done to entities and collections
772
     * since the last commit and stores these changes in the _entityChangeSet map
773
     * temporarily for access by the persisters, until the UoW commit is finished.
774
     *
775
     * @return void
776
     */
777 998
    public function computeChangeSets()
778
    {
779
        // Compute changes for INSERTed entities first. This must always happen.
780 998
        $this->computeScheduleInsertsChangeSets();
781
782
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
783 996
        foreach ($this->identityMap as $className => $entities) {
784 444
            $class = $this->em->getClassMetadata($className);
785
786
            // Skip class if instances are read-only
787 444
            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...
788 1
                continue;
789
            }
790
791
            // If change tracking is explicit or happens through notification, then only compute
792
            // changes on entities of that type that are explicitly marked for synchronization.
793
            switch (true) {
794 443
                case ($class->isChangeTrackingDeferredImplicit()):
795 441
                    $entitiesToProcess = $entities;
796 441
                    break;
797
798 3
                case (isset($this->scheduledForSynchronization[$className])):
799 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
800 3
                    break;
801
802
                default:
803 1
                    $entitiesToProcess = array();
804
805
            }
806
807 443
            foreach ($entitiesToProcess as $entity) {
808
                // Ignore uninitialized proxy objects
809 423
                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...
810 34
                    continue;
811
                }
812
813
                // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
814 422
                $oid = spl_object_hash($entity);
815
816 422
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
817 443
                    $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...
818
                }
819
            }
820
        }
821 996
    }
822
823
    /**
824
     * Computes the changes of an association.
825
     *
826
     * @param array $assoc The association mapping.
827
     * @param mixed $value The value of the association.
828
     *
829
     * @throws ORMInvalidArgumentException
830
     * @throws ORMException
831
     *
832
     * @return void
833
     */
834 857
    private function computeAssociationChanges($assoc, $value)
835
    {
836 857
        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...
837 27
            return;
838
        }
839
840 856
        if ($value instanceof PersistentCollection && $value->isDirty()) {
841 525
            $coid = spl_object_hash($value);
842
843 525
            $this->collectionUpdates[$coid] = $value;
844 525
            $this->visitedCollections[$coid] = $value;
845
        }
846
847
        // Look through the entities, and in any of their associations,
848
        // for transient (new) entities, recursively. ("Persistence by reachability")
849
        // Unwrap. Uninitialized collections will simply be empty.
850 856
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
851 856
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
852
853 856
        foreach ($unwrappedValue as $key => $entry) {
854 714
            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...
855 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...
856
            }
857
858 708
            $state = $this->getEntityState($entry, self::STATE_NEW);
859
860 708
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
861
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
862
            }
863
864
            switch ($state) {
865 708
                case self::STATE_NEW:
866 39
                    if ( ! $assoc['isCascadePersist']) {
867 4
                        throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
868
                    }
869
870 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...
871 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...
872 35
                    break;
873
874 702
                case self::STATE_REMOVED:
875
                    // Consume the $value as array (it's either an array or an ArrayAccess)
876
                    // and remove the element from Collection.
877 4
                    if ($assoc['type'] & ClassMetadata::TO_MANY) {
878 3
                        unset($value[$key]);
879
                    }
880 4
                    break;
881
882 702
                case self::STATE_DETACHED:
883
                    // Can actually not happen right now as we assume STATE_NEW,
884
                    // so the exception will be raised from the DBAL layer (constraint violation).
885
                    throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
886
                    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...
887
888 705
                default:
889
                    // MANAGED associated entities are already taken into account
890
                    // during changeset calculation anyway, since they are in the identity map.
891
            }
892
        }
893 848
    }
894
895
    /**
896
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
897
     * @param object                              $entity
898
     *
899
     * @return void
900
     */
901 1015
    private function persistNew($class, $entity)
902
    {
903 1015
        $oid    = spl_object_hash($entity);
904 1015
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
905
906 1015
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
907 138
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
908
        }
909
910 1015
        $idGen = $class->idGenerator;
911
912 1015
        if ( ! $idGen->isPostInsertGenerator()) {
913 260
            $idValue = $idGen->generate($this->em, $entity);
0 ignored issues
show
Compatibility introduced by
$this->em of type object<Doctrine\ORM\EntityManagerInterface> is not a sub-type of object<Doctrine\ORM\EntityManager>. It seems like you assume a concrete implementation of the interface Doctrine\ORM\EntityManagerInterface to be always present.

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

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

Loading history...
914
915 260
            if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
916 1
                $idValue = array($class->identifier[0] => $idValue);
917
918 1
                $class->setIdentifierValues($entity, $idValue);
919
            }
920
921 260
            $this->entityIdentifiers[$oid] = $idValue;
922
        }
923
924 1015
        $this->entityStates[$oid] = self::STATE_MANAGED;
925
926 1015
        $this->scheduleForInsert($entity);
927 1015
    }
928
929
    /**
930
     * INTERNAL:
931
     * Computes the changeset of an individual entity, independently of the
932
     * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
933
     *
934
     * The passed entity must be a managed entity. If the entity already has a change set
935
     * because this method is invoked during a commit cycle then the change sets are added.
936
     * whereby changes detected in this method prevail.
937
     *
938
     * @ignore
939
     *
940
     * @param ClassMetadata $class  The class descriptor of the entity.
941
     * @param object        $entity The entity for which to (re)calculate the change set.
942
     *
943
     * @return void
944
     *
945
     * @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
946
     */
947 16
    public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
948
    {
949 16
        $oid = spl_object_hash($entity);
950
951 16
        if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
952
            throw ORMInvalidArgumentException::entityNotManaged($entity);
953
        }
954
955
        // skip if change tracking is "NOTIFY"
956 16
        if ($class->isChangeTrackingNotify()) {
957
            return;
958
        }
959
960 16
        if ( ! $class->isInheritanceTypeNone()) {
961 3
            $class = $this->em->getClassMetadata(get_class($entity));
962
        }
963
964 16
        $actualData = array();
965
966 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...
967 16
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
968 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...
969 16
                && ! $class->isCollectionValuedAssociation($name)) {
970 16
                $actualData[$name] = $refProp->getValue($entity);
971
            }
972
        }
973
974 16
        if ( ! isset($this->originalEntityData[$oid])) {
975
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
976
        }
977
978 16
        $originalData = $this->originalEntityData[$oid];
979 16
        $changeSet = array();
980
981 16
        foreach ($actualData as $propName => $actualValue) {
982 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
983
984 16
            if ($orgValue !== $actualValue) {
985 16
                $changeSet[$propName] = array($orgValue, $actualValue);
986
            }
987
        }
988
989 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...
990 7
            if (isset($this->entityChangeSets[$oid])) {
991 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
992 1
            } else if ( ! isset($this->entityInsertions[$oid])) {
993 1
                $this->entityChangeSets[$oid] = $changeSet;
994 1
                $this->entityUpdates[$oid]    = $entity;
995
            }
996 7
            $this->originalEntityData[$oid] = $actualData;
997
        }
998 16
    }
999
1000
    /**
1001
     * Executes all entity insertions for entities of the specified type.
1002
     *
1003
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1004
     *
1005
     * @return void
1006
     */
1007 995
    private function executeInserts($class)
1008
    {
1009 995
        $entities   = array();
1010 995
        $className  = $class->name;
1011 995
        $persister  = $this->getEntityPersister($className);
1012 995
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
1013
1014 995
        foreach ($this->entityInsertions as $oid => $entity) {
1015
1016 995
            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...
1017 847
                continue;
1018
            }
1019
1020 995
            $persister->addInsert($entity);
1021
1022 995
            unset($this->entityInsertions[$oid]);
1023
1024 995
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1025 995
                $entities[] = $entity;
1026
            }
1027
        }
1028
1029 995
        $postInsertIds = $persister->executeInserts();
1030
1031 995
        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...
1032
            // Persister returned post-insert IDs
1033 912
            foreach ($postInsertIds as $postInsertId) {
1034 912
                $id      = $postInsertId['generatedId'];
1035 912
                $entity  = $postInsertId['entity'];
1036 912
                $oid     = spl_object_hash($entity);
1037 912
                $idField = $class->identifier[0];
1038
1039 912
                $class->reflFields[$idField]->setValue($entity, $id);
1040
1041 912
                $this->entityIdentifiers[$oid] = array($idField => $id);
1042 912
                $this->entityStates[$oid] = self::STATE_MANAGED;
1043 912
                $this->originalEntityData[$oid][$idField] = $id;
1044
1045 912
                $this->addToIdentityMap($entity);
1046
            }
1047
        }
1048
1049 995
        foreach ($entities as $entity) {
1050 134
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1051
        }
1052 995
    }
1053
1054
    /**
1055
     * Executes all entity updates for entities of the specified type.
1056
     *
1057
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1058
     *
1059
     * @return void
1060
     */
1061 115
    private function executeUpdates($class)
1062
    {
1063 115
        $className          = $class->name;
1064 115
        $persister          = $this->getEntityPersister($className);
1065 115
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1066 115
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1067
1068 115
        foreach ($this->entityUpdates as $oid => $entity) {
1069
1070 115
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1071 73
                continue;
1072
            }
1073
1074 115
            if ($preUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1075 13
                $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->entityChangeSets[$oid]), $preUpdateInvoke);
1076 13
                $this->recomputeSingleEntityChangeSet($class, $entity);
1077
            }
1078
1079 115
            if ( ! empty($this->entityChangeSets[$oid])) {
1080 82
                $persister->update($entity);
1081
            }
1082
1083 111
            unset($this->entityUpdates[$oid]);
1084
1085 111
            if ($postUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1086 111
                $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new LifecycleEventArgs($entity, $this->em), $postUpdateInvoke);
1087
            }
1088
        }
1089 111
    }
1090
1091
    /**
1092
     * Executes all entity deletions for entities of the specified type.
1093
     *
1094
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1095
     *
1096
     * @return void
1097
     */
1098 63
    private function executeDeletions($class)
1099
    {
1100 63
        $className  = $class->name;
1101 63
        $persister  = $this->getEntityPersister($className);
1102 63
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove);
1103
1104 63
        foreach ($this->entityDeletions as $oid => $entity) {
1105 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...
1106 26
                continue;
1107
            }
1108
1109 63
            $persister->delete($entity);
1110
1111
            unset(
1112 63
                $this->entityDeletions[$oid],
1113 63
                $this->entityIdentifiers[$oid],
1114 63
                $this->originalEntityData[$oid],
1115 63
                $this->entityStates[$oid]
1116
            );
1117
1118
            // Entity with this $oid after deletion treated as NEW, even if the $oid
1119
            // is obtained by a new entity because the old one went out of scope.
1120
            //$this->entityStates[$oid] = self::STATE_NEW;
1121 63
            if ( ! $class->isIdentifierNatural()) {
1122 53
                $class->reflFields[$class->identifier[0]]->setValue($entity, null);
1123
            }
1124
1125 63
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1126 63
                $this->listenersInvoker->invoke($class, Events::postRemove, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1127
            }
1128
        }
1129 62
    }
1130
1131
    /**
1132
     * Gets the commit order.
1133
     *
1134
     * @param array|null $entityChangeSet
1135
     *
1136
     * @return array
1137
     */
1138 999
    private function getCommitOrder(array $entityChangeSet = null)
1139
    {
1140 999
        if ($entityChangeSet === null) {
1141 999
            $entityChangeSet = array_merge($this->entityInsertions, $this->entityUpdates, $this->entityDeletions);
1142
        }
1143
1144 999
        $calc = $this->getCommitOrderCalculator();
1145
1146
        // See if there are any new classes in the changeset, that are not in the
1147
        // commit order graph yet (don't have a node).
1148
        // We have to inspect changeSet to be able to correctly build dependencies.
1149
        // It is not possible to use IdentityMap here because post inserted ids
1150
        // are not yet available.
1151 999
        $newNodes = array();
1152
1153 999
        foreach ($entityChangeSet as $entity) {
1154 999
            $class = $this->em->getClassMetadata(get_class($entity));
1155
1156 999
            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...
1157 618
                continue;
1158
            }
1159
1160 999
            $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...
1161
1162 999
            $newNodes[] = $class;
1163
        }
1164
1165
        // Calculate dependencies for new nodes
1166 999
        while ($class = array_pop($newNodes)) {
1167 999
            foreach ($class->associationMappings as $assoc) {
1168 878
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1169 838
                    continue;
1170
                }
1171
1172 831
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1173
1174 831
                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...
1175 642
                    $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...
1176
1177 642
                    $newNodes[] = $targetClass;
1178
                }
1179
1180 831
                $joinColumns = reset($assoc['joinColumns']);
1181 831
                $isNullable  = isset($joinColumns['nullable']) ? $joinColumns['nullable'] : false;
1182
1183 831
                $calc->addDependency($targetClass->name, $class->name, $isNullable ? 0 : 1);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1187 824
                    continue;
1188
                }
1189
1190 216
                foreach ($targetClass->subClasses as $subClassName) {
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1191 216
                    $targetSubClass = $this->em->getClassMetadata($subClassName);
1192
1193 216
                    if ( ! $calc->hasNode($subClassName)) {
1194 189
                        $calc->addNode($targetSubClass->name, $targetSubClass);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1195
1196 189
                        $newNodes[] = $targetSubClass;
1197
                    }
1198
1199 216
                    $calc->addDependency($targetSubClass->name, $class->name, 1);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1200
                }
1201
            }
1202
        }
1203
1204 999
        return $calc->sort();
1205
    }
1206
1207
    /**
1208
     * Schedules an entity for insertion into the database.
1209
     * If the entity already has an identifier, it will be added to the identity map.
1210
     *
1211
     * @param object $entity The entity to schedule for insertion.
1212
     *
1213
     * @return void
1214
     *
1215
     * @throws ORMInvalidArgumentException
1216
     * @throws \InvalidArgumentException
1217
     */
1218 1016
    public function scheduleForInsert($entity)
1219
    {
1220 1016
        $oid = spl_object_hash($entity);
1221
1222 1016
        if (isset($this->entityUpdates[$oid])) {
1223
            throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion.");
1224
        }
1225
1226 1016
        if (isset($this->entityDeletions[$oid])) {
1227 1
            throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
1228
        }
1229 1016
        if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) {
1230 1
            throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
1231
        }
1232
1233 1016
        if (isset($this->entityInsertions[$oid])) {
1234 1
            throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
1235
        }
1236
1237 1016
        $this->entityInsertions[$oid] = $entity;
1238
1239 1016
        if (isset($this->entityIdentifiers[$oid])) {
1240 260
            $this->addToIdentityMap($entity);
1241
        }
1242
1243 1016
        if ($entity instanceof NotifyPropertyChanged) {
1244 5
            $entity->addPropertyChangedListener($this);
1245
        }
1246 1016
    }
1247
1248
    /**
1249
     * Checks whether an entity is scheduled for insertion.
1250
     *
1251
     * @param object $entity
1252
     *
1253
     * @return boolean
1254
     */
1255 628
    public function isScheduledForInsert($entity)
1256
    {
1257 628
        return isset($this->entityInsertions[spl_object_hash($entity)]);
1258
    }
1259
1260
    /**
1261
     * Schedules an entity for being updated.
1262
     *
1263
     * @param object $entity The entity to schedule for being updated.
1264
     *
1265
     * @return void
1266
     *
1267
     * @throws ORMInvalidArgumentException
1268
     */
1269 1
    public function scheduleForUpdate($entity)
1270
    {
1271 1
        $oid = spl_object_hash($entity);
1272
1273 1
        if ( ! isset($this->entityIdentifiers[$oid])) {
1274
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update");
1275
        }
1276
1277 1
        if (isset($this->entityDeletions[$oid])) {
1278
            throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update");
1279
        }
1280
1281 1
        if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) {
1282 1
            $this->entityUpdates[$oid] = $entity;
1283
        }
1284 1
    }
1285
1286
    /**
1287
     * INTERNAL:
1288
     * Schedules an extra update that will be executed immediately after the
1289
     * regular entity updates within the currently running commit cycle.
1290
     *
1291
     * Extra updates for entities are stored as (entity, changeset) tuples.
1292
     *
1293
     * @ignore
1294
     *
1295
     * @param object $entity    The entity for which to schedule an extra update.
1296
     * @param array  $changeset The changeset of the entity (what to update).
1297
     *
1298
     * @return void
1299
     */
1300 40
    public function scheduleExtraUpdate($entity, array $changeset)
1301
    {
1302 40
        $oid         = spl_object_hash($entity);
1303 40
        $extraUpdate = array($entity, $changeset);
1304
1305 40
        if (isset($this->extraUpdates[$oid])) {
1306 1
            list($ignored, $changeset2) = $this->extraUpdates[$oid];
0 ignored issues
show
Unused Code introduced by
The assignment to $ignored is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1307
1308 1
            $extraUpdate = array($entity, $changeset + $changeset2);
1309
        }
1310
1311 40
        $this->extraUpdates[$oid] = $extraUpdate;
1312 40
    }
1313
1314
    /**
1315
     * Checks whether an entity is registered as dirty in the unit of work.
1316
     * Note: Is not very useful currently as dirty entities are only registered
1317
     * at commit time.
1318
     *
1319
     * @param object $entity
1320
     *
1321
     * @return boolean
1322
     */
1323
    public function isScheduledForUpdate($entity)
1324
    {
1325
        return isset($this->entityUpdates[spl_object_hash($entity)]);
1326
    }
1327
1328
    /**
1329
     * Checks whether an entity is registered to be checked in the unit of work.
1330
     *
1331
     * @param object $entity
1332
     *
1333
     * @return boolean
1334
     */
1335 1
    public function isScheduledForDirtyCheck($entity)
1336
    {
1337 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...
1338
1339 1
        return isset($this->scheduledForSynchronization[$rootEntityName][spl_object_hash($entity)]);
1340
    }
1341
1342
    /**
1343
     * INTERNAL:
1344
     * Schedules an entity for deletion.
1345
     *
1346
     * @param object $entity
1347
     *
1348
     * @return void
1349
     */
1350 66
    public function scheduleForDelete($entity)
1351
    {
1352 66
        $oid = spl_object_hash($entity);
1353
1354 66
        if (isset($this->entityInsertions[$oid])) {
1355 1
            if ($this->isInIdentityMap($entity)) {
1356
                $this->removeFromIdentityMap($entity);
1357
            }
1358
1359 1
            unset($this->entityInsertions[$oid], $this->entityStates[$oid]);
1360
1361 1
            return; // entity has not been persisted yet, so nothing more to do.
1362
        }
1363
1364 66
        if ( ! $this->isInIdentityMap($entity)) {
1365 1
            return;
1366
        }
1367
1368 65
        $this->removeFromIdentityMap($entity);
1369
1370 65
        if (isset($this->entityUpdates[$oid])) {
1371 2
            unset($this->entityUpdates[$oid]);
1372
        }
1373
1374 65
        if ( ! isset($this->entityDeletions[$oid])) {
1375 65
            $this->entityDeletions[$oid] = $entity;
1376 65
            $this->entityStates[$oid]    = self::STATE_REMOVED;
1377
        }
1378 65
    }
1379
1380
    /**
1381
     * Checks whether an entity is registered as removed/deleted with the unit
1382
     * of work.
1383
     *
1384
     * @param object $entity
1385
     *
1386
     * @return boolean
1387
     */
1388 17
    public function isScheduledForDelete($entity)
1389
    {
1390 17
        return isset($this->entityDeletions[spl_object_hash($entity)]);
1391
    }
1392
1393
    /**
1394
     * Checks whether an entity is scheduled for insertion, update or deletion.
1395
     *
1396
     * @param object $entity
1397
     *
1398
     * @return boolean
1399
     */
1400
    public function isEntityScheduled($entity)
1401
    {
1402
        $oid = spl_object_hash($entity);
1403
1404
        return isset($this->entityInsertions[$oid])
1405
            || isset($this->entityUpdates[$oid])
1406
            || isset($this->entityDeletions[$oid]);
1407
    }
1408
1409
    /**
1410
     * INTERNAL:
1411
     * Registers an entity in the identity map.
1412
     * Note that entities in a hierarchy are registered with the class name of
1413
     * the root entity.
1414
     *
1415
     * @ignore
1416
     *
1417
     * @param object $entity The entity to register.
1418
     *
1419
     * @return boolean TRUE if the registration was successful, FALSE if the identity of
1420
     *                 the entity in question is already managed.
1421
     *
1422
     * @throws ORMInvalidArgumentException
1423
     */
1424 1077
    public function addToIdentityMap($entity)
1425
    {
1426 1077
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1427 1077
        $idHash        = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]);
1428
1429 1077
        if ($idHash === '') {
1430 1
            throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

An additional type check may prevent trouble.

Loading history...
1831
            }
1832
1833 4
            return $managedCopy;
1834
        }
1835
1836 40
        $class = $this->em->getClassMetadata(get_class($entity));
1837
1838
        // First we assume DETACHED, although it can still be NEW but we can avoid
1839
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1840
        // we need to fetch it from the db anyway in order to merge.
1841
        // MANAGED entities are ignored by the merge operation.
1842 40
        $managedCopy = $entity;
1843
1844 40
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1845
            // Try to look the entity up in the identity map.
1846 39
            $id = $class->getIdentifierValues($entity);
1847
1848
            // If there is no ID, it is actually NEW.
1849 39
            if ( ! $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

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

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

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

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

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

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

Loading history...
1853
            } else {
1854 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...
1855 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...
1856 35
                    : $id;
1857
1858 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 1922 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1859
1860 35
                if ($managedCopy) {
1861
                    // We have the entity in-memory already, just make sure its not removed.
1862 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 1858 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...
1863 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 1858 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...
1864
                    }
1865
                } else {
1866
                    // We need to fetch the managed copy in order to merge.
1867 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...
1868
                }
1869
1870 35
                if ($managedCopy === null) {
1871
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1872
                    // since the managed entity was not found.
1873 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...
1874 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1875 1
                            $class->getName(),
1876 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...
1877
                        );
1878
                    }
1879
1880 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...
1881 1
                    $class->setIdentifierValues($managedCopy, $id);
1882
1883 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...
1884
                }
1885
            }
1886
1887 38
            if ($class->isVersioned && $this->isLoaded($managedCopy) && $this->isLoaded($entity)) {
0 ignored issues
show
Bug introduced by
Accessing isVersioned on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1858 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...
1888 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...
1889 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1890 4
                $entityVersion      = $reflField->getValue($entity);
1891
1892
                // Throw exception if versions don't match.
1893 4
                if ($managedCopyVersion != $entityVersion) {
1894 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1895
                }
1896
            }
1897
1898 37
            $visited[$oid] = $managedCopy; // mark visited
1899
1900 37
            if ($this->isLoaded($entity)) {
1901 30
                if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) {
1902 4
                    $managedCopy->__load();
1903
                }
1904
1905 30
                $this->mergeEntityStateIntoManagedCopy($entity, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1858 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...
1906
            }
1907
1908 37
            if ($class->isChangeTrackingDeferredExplicit()) {
1909
                $this->scheduleForDirtyCheck($entity);
1910
            }
1911
        }
1912
1913 38
        if ($prevManagedCopy !== null) {
1914 6
            $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $assoc defined by parameter $assoc on line 1822 can also be of type null; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept array, maybe add an additional type check?

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

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

An additional type check may prevent trouble.

Loading history...
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1858 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...
1915
        }
1916
1917
        // Mark the managed copy visited as well
1918 38
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1919
1920 38
        $this->cascadeMerge($entity, $managedCopy, $visited);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1858 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...
1921
1922 38
        return $managedCopy;
1923
    }
1924
1925
    /**
1926
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1927
     *
1928
     * @param object $entity
1929
     *
1930
     * @return bool
1931
     */
1932 38
    private function isLoaded($entity)
1933
    {
1934 38
        return !($entity instanceof Proxy) || $entity->__isInitialized();
1935
    }
1936
1937
    /**
1938
     * Sets/adds associated managed copies into the previous entity's association field
1939
     *
1940
     * @param object $entity
1941
     * @param array  $association
1942
     * @param object $previousManagedCopy
1943
     * @param object $managedCopy
1944
     *
1945
     * @return void
1946
     */
1947 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1948
    {
1949 6
        $assocField = $association['fieldName'];
1950 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1951
1952 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1953 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...
1954
1955 6
            return;
1956
        }
1957
1958 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...
1959 1
        $value[] = $managedCopy;
1960
1961 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1962 1
            $class = $this->em->getClassMetadata(get_class($entity));
1963
1964 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...
1965
        }
1966 1
    }
1967
1968
    /**
1969
     * Detaches an entity from the persistence management. It's persistence will
1970
     * no longer be managed by Doctrine.
1971
     *
1972
     * @param object $entity The entity to detach.
1973
     *
1974
     * @return void
1975
     */
1976 12
    public function detach($entity)
1977
    {
1978 12
        $visited = array();
1979
1980 12
        $this->doDetach($entity, $visited);
1981 12
    }
1982
1983
    /**
1984
     * Executes a detach operation on the given entity.
1985
     *
1986
     * @param object  $entity
1987
     * @param array   $visited
1988
     * @param boolean $noCascade if true, don't cascade detach operation.
1989
     *
1990
     * @return void
1991
     */
1992 14
    private function doDetach($entity, array &$visited, $noCascade = false)
1993
    {
1994 14
        $oid = spl_object_hash($entity);
1995
1996 14
        if (isset($visited[$oid])) {
1997
            return; // Prevent infinite recursion
1998
        }
1999
2000 14
        $visited[$oid] = $entity; // mark visited
2001
2002 14
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
2003 14
            case self::STATE_MANAGED:
2004 12
                if ($this->isInIdentityMap($entity)) {
2005 11
                    $this->removeFromIdentityMap($entity);
2006
                }
2007
2008
                unset(
2009 12
                    $this->entityInsertions[$oid],
2010 12
                    $this->entityUpdates[$oid],
2011 12
                    $this->entityDeletions[$oid],
2012 12
                    $this->entityIdentifiers[$oid],
2013 12
                    $this->entityStates[$oid],
2014 12
                    $this->originalEntityData[$oid]
2015
                );
2016 12
                break;
2017 3
            case self::STATE_NEW:
2018 3
            case self::STATE_DETACHED:
2019 3
                return;
2020
        }
2021
2022 12
        if ( ! $noCascade) {
2023 12
            $this->cascadeDetach($entity, $visited);
2024
        }
2025 12
    }
2026
2027
    /**
2028
     * Refreshes the state of the given entity from the database, overwriting
2029
     * any local, unpersisted changes.
2030
     *
2031
     * @param object $entity The entity to refresh.
2032
     *
2033
     * @return void
2034
     *
2035
     * @throws InvalidArgumentException If the entity is not MANAGED.
2036
     */
2037 16
    public function refresh($entity)
2038
    {
2039 16
        $visited = array();
2040
2041 16
        $this->doRefresh($entity, $visited);
2042 16
    }
2043
2044
    /**
2045
     * Executes a refresh operation on an entity.
2046
     *
2047
     * @param object $entity  The entity to refresh.
2048
     * @param array  $visited The already visited entities during cascades.
2049
     *
2050
     * @return void
2051
     *
2052
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2053
     */
2054 16
    private function doRefresh($entity, array &$visited)
2055
    {
2056 16
        $oid = spl_object_hash($entity);
2057
2058 16
        if (isset($visited[$oid])) {
2059
            return; // Prevent infinite recursion
2060
        }
2061
2062 16
        $visited[$oid] = $entity; // mark visited
2063
2064 16
        $class = $this->em->getClassMetadata(get_class($entity));
2065
2066 16
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2067
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2068
        }
2069
2070 16
        $this->getEntityPersister($class->name)->refresh(
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2071 16
            array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2072
            $entity
2073
        );
2074
2075 16
        $this->cascadeRefresh($entity, $visited);
2076 16
    }
2077
2078
    /**
2079
     * Cascades a refresh operation to associated entities.
2080
     *
2081
     * @param object $entity
2082
     * @param array  $visited
2083
     *
2084
     * @return void
2085
     */
2086 16
    private function cascadeRefresh($entity, array &$visited)
2087
    {
2088 16
        $class = $this->em->getClassMetadata(get_class($entity));
2089
2090 16
        $associationMappings = array_filter(
2091 16
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2092
            function ($assoc) { return $assoc['isCascadeRefresh']; }
2093
        );
2094
2095 16
        foreach ($associationMappings as $assoc) {
2096
            $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...
2097
2098
            switch (true) {
2099
                case ($relatedEntities instanceof PersistentCollection):
2100
                    // Unwrap so that foreach() does not initialize
2101
                    $relatedEntities = $relatedEntities->unwrap();
2102
                    // break; is commented intentionally!
2103
2104
                case ($relatedEntities instanceof Collection):
2105
                case (is_array($relatedEntities)):
2106
                    foreach ($relatedEntities as $relatedEntity) {
2107
                        $this->doRefresh($relatedEntity, $visited);
2108
                    }
2109
                    break;
2110
2111
                case ($relatedEntities !== null):
2112
                    $this->doRefresh($relatedEntities, $visited);
2113
                    break;
2114
2115
                default:
2116
                    // Do nothing
2117
            }
2118
        }
2119 16
    }
2120
2121
    /**
2122
     * Cascades a detach operation to associated entities.
2123
     *
2124
     * @param object $entity
2125
     * @param array  $visited
2126
     *
2127
     * @return void
2128
     */
2129 12
    private function cascadeDetach($entity, array &$visited)
2130
    {
2131 12
        $class = $this->em->getClassMetadata(get_class($entity));
2132
2133 12
        $associationMappings = array_filter(
2134 12
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2135
            function ($assoc) { return $assoc['isCascadeDetach']; }
2136
        );
2137
2138 12
        foreach ($associationMappings as $assoc) {
2139 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...
2140
2141
            switch (true) {
2142 3
                case ($relatedEntities instanceof PersistentCollection):
2143
                    // Unwrap so that foreach() does not initialize
2144 2
                    $relatedEntities = $relatedEntities->unwrap();
2145
                    // break; is commented intentionally!
2146
2147
                case ($relatedEntities instanceof Collection):
2148
                case (is_array($relatedEntities)):
2149 3
                    foreach ($relatedEntities as $relatedEntity) {
2150 1
                        $this->doDetach($relatedEntity, $visited);
2151
                    }
2152 3
                    break;
2153
2154
                case ($relatedEntities !== null):
2155
                    $this->doDetach($relatedEntities, $visited);
2156
                    break;
2157
2158 3
                default:
2159
                    // Do nothing
2160
            }
2161
        }
2162 12
    }
2163
2164
    /**
2165
     * Cascades a merge operation to associated entities.
2166
     *
2167
     * @param object $entity
2168
     * @param object $managedCopy
2169
     * @param array  $visited
2170
     *
2171
     * @return void
2172
     */
2173 38
    private function cascadeMerge($entity, $managedCopy, array &$visited)
2174
    {
2175 38
        $class = $this->em->getClassMetadata(get_class($entity));
2176
2177 38
        $associationMappings = array_filter(
2178 38
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2539 311
            $oid = spl_object_hash($entity);
2540
2541
            if (
2542 311
                isset($hints[Query::HINT_REFRESH])
2543 311
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2544 311
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2545 311
                && $unmanagedProxy instanceof Proxy
2546 311
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2547
            ) {
2548
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2549
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2550
                // refreshed object may be anything
2551
2552 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...
2553 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...
2554
                }
2555
2556 2
                return $unmanagedProxy;
2557
            }
2558
2559 309
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2560 21
                $entity->__setInitialized(true);
2561
2562 21
                $overrideLocalValues = true;
2563
2564 21
                if ($entity instanceof NotifyPropertyChanged) {
2565 21
                    $entity->addPropertyChangedListener($this);
2566
                }
2567
            } else {
2568 290
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2569
2570
                // If only a specific entity is set to refresh, check that it's the one
2571 290
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2572 72
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2573
                }
2574
            }
2575
2576 309
            if ($overrideLocalValues) {
2577
                // inject ObjectManager upon refresh.
2578 112
                if ($entity instanceof ObjectManagerAware) {
2579 3
                    $entity->injectObjectManager($this->em, $class);
2580
                }
2581
2582 309
                $this->originalEntityData[$oid] = $data;
2583
            }
2584
        } else {
2585 659
            $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...
2586 659
            $oid    = spl_object_hash($entity);
2587
2588 659
            $this->entityIdentifiers[$oid]  = $id;
2589 659
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2590 659
            $this->originalEntityData[$oid] = $data;
2591
2592 659
            $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...
2593
2594 659
            if ($entity instanceof NotifyPropertyChanged) {
2595 2
                $entity->addPropertyChangedListener($this);
2596
            }
2597
2598 659
            $overrideLocalValues = true;
2599
        }
2600
2601 799
        if ( ! $overrideLocalValues) {
2602 219
            return $entity;
2603
        }
2604
2605 696
        foreach ($data as $field => $value) {
2606 696
            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...
2607 696
                $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...
2608
            }
2609
        }
2610
2611
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2612 696
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2613
2614 696
        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...
2615
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2616
        }
2617
2618
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2619 696
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2620 33
            return $entity;
2621
        }
2622
2623 663
        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...
2624
            // Check if the association is not among the fetch-joined associations already.
2625 580
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2626 254
                continue;
2627
            }
2628
2629 558
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2630
2631
            switch (true) {
2632 558
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2633 478
                    if ( ! $assoc['isOwningSide']) {
2634
2635
                        // use the given entity association
2636 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2637
2638 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2639
2640 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...
2641 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...
2642
2643 2
                            continue 2;
2644
                        }
2645
2646
                        // Inverse side of x-to-one can never be lazy
2647 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...
2648
2649 62
                        continue 2;
2650
                    }
2651
2652
                    // use the entity association
2653 478
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2654 37
                        $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...
2655 37
                        $this->originalEntityData[$oid][$field] = $data[$field];
2656
2657 37
                        continue;
2658
                    }
2659
2660 471
                    $associatedId = array();
2661
2662
                    // TODO: Is this even computed right in all cases of composite keys?
2663 471
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2664 471
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2665
2666 471
                        if ($joinColumnValue !== null) {
2667 282
                            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...
2668 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2669
                            } else {
2670 282
                                $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...
2671
                            }
2672 281
                        } 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...
2673 281
                            && 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...
2674
                        ) {
2675
                            // the missing key is part of target's entity primary key
2676 7
                            $associatedId = array();
2677 471
                            break;
2678
                        }
2679
                    }
2680
2681 471
                    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...
2682
                        // Foreign key is NULL
2683 281
                        $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...
2684 281
                        $this->originalEntityData[$oid][$field] = null;
2685
2686 281
                        continue;
2687
                    }
2688
2689 282
                    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...
2690 279
                        $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...
2691
                    }
2692
2693
                    // Foreign key is set
2694
                    // Check identity map first
2695
                    // FIXME: Can break easily with composite keys if join column values are in
2696
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2697 282
                    $relatedIdHash = implode(' ', $associatedId);
2698
2699
                    switch (true) {
2700 282
                        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...
2701 164
                            $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...
2702
2703
                            // If this is an uninitialized proxy, we are deferring eager loads,
2704
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2705
                            // then we can append this entity for eager loading!
2706 164
                            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...
2707 164
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2708 164
                                !$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...
2709 164
                                $newValue instanceof Proxy &&
2710 164
                                $newValue->__isInitialized__ === false) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3409
3410 28
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3411 24
                    $other = $prop->getValue($entity);
3412 24
                    if ($other === null) {
3413 11
                        $prop->setValue($managedCopy, null);
3414
                    } else {
3415 16
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3416
                            // do not merge fields marked lazy that have not been fetched.
3417 4
                            continue;
3418
                        }
3419
3420 12
                        if ( ! $assoc2['isCascadeMerge']) {
3421 6
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3422 3
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3423 3
                                $relatedId   = $targetClass->getIdentifierValues($other);
3424
3425 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...
3426 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...
3427
                                } else {
3428 1
                                    $other = $this->em->getProxyFactory()->getProxy(
3429 1
                                        $assoc2['targetEntity'],
3430
                                        $relatedId
3431
                                    );
3432 1
                                    $this->registerManaged($other, $relatedId, array());
3433
                                }
3434
                            }
3435
3436 20
                            $prop->setValue($managedCopy, $other);
3437
                        }
3438
                    }
3439
                } else {
3440 16
                    $mergeCol = $prop->getValue($entity);
3441
3442 16
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3443
                        // do not merge fields marked lazy that have not been fetched.
3444
                        // keep the lazy persistent collection of the managed copy.
3445 5
                        continue;
3446
                    }
3447
3448 13
                    $managedCol = $prop->getValue($managedCopy);
3449
3450 13
                    if ( ! $managedCol) {
3451 3
                        $managedCol = new PersistentCollection(
3452 3
                            $this->em,
3453 3
                            $this->em->getClassMetadata($assoc2['targetEntity']),
0 ignored issues
show
Compatibility introduced by
$this->em->getClassMetad...assoc2['targetEntity']) of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
3454 3
                            new ArrayCollection
3455
                        );
3456 3
                        $managedCol->setOwner($managedCopy, $assoc2);
3457 3
                        $prop->setValue($managedCopy, $managedCol);
3458
3459 3
                        $this->originalEntityData[spl_object_hash($entity)][$name] = $managedCol;
3460
                    }
3461
3462 13
                    if ($assoc2['isCascadeMerge']) {
3463 8
                        $managedCol->initialize();
3464
3465
                        // clear and set dirty a managed collection if its not also the same collection to merge from.
3466 8
                        if ( ! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
3467 1
                            $managedCol->unwrap()->clear();
3468 1
                            $managedCol->setDirty(true);
3469
3470 1
                            if ($assoc2['isOwningSide']
3471 1
                                && $assoc2['type'] == ClassMetadata::MANY_TO_MANY
3472 1
                                && $class->isChangeTrackingNotify()
3473
                            ) {
3474
                                $this->scheduleForDirtyCheck($managedCopy);
3475
                            }
3476
                        }
3477
                    }
3478
                }
3479
            }
3480
3481 30
            if ($class->isChangeTrackingNotify()) {
3482
                // Just treat all properties as changed, there is no other choice.
3483 30
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
3484
            }
3485
        }
3486 30
    }
3487
3488
    /**
3489
     * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
3490
     * Unit of work able to fire deferred events, related to loading events here.
3491
     *
3492
     * @internal should be called internally from object hydrators
3493
     */
3494 868
    public function hydrationComplete()
3495
    {
3496 868
        $this->hydrationCompleteHandler->hydrationComplete();
3497 868
    }
3498
}
3499