Completed
Pull Request — master (#1241)
by Marco
12:49
created

UnitOfWork::lock()   C

Complexity

Conditions 13
Paths 15

Size

Total Lines 53
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

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

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 ProxyManager\Proxy\GhostObjectInterface;
29
use UnexpectedValueException;
30
31
use Doctrine\Common\Collections\ArrayCollection;
32
use Doctrine\Common\Collections\Collection;
33
use Doctrine\Common\NotifyPropertyChanged;
34
use Doctrine\Common\PropertyChangedListener;
35
use Doctrine\Common\Persistence\ObjectManagerAware;
36
use Doctrine\ORM\Mapping\ClassMetadata;
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 2315
    public function __construct(EntityManagerInterface $em)
294
    {
295 2315
        $this->em                         = $em;
296 2315
        $this->evm                        = $em->getEventManager();
297 2315
        $this->listenersInvoker           = new ListenersInvoker($em);
298 2315
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
299 2315
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
300 2315
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
301 2315
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
302 2315
    }
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 1004
    public function commit($entity = null)
324
    {
325
        // Raise preFlush
326 1004
        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 1004
        if ($entity === null) {
332 996
            $this->computeChangeSets();
333 16
        } elseif (is_object($entity)) {
334 15
            $this->computeSingleEntityChangeSet($entity);
335 1
        } elseif (is_array($entity)) {
336 1
            foreach ($entity as $object) {
337 1
                $this->computeSingleEntityChangeSet($object);
338
            }
339
        }
340
341 1001
        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 1001
                $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 997
        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 997
        $this->dispatchOnFlushEvent();
360
361
        // Now we need a commit order to maintain referential integrity
362 997
        $commitOrder = $this->getCommitOrder();
363
364 997
        $conn = $this->em->getConnection();
365 997
        $conn->beginTransaction();
366
367
        try {
368
            // Collection deletions (deletions of complete collections)
369 997
            foreach ($this->collectionDeletions as $collectionToDelete) {
370 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
371
            }
372
373 997
            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 993
                foreach ($commitOrder as $class) {
375 993
                    $this->executeInserts($class);
376
                }
377
            }
378
379 996
            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 992
            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 992
            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 992
            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 62
                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 62
                    $this->executeDeletions($commitOrder[$i]);
399
                }
400
            }
401
402 992
            $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 992
        $this->afterTransactionComplete();
413
414
        // Take new snapshots from visited collections
415 992
        foreach ($this->visitedCollections as $coll) {
416 522
            $coll->takeSnapshot();
417
        }
418
419 992
        $this->dispatchPostFlushEvent();
420
421
        // Clear up
422 991
        $this->entityInsertions =
423 991
        $this->entityUpdates =
424 991
        $this->entityDeletions =
425 991
        $this->extraUpdates =
426 991
        $this->entityChangeSets =
427 991
        $this->collectionUpdates =
428 991
        $this->collectionDeletions =
429 991
        $this->visitedCollections =
430 991
        $this->scheduledForSynchronization =
431 991
        $this->orphanRemovals = array();
432 991
    }
433
434
    /**
435
     * Computes the changesets of all entities scheduled for insertion.
436
     *
437
     * @return void
438
     */
439 1003
    private function computeScheduleInsertsChangeSets()
440
    {
441 1003
        foreach ($this->entityInsertions as $entity) {
442 995
            $class = $this->em->getClassMetadata(get_class($entity));
443
444 995
            $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...
445
        }
446 1001
    }
447
448
    /**
449
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
450
     *
451
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
452
     * 2. Read Only entities are skipped.
453
     * 3. Proxies are skipped.
454
     * 4. Only if entity is properly managed.
455
     *
456
     * @param object $entity
457
     *
458
     * @return void
459
     *
460
     * @throws \InvalidArgumentException
461
     */
462 16
    private function computeSingleEntityChangeSet($entity)
463
    {
464 16
        $state = $this->getEntityState($entity);
465
466 16
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
467 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
468
        }
469
470 15
        $class = $this->em->getClassMetadata(get_class($entity));
471
472 15
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
473 14
            $this->persist($entity);
474
        }
475
476
        // Compute changes for INSERTed entities first. This must always happen even in this case.
477 15
        $this->computeScheduleInsertsChangeSets();
478
479 15
        if ($class->isReadOnly) {
0 ignored issues
show
Bug introduced by
Accessing isReadOnly on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

Loading history...
576
577 1005
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
578 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...
579
        }
580
581 1005
        $actualData = array();
582
583 1005
        foreach ($class->reflFields as $name => $refProp) {
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
765 1
                continue;
766
            }
767
768
            // If change tracking is explicit or happens through notification, then only compute
769
            // changes on entities of that type that are explicitly marked for synchronization.
770
            switch (true) {
771 442
                case ($class->isChangeTrackingDeferredImplicit()):
772 440
                    $entitiesToProcess = $entities;
773 440
                    break;
774
775 3
                case (isset($this->scheduledForSynchronization[$className])):
776 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
777 3
                    break;
778
779
                default:
780 1
                    $entitiesToProcess = array();
781
782
            }
783
784 442
            foreach ($entitiesToProcess as $entity) {
785
                // Ignore uninitialized proxy objects
786 423
                if ($entity instanceof GhostObjectInterface && ! $entity->isProxyInitialized()) {
787 31
                    continue;
788
                }
789
790
                // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
791 422
                $oid = spl_object_hash($entity);
792
793 422
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
794 442
                    $this->computeChangeSet($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
795
                }
796
            }
797
        }
798 994
    }
799
800
    /**
801
     * Computes the changes of an association.
802
     *
803
     * @param array $assoc The association mapping.
804
     * @param mixed $value The value of the association.
805
     *
806
     * @throws ORMInvalidArgumentException
807
     * @throws ORMException
808
     *
809
     * @return void
810
     */
811 855
    private function computeAssociationChanges($assoc, $value)
812
    {
813 855
        if ($value instanceof GhostObjectInterface && ! $value->isProxyInitialized()) {
814 26
            return;
815
        }
816
817 854
        if ($value instanceof PersistentCollection && $value->isDirty()) {
818 525
            $coid = spl_object_hash($value);
819
820 525
            $this->collectionUpdates[$coid] = $value;
821 525
            $this->visitedCollections[$coid] = $value;
822
        }
823
824
        // Look through the entities, and in any of their associations,
825
        // for transient (new) entities, recursively. ("Persistence by reachability")
826
        // Unwrap. Uninitialized collections will simply be empty.
827 854
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
828 854
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
829
830 854
        foreach ($unwrappedValue as $key => $entry) {
831 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...
832 6
                throw ORMInvalidArgumentException::invalidAssociation($targetClass, $assoc, $entry);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

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

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

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

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

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

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

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

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

    return false;
}

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

Loading history...
1009
            // Persister returned post-insert IDs
1010 910
            foreach ($postInsertIds as $postInsertId) {
1011 910
                $id      = $postInsertId['generatedId'];
1012 910
                $entity  = $postInsertId['entity'];
1013 910
                $oid     = spl_object_hash($entity);
1014 910
                $idField = $class->identifier[0];
1015
1016 910
                $class->reflFields[$idField]->setValue($entity, $id);
1017
1018 910
                $this->entityIdentifiers[$oid] = array($idField => $id);
1019 910
                $this->entityStates[$oid] = self::STATE_MANAGED;
1020 910
                $this->originalEntityData[$oid][$idField] = $id;
1021
1022 910
                $this->addToIdentityMap($entity);
1023
            }
1024
        }
1025
1026 993
        foreach ($entities as $entity) {
1027 134
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1028
        }
1029 993
    }
1030
1031
    /**
1032
     * Executes all entity updates for entities of the specified type.
1033
     *
1034
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1035
     *
1036
     * @return void
1037
     */
1038 115
    private function executeUpdates($class)
1039
    {
1040 115
        $className          = $class->name;
1041 115
        $persister          = $this->getEntityPersister($className);
1042 115
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1043 115
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1044
1045 115
        foreach ($this->entityUpdates as $oid => $entity) {
1046
1047 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...
1048 73
                continue;
1049
            }
1050
1051 115
            if ($preUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1052 13
                $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->entityChangeSets[$oid]), $preUpdateInvoke);
1053 13
                $this->recomputeSingleEntityChangeSet($class, $entity);
1054
            }
1055
1056 115
            if ( ! empty($this->entityChangeSets[$oid])) {
1057 82
                $persister->update($entity);
1058
            }
1059
1060 111
            unset($this->entityUpdates[$oid]);
1061
1062 111
            if ($postUpdateInvoke != ListenersInvoker::INVOKE_NONE) {
1063 111
                $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new LifecycleEventArgs($entity, $this->em), $postUpdateInvoke);
1064
            }
1065
        }
1066 111
    }
1067
1068
    /**
1069
     * Executes all entity deletions for entities of the specified type.
1070
     *
1071
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1072
     *
1073
     * @return void
1074
     */
1075 62
    private function executeDeletions($class)
1076
    {
1077 62
        $className  = $class->name;
1078 62
        $persister  = $this->getEntityPersister($className);
1079 62
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove);
1080
1081 62
        foreach ($this->entityDeletions as $oid => $entity) {
1082 62
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1164 822
                    continue;
1165
                }
1166
1167 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...
1168 216
                    $targetSubClass = $this->em->getClassMetadata($subClassName);
1169
1170 216
                    if ( ! $calc->hasNode($subClassName)) {
1171 189
                        $calc->addNode($targetSubClass->name, $targetSubClass);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1601
    }
1602
1603
    /**
1604
     * INTERNAL:
1605
     * Checks whether an identifier hash exists in the identity map.
1606
     *
1607
     * @ignore
1608
     *
1609
     * @param string $idHash
1610
     * @param string $rootClassName
1611
     *
1612
     * @return boolean
1613
     */
1614
    public function containsIdHash($idHash, $rootClassName)
1615
    {
1616
        return isset($this->identityMap[$rootClassName][$idHash]);
1617
    }
1618
1619
    /**
1620
     * Persists an entity as part of the current unit of work.
1621
     *
1622
     * @param object $entity The entity to persist.
1623
     *
1624
     * @return void
1625
     */
1626 1010
    public function persist($entity)
1627
    {
1628 1010
        $visited = array();
1629
1630 1010
        $this->doPersist($entity, $visited);
1631 1003
    }
1632
1633
    /**
1634
     * Persists an entity as part of the current unit of work.
1635
     *
1636
     * This method is internally called during persist() cascades as it tracks
1637
     * the already visited entities to prevent infinite recursions.
1638
     *
1639
     * @param object $entity  The entity to persist.
1640
     * @param array  $visited The already visited entities.
1641
     *
1642
     * @return void
1643
     *
1644
     * @throws ORMInvalidArgumentException
1645
     * @throws UnexpectedValueException
1646
     */
1647 1010
    private function doPersist($entity, array &$visited)
1648
    {
1649 1010
        $oid = spl_object_hash($entity);
1650
1651 1010
        if (isset($visited[$oid])) {
1652 109
            return; // Prevent infinite recursion
1653
        }
1654
1655 1010
        $visited[$oid] = $entity; // Mark visited
1656
1657 1010
        $class = $this->em->getClassMetadata(get_class($entity));
1658
1659
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1660
        // If we would detect DETACHED here we would throw an exception anyway with the same
1661
        // consequences (not recoverable/programming error), so just assuming NEW here
1662
        // lets us avoid some database lookups for entities with natural identifiers.
1663 1010
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1664
1665
        switch ($entityState) {
1666 1010
            case self::STATE_MANAGED:
1667
                // Nothing to do, except if policy is "deferred explicit"
1668 233
                if ($class->isChangeTrackingDeferredExplicit()) {
1669 2
                    $this->scheduleForDirtyCheck($entity);
1670
                }
1671 233
                break;
1672
1673 1010
            case self::STATE_NEW:
1674 1009
                $this->persistNew($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

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

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

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

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

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

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

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

An additional type check may prevent trouble.

Loading history...
1808
            }
1809
1810 4
            return $managedCopy;
1811
        }
1812
1813 38
        $class = $this->em->getClassMetadata(get_class($entity));
1814
1815
        // First we assume DETACHED, although it can still be NEW but we can avoid
1816
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1817
        // we need to fetch it from the db anyway in order to merge.
1818
        // MANAGED entities are ignored by the merge operation.
1819 38
        $managedCopy = $entity;
1820
1821 38
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1822 37
            if ($entity instanceof GhostObjectInterface && ! $entity->isProxyInitialized()) {
1823 6
                $this->em->getProxyFactory()->resetUninitializedProxy($entity);
1824 6
                $entity->initializeProxy();
1825
            }
1826
1827
            // Try to look the entity up in the identity map.
1828 35
            $id = $class->getIdentifierValues($entity);
1829
1830
            // If there is no ID, it is actually NEW.
1831 35
            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...
1832 6
                $managedCopy = $this->newInstance($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

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

Loading history...
1835
            } else {
1836 30
                $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...
1837 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...
1838 30
                    : $id;
1839
1840 30
                $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 1908 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1841
1842 30
                if ($managedCopy) {
1843
                    // We have the entity in-memory already, just make sure its not removed.
1844 12
                    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 1840 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...
1845 12
                        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 1840 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...
1846
                    }
1847
                } else {
1848
                    // We need to fetch the managed copy in order to merge.
1849 21
                    $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...
1850
                }
1851
1852 30
                if ($managedCopy === null) {
1853
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1854
                    // since the managed entity was not found.
1855 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...
1856 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1857 1
                            $class->getName(),
1858 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...
1859
                        );
1860
                    }
1861
1862 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...
1863 1
                    $class->setIdentifierValues($managedCopy, $id);
1864
1865 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...
1866
                } else {
1867 28
                    if ($managedCopy instanceof GhostObjectInterface && ! $managedCopy->isProxyInitialized()) {
1868 3
                        $managedCopy->isProxyInitialized();
1869
                    }
1870
                }
1871
            }
1872
1873 34
            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 1840 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...
1874 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...
1875 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1876 4
                $entityVersion      = $reflField->getValue($entity);
1877
1878
                // Throw exception if versions don't match.
1879 4
                if ($managedCopyVersion != $entityVersion) {
1880 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1881
                }
1882
            }
1883
1884 33
            $visited[$oid] = $managedCopy; // mark visited
1885
1886 33
            if ($this->isLoaded($entity)) {
1887 33
                if ($managedCopy instanceof GhostObjectInterface) {
1888 6
                    $managedCopy->initializeProxy();
1889
                }
1890
1891 33
                $this->mergeEntityStateIntoManagedCopy($entity, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1840 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...
1892
            }
1893
1894 33
            if ($class->isChangeTrackingDeferredExplicit()) {
1895
                $this->scheduleForDirtyCheck($entity);
1896
            }
1897
        }
1898
1899 34
        if ($prevManagedCopy !== null) {
1900 6
            $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $assoc defined by parameter $assoc on line 1799 can also be of type null; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept array, maybe add an additional type check?

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

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

An additional type check may prevent trouble.

Loading history...
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1840 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...
1901
        }
1902
1903
        // Mark the managed copy visited as well
1904 34
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1905
1906 34
        $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 1840 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...
1907
1908 34
        return $managedCopy;
1909
    }
1910
1911
    /**
1912
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1913
     *
1914
     * @param object $entity
1915
     *
1916
     * @return bool
1917
     */
1918 34
    private function isLoaded($entity)
1919
    {
1920 34
        return !($entity instanceof GhostObjectInterface) || $entity->isProxyInitialized();
1921
    }
1922
1923
    /**
1924
     * Sets/adds associated managed copies into the previous entity's association field
1925
     *
1926
     * @param object $entity
1927
     * @param array  $association
1928
     * @param object $previousManagedCopy
1929
     * @param object $managedCopy
1930
     *
1931
     * @return void
1932
     */
1933 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1934
    {
1935 6
        $assocField = $association['fieldName'];
1936 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1937
1938 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1939 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...
1940
1941 6
            return;
1942
        }
1943
1944 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...
1945 1
        $value[] = $managedCopy;
1946
1947 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1948 1
            $class = $this->em->getClassMetadata(get_class($entity));
1949
1950 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...
1951
        }
1952 1
    }
1953
1954
    /**
1955
     * Detaches an entity from the persistence management. It's persistence will
1956
     * no longer be managed by Doctrine.
1957
     *
1958
     * @param object $entity The entity to detach.
1959
     *
1960
     * @return void
1961
     */
1962 12
    public function detach($entity)
1963
    {
1964 12
        $visited = array();
1965
1966 12
        $this->doDetach($entity, $visited);
1967 12
    }
1968
1969
    /**
1970
     * Executes a detach operation on the given entity.
1971
     *
1972
     * @param object  $entity
1973
     * @param array   $visited
1974
     * @param boolean $noCascade if true, don't cascade detach operation.
1975
     *
1976
     * @return void
1977
     */
1978 14
    private function doDetach($entity, array &$visited, $noCascade = false)
1979
    {
1980 14
        $oid = spl_object_hash($entity);
1981
1982 14
        if (isset($visited[$oid])) {
1983
            return; // Prevent infinite recursion
1984
        }
1985
1986 14
        $visited[$oid] = $entity; // mark visited
1987
1988 14
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
1989 14
            case self::STATE_MANAGED:
1990 12
                if ($this->isInIdentityMap($entity)) {
1991 11
                    $this->removeFromIdentityMap($entity);
1992
                }
1993
1994
                unset(
1995 12
                    $this->entityInsertions[$oid],
1996 12
                    $this->entityUpdates[$oid],
1997 12
                    $this->entityDeletions[$oid],
1998 12
                    $this->entityIdentifiers[$oid],
1999 12
                    $this->entityStates[$oid],
2000 12
                    $this->originalEntityData[$oid]
2001
                );
2002 12
                break;
2003 3
            case self::STATE_NEW:
2004 3
            case self::STATE_DETACHED:
2005 3
                return;
2006
        }
2007
2008 12
        if ( ! $noCascade) {
2009 12
            $this->cascadeDetach($entity, $visited);
2010
        }
2011 12
    }
2012
2013
    /**
2014
     * Refreshes the state of the given entity from the database, overwriting
2015
     * any local, unpersisted changes.
2016
     *
2017
     * @param object $entity The entity to refresh.
2018
     *
2019
     * @return void
2020
     *
2021
     * @throws InvalidArgumentException If the entity is not MANAGED.
2022
     */
2023 16
    public function refresh($entity)
2024
    {
2025 16
        $visited = array();
2026
2027 16
        $this->doRefresh($entity, $visited);
2028 16
    }
2029
2030
    /**
2031
     * Executes a refresh operation on an entity.
2032
     *
2033
     * @param object $entity  The entity to refresh.
2034
     * @param array  $visited The already visited entities during cascades.
2035
     *
2036
     * @return void
2037
     *
2038
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2039
     */
2040 16
    private function doRefresh($entity, array &$visited)
2041
    {
2042 16
        $oid = spl_object_hash($entity);
2043
2044 16
        if (isset($visited[$oid])) {
2045
            return; // Prevent infinite recursion
2046
        }
2047
2048 16
        $visited[$oid] = $entity; // mark visited
2049
2050 16
        $class = $this->em->getClassMetadata(get_class($entity));
2051
2052 16
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2053
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2054
        }
2055
2056 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...
2057 16
            array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2058
            $entity
2059
        );
2060
2061 16
        $this->cascadeRefresh($entity, $visited);
2062 16
    }
2063
2064
    /**
2065
     * Cascades a refresh operation to associated entities.
2066
     *
2067
     * @param object $entity
2068
     * @param array  $visited
2069
     *
2070
     * @return void
2071
     */
2072 16
    private function cascadeRefresh($entity, array &$visited)
2073
    {
2074 16
        $class = $this->em->getClassMetadata(get_class($entity));
2075
2076 16
        $associationMappings = array_filter(
2077 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...
2078
            function ($assoc) { return $assoc['isCascadeRefresh']; }
2079
        );
2080
2081 16
        foreach ($associationMappings as $assoc) {
2082
            $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...
2083
2084
            switch (true) {
2085
                case ($relatedEntities instanceof PersistentCollection):
2086
                    // Unwrap so that foreach() does not initialize
2087
                    $relatedEntities = $relatedEntities->unwrap();
2088
                    // break; is commented intentionally!
2089
2090
                case ($relatedEntities instanceof Collection):
2091
                case (is_array($relatedEntities)):
2092
                    foreach ($relatedEntities as $relatedEntity) {
2093
                        $this->doRefresh($relatedEntity, $visited);
2094
                    }
2095
                    break;
2096
2097
                case ($relatedEntities !== null):
2098
                    $this->doRefresh($relatedEntities, $visited);
2099
                    break;
2100
2101
                default:
2102
                    // Do nothing
2103
            }
2104
        }
2105 16
    }
2106
2107
    /**
2108
     * Cascades a detach operation to associated entities.
2109
     *
2110
     * @param object $entity
2111
     * @param array  $visited
2112
     *
2113
     * @return void
2114
     */
2115 12
    private function cascadeDetach($entity, array &$visited)
2116
    {
2117 12
        $class = $this->em->getClassMetadata(get_class($entity));
2118
2119 12
        $associationMappings = array_filter(
2120 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...
2121
            function ($assoc) { return $assoc['isCascadeDetach']; }
2122
        );
2123
2124 12
        foreach ($associationMappings as $assoc) {
2125 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...
2126
2127
            switch (true) {
2128 3
                case ($relatedEntities instanceof PersistentCollection):
2129
                    // Unwrap so that foreach() does not initialize
2130 2
                    $relatedEntities = $relatedEntities->unwrap();
2131
                    // break; is commented intentionally!
2132
2133
                case ($relatedEntities instanceof Collection):
2134
                case (is_array($relatedEntities)):
2135 3
                    foreach ($relatedEntities as $relatedEntity) {
2136 1
                        $this->doDetach($relatedEntity, $visited);
2137
                    }
2138 3
                    break;
2139
2140
                case ($relatedEntities !== null):
2141
                    $this->doDetach($relatedEntities, $visited);
2142
                    break;
2143
2144 3
                default:
2145
                    // Do nothing
2146
            }
2147
        }
2148 12
    }
2149
2150
    /**
2151
     * Cascades a merge operation to associated entities.
2152
     *
2153
     * @param object $entity
2154
     * @param object $managedCopy
2155
     * @param array  $visited
2156
     *
2157
     * @return void
2158
     */
2159 34
    private function cascadeMerge($entity, $managedCopy, array &$visited)
2160
    {
2161 34
        $class = $this->em->getClassMetadata(get_class($entity));
2162
2163 34
        $associationMappings = array_filter(
2164 34
            $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...
2165
            function ($assoc) { return $assoc['isCascadeMerge']; }
2166
        );
2167
2168 34
        foreach ($associationMappings as $assoc) {
2169 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...
2170
2171 15
            if ($relatedEntities instanceof Collection) {
2172 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...
2173 1
                    continue;
2174
                }
2175
2176 8
                if ($relatedEntities instanceof PersistentCollection) {
2177
                    // Unwrap so that foreach() does not initialize
2178 5
                    $relatedEntities = $relatedEntities->unwrap();
2179
                }
2180
2181 8
                foreach ($relatedEntities as $relatedEntity) {
2182 8
                    $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
2183
                }
2184 7
            } else if ($relatedEntities !== null) {
2185 14
                $this->doMerge($relatedEntities, $visited, $managedCopy, $assoc);
2186
            }
2187
        }
2188 34
    }
2189
2190
    /**
2191
     * Cascades the save operation to associated entities.
2192
     *
2193
     * @param object $entity
2194
     * @param array  $visited
2195
     *
2196
     * @return void
2197
     */
2198 1010
    private function cascadePersist($entity, array &$visited)
2199
    {
2200 1010
        $class = $this->em->getClassMetadata(get_class($entity));
2201
2202 1010
        $associationMappings = array_filter(
2203 1010
            $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...
2204
            function ($assoc) { return $assoc['isCascadePersist']; }
2205
        );
2206
2207 1010
        foreach ($associationMappings as $assoc) {
2208 641
            $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...
2209
2210
            switch (true) {
2211 641
                case ($relatedEntities instanceof PersistentCollection):
2212
                    // Unwrap so that foreach() does not initialize
2213 22
                    $relatedEntities = $relatedEntities->unwrap();
2214
                    // break; is commented intentionally!
2215
2216
                case ($relatedEntities instanceof Collection):
2217 581
                case (is_array($relatedEntities)):
2218 546
                    if (($assoc['type'] & ClassMetadata::TO_MANY) <= 0) {
2219 3
                        throw ORMInvalidArgumentException::invalidAssociation(
2220 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...
2221
                            $assoc,
2222
                            $relatedEntities
2223
                        );
2224
                    }
2225
2226 543
                    foreach ($relatedEntities as $relatedEntity) {
2227 277
                        $this->doPersist($relatedEntity, $visited);
2228
                    }
2229
2230 543
                    break;
2231
2232 571
                case ($relatedEntities !== null):
2233 246
                    if (! $relatedEntities instanceof $assoc['targetEntity']) {
2234 4
                        throw ORMInvalidArgumentException::invalidAssociation(
2235 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...
2236
                            $assoc,
2237
                            $relatedEntities
2238
                        );
2239
                    }
2240
2241 242
                    $this->doPersist($relatedEntities, $visited);
2242 242
                    break;
2243
2244 635
                default:
2245
                    // Do nothing
2246
            }
2247
        }
2248 1003
    }
2249
2250
    /**
2251
     * Cascades the delete operation to associated entities.
2252
     *
2253
     * @param object $entity
2254
     * @param array  $visited
2255
     *
2256
     * @return void
2257
     */
2258 64
    private function cascadeRemove($entity, array &$visited)
2259
    {
2260 64
        $class = $this->em->getClassMetadata(get_class($entity));
2261
2262 64
        $associationMappings = array_filter(
2263 64
            $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...
2264
            function ($assoc) { return $assoc['isCascadeRemove']; }
2265
        );
2266
2267 64
        $entitiesToCascade = array();
2268
2269 64
        foreach ($associationMappings as $assoc) {
2270 25
            if ($entity instanceof GhostObjectInterface && !$entity->isProxyInitialized()) {
2271 5
                $entity->initializeProxy();
2272
            }
2273
2274 25
            $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...
2275
2276
            switch (true) {
2277 25
                case ($relatedEntities instanceof Collection):
2278 18
                case (is_array($relatedEntities)):
2279
                    // If its a PersistentCollection initialization is intended! No unwrap!
2280 19
                    foreach ($relatedEntities as $relatedEntity) {
2281 10
                        $entitiesToCascade[] = $relatedEntity;
2282
                    }
2283 19
                    break;
2284
2285 18
                case ($relatedEntities !== null):
2286 7
                    $entitiesToCascade[] = $relatedEntities;
2287 7
                    break;
2288
2289 25
                default:
2290
                    // Do nothing
2291
            }
2292
        }
2293
2294 64
        foreach ($entitiesToCascade as $relatedEntity) {
2295 16
            $this->doRemove($relatedEntity, $visited);
2296
        }
2297 64
    }
2298
2299
    /**
2300
     * Acquire a lock on the given entity.
2301
     *
2302
     * @param object $entity
2303
     * @param int    $lockMode
2304
     * @param int    $lockVersion
2305
     *
2306
     * @return void
2307
     *
2308
     * @throws ORMInvalidArgumentException
2309
     * @throws TransactionRequiredException
2310
     * @throws OptimisticLockException
2311
     */
2312 11
    public function lock($entity, $lockMode, $lockVersion = null)
2313
    {
2314 11
        if ($entity === null) {
2315 1
            throw new \InvalidArgumentException("No entity passed to UnitOfWork#lock().");
2316
        }
2317
2318 10
        if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
2319 1
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2320
        }
2321
2322 9
        $class = $this->em->getClassMetadata(get_class($entity));
2323
2324
        switch (true) {
2325 9
            case LockMode::OPTIMISTIC === $lockMode:
2326 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...
2327 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...
2328
                }
2329
2330 4
                if ($lockVersion === null) {
2331
                    return;
2332
                }
2333
2334 4
                if ($entity instanceof Proxy && !$entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ORM\Proxy does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
2335
                    $entity->__load();
2336
                }
2337
2338 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...
2339
2340 4
                if ($entityVersion != $lockVersion) {
2341 2
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion);
2342
                }
2343
2344 2
                break;
2345
2346 3
            case LockMode::NONE === $lockMode:
2347 3
            case LockMode::PESSIMISTIC_READ === $lockMode:
2348 1
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
2349 3
                if (!$this->em->getConnection()->isTransactionActive()) {
2350 2
                    throw TransactionRequiredException::transactionRequired();
2351
                }
2352
2353 1
                $oid = spl_object_hash($entity);
2354
2355 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...
2356 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2357
                    $lockMode
2358
                );
2359 1
                break;
2360
2361
            default:
2362
                // Do nothing
2363
        }
2364 3
    }
2365
2366
    /**
2367
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2368
     *
2369
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2370
     */
2371 997
    public function getCommitOrderCalculator()
2372
    {
2373 997
        return new Internal\CommitOrderCalculator();
2374
    }
2375
2376
    /**
2377
     * Clears the UnitOfWork.
2378
     *
2379
     * @param string|null $entityName if given, only entities of this type will get detached.
2380
     *
2381
     * @return void
2382
     */
2383 1207
    public function clear($entityName = null)
2384
    {
2385 1207
        if ($entityName === null) {
2386 1207
            $this->identityMap =
2387 1207
            $this->entityIdentifiers =
2388 1207
            $this->originalEntityData =
2389 1207
            $this->entityChangeSets =
2390 1207
            $this->entityStates =
2391 1207
            $this->scheduledForSynchronization =
2392 1207
            $this->entityInsertions =
2393 1207
            $this->entityUpdates =
2394 1207
            $this->entityDeletions =
2395 1207
            $this->collectionDeletions =
2396 1207
            $this->collectionUpdates =
2397 1207
            $this->extraUpdates =
2398 1207
            $this->readOnlyObjects =
2399 1207
            $this->visitedCollections =
2400 1207
            $this->orphanRemovals = array();
2401
        } else {
2402 2
            $visited = array();
2403
2404 2
            foreach ($this->identityMap as $className => $entities) {
2405 2
                if ($className !== $entityName) {
2406 1
                    continue;
2407
                }
2408
2409 2
                foreach ($entities as $entity) {
2410 2
                    $this->doDetach($entity, $visited, false);
2411
                }
2412
            }
2413
        }
2414
2415 1207
        if ($this->evm->hasListeners(Events::onClear)) {
2416 7
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2417
        }
2418 1207
    }
2419
2420
    /**
2421
     * INTERNAL:
2422
     * Schedules an orphaned entity for removal. The remove() operation will be
2423
     * invoked on that entity at the beginning of the next commit of this
2424
     * UnitOfWork.
2425
     *
2426
     * @ignore
2427
     *
2428
     * @param object $entity
2429
     *
2430
     * @return void
2431
     */
2432 17
    public function scheduleOrphanRemoval($entity)
2433
    {
2434 17
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2435 17
    }
2436
2437
    /**
2438
     * INTERNAL:
2439
     * Cancels a previously scheduled orphan removal.
2440
     *
2441
     * @ignore
2442
     *
2443
     * @param object $entity
2444
     *
2445
     * @return void
2446
     */
2447 110
    public function cancelOrphanRemoval($entity)
2448
    {
2449 110
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2450 110
    }
2451
2452
    /**
2453
     * INTERNAL:
2454
     * Schedules a complete collection for removal when this UnitOfWork commits.
2455
     *
2456
     * @param PersistentCollection $coll
2457
     *
2458
     * @return void
2459
     */
2460 13
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2461
    {
2462 13
        $coid = spl_object_hash($coll);
2463
2464
        // TODO: if $coll is already scheduled for recreation ... what to do?
2465
        // Just remove $coll from the scheduled recreations?
2466 13
        if (isset($this->collectionUpdates[$coid])) {
2467
            unset($this->collectionUpdates[$coid]);
2468
        }
2469
2470 13
        $this->collectionDeletions[$coid] = $coll;
2471 13
    }
2472
2473
    /**
2474
     * @param PersistentCollection $coll
2475
     *
2476
     * @return bool
2477
     */
2478
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2479
    {
2480
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2481
    }
2482
2483
    /**
2484
     * @param ClassMetadata $class
2485
     *
2486
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2487
     */
2488 661
    private function newInstance($class)
2489
    {
2490 661
        $entity = $class->newInstance();
2491
2492 661
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2493 4
            $entity->injectObjectManager($this->em, $class);
2494
        }
2495
2496 661
        return $entity;
2497
    }
2498
2499
    /**
2500
     * INTERNAL:
2501
     * Creates an entity. Used for reconstitution of persistent entities.
2502
     *
2503
     * Internal note: Highly performance-sensitive method.
2504
     *
2505
     * @ignore
2506
     *
2507
     * @param string $className The name of the entity class.
2508
     * @param array  $data      The data for the entity.
2509
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2510
     *
2511
     * @return object The managed entity instance.
2512
     *
2513
     * @todo Rename: getOrCreateEntity
2514
     */
2515 797
    public function createEntity($className, array $data, &$hints = array())
2516
    {
2517 797
        $class = $this->em->getClassMetadata($className);
2518
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2519
2520 797
        $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...
2521 797
        $idHash = implode(' ', $id);
2522
2523 797
        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...
2524 326
            $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...
2525 326
            $oid = spl_object_hash($entity);
2526
2527
            if (
2528 326
                isset($hints[Query::HINT_REFRESH])
2529 326
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2530 326
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2531 326
                && $unmanagedProxy instanceof GhostObjectInterface
2532 326
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2533
            ) {
2534
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2535
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2536
                // refreshed object may be anything
2537
2538 3
                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...
2539 3
                    $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...
2540
                }
2541
2542 3
                return $unmanagedProxy;
2543
            }
2544
2545 323
            if ($entity instanceof GhostObjectInterface && ! $entity->isProxyInitialized()) {
2546 15
                $entity->setProxyInitializer(null);
2547
2548 15
                $overrideLocalValues = true;
2549
2550 15
                if ($entity instanceof NotifyPropertyChanged) {
2551 15
                    $entity->addPropertyChangedListener($this);
2552
                }
2553
            } else {
2554 310
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2555
2556
                // If only a specific entity is set to refresh, check that it's the one
2557 310
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2558 94
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2559
                }
2560
            }
2561
2562 323
            if ($overrideLocalValues) {
2563
                // inject ObjectManager upon refresh.
2564 128
                if ($entity instanceof ObjectManagerAware) {
2565 3
                    $entity->injectObjectManager($this->em, $class);
2566
                }
2567
2568 323
                $this->originalEntityData[$oid] = $data;
2569
            }
2570
        } else {
2571 657
            $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...
2572 657
            $oid    = spl_object_hash($entity);
2573
2574 657
            $this->entityIdentifiers[$oid]  = $id;
2575 657
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2576 657
            $this->originalEntityData[$oid] = $data;
2577
2578 657
            $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...
2579
2580 657
            if ($entity instanceof NotifyPropertyChanged) {
2581 2
                $entity->addPropertyChangedListener($this);
2582
            }
2583
2584 657
            $overrideLocalValues = true;
2585
        }
2586
2587 795
        if ( ! $overrideLocalValues) {
2588 244
            return $entity;
2589
        }
2590
2591 692
        foreach ($data as $field => $value) {
2592 692
            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...
2593 692
                $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...
2594
            }
2595
        }
2596
2597
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2598 692
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2599
2600 692
        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...
2601 4
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2602
        }
2603
2604
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2605 692
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2606 33
            return $entity;
2607
        }
2608
2609 659
        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...
2610
            // Check if the association is not among the fetch-joined associations already.
2611 578
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2612 268
                continue;
2613
            }
2614
2615 556
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2616
2617
            switch (true) {
2618 556
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2619 476
                    if ( ! $assoc['isOwningSide']) {
2620
2621
                        // use the given entity association
2622 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2623
2624 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2625
2626 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...
2627 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...
2628
2629 2
                            continue 2;
2630
                        }
2631
2632
                        // Inverse side of x-to-one can never be lazy
2633 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...
2634
2635 62
                        continue 2;
2636
                    }
2637
2638
                    // use the entity association
2639 476
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2640 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...
2641 37
                        $this->originalEntityData[$oid][$field] = $data[$field];
2642
2643 37
                        continue;
2644
                    }
2645
2646 469
                    $associatedId = array();
2647
2648
                    // TODO: Is this even computed right in all cases of composite keys?
2649 469
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2650 469
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2651
2652 469
                        if ($joinColumnValue !== null) {
2653 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...
2654 11
                                $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
2655
                            } else {
2656 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...
2657
                            }
2658 290
                        } 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...
2659 290
                            && 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...
2660
                        ) {
2661
                            // the missing key is part of target's entity primary key
2662 7
                            $associatedId = array();
2663 469
                            break;
2664
                        }
2665
                    }
2666
2667 469
                    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...
2668
                        // Foreign key is NULL
2669 290
                        $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...
2670 290
                        $this->originalEntityData[$oid][$field] = null;
2671
2672 290
                        continue;
2673
                    }
2674
2675 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...
2676 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...
2677
                    }
2678
2679
                    // Foreign key is set
2680
                    // Check identity map first
2681
                    // FIXME: Can break easily with composite keys if join column values are in
2682
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2683 282
                    $relatedIdHash = implode(' ', $associatedId);
2684
2685
                    switch (true) {
2686 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...
2687 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...
2688
2689
                            // If this is an uninitialized proxy, we are deferring eager loads,
2690
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2691
                            // then we can append this entity for eager loading!
2692 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...
2693 164
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2694 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...
2695 164
                                $newValue instanceof GhostObjectInterface &&
2696 164
                                $newValue->isProxyInitialized() === false) {
2697
2698
                                $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2699
                            }
2700
2701 164
                            break;
2702
2703 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...
2704
                            // If it might be a subtype, it can not be lazy. There isn't even
2705
                            // a way to solve this with deferred eager loading, which means putting
2706
                            // an entity with subclasses at a *-to-one location is really bad! (performance-wise)
2707 30
                            $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
2708 30
                            break;
2709
2710
                        default:
2711
                            switch (true) {
2712
                                // We are negating the condition here. Other cases will assume it is valid!
2713 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...
2714 155
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2715 155
                                    break;
2716
2717
                                // Deferred eager load only works for single identifier classes
2718 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...
2719
                                    // TODO: Is there a faster approach?
2720 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...
2721
2722 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2723 7
                                    break;
2724
2725
                                default:
2726
                                    // TODO: This is very imperformant, ignore it?
2727
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2728
                                    break;
2729
                            }
2730
2731
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2732 162
                            $newValueOid = spl_object_hash($newValue);
2733 162
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2734 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...
2735
2736
                            if (
2737 162
                                $newValue instanceof NotifyPropertyChanged &&
2738 162
                                ( ! $newValue instanceof GhostObjectInterface || $newValue->isProxyInitialized())
2739
                            ) {
2740
                                $newValue->addPropertyChangedListener($this);
2741
                            }
2742 162
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2743
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2744 162
                            break;
2745
                    }
2746
2747 282
                    $this->originalEntityData[$oid][$field] = $newValue;
2748 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...
2749
2750 282
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2751 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...
2752 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...
2753
                    }
2754
2755 282
                    break;
2756
2757
                default:
2758
                    // Ignore if its a cached collection
2759 485
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2760
                        break;
2761
                    }
2762
2763
                    // use the given collection
2764 485
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2765
2766 2
                        $data[$field]->setOwner($entity, $assoc);
2767
2768 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...
2769 2
                        $this->originalEntityData[$oid][$field] = $data[$field];
2770
2771 2
                        break;
2772
                    }
2773
2774
                    // Inject collection
2775 485
                    $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...
2776 485
                    $pColl->setOwner($entity, $assoc);
2777 485
                    $pColl->setInitialized(false);
2778
2779 485
                    $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...
2780 485
                    $reflField->setValue($entity, $pColl);
2781
2782 485
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2783 4
                        $this->loadCollection($pColl);
2784 4
                        $pColl->takeSnapshot();
2785
                    }
2786
2787 485
                    $this->originalEntityData[$oid][$field] = $pColl;
2788 556
                    break;
2789
            }
2790
        }
2791
2792 659
        if ($overrideLocalValues) {
2793
            // defer invoking of postLoad event to hydration complete step
2794 659
            $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...
2795
        }
2796
2797 659
        return $entity;
2798
    }
2799
2800
    /**
2801
     * @return void
2802
     */
2803 855
    public function triggerEagerLoads()
2804
    {
2805 855
        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...
2806 855
            return;
2807
        }
2808
2809
        // avoid infinite recursion
2810 3
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2811 3
        $this->eagerLoadingEntities = array();
2812
2813 3
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2814 3
            if ( ! $ids) {
2815
                continue;
2816
            }
2817
2818 3
            $class = $this->em->getClassMetadata($entityName);
2819
2820 3
            $this->getEntityPersister($entityName)->loadAll(
2821 3
                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...
2822
            );
2823
        }
2824 3
    }
2825
2826
    /**
2827
     * Initializes (loads) an uninitialized persistent collection of an entity.
2828
     *
2829
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2830
     *
2831
     * @return void
2832
     *
2833
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2834
     */
2835 140
    public function loadCollection(PersistentCollection $collection)
2836
    {
2837 140
        $assoc     = $collection->getMapping();
2838 140
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2839
2840 140
        switch ($assoc['type']) {
2841 140
            case ClassMetadata::ONE_TO_MANY:
2842 74
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2843 74
                break;
2844
2845 75
            case ClassMetadata::MANY_TO_MANY:
2846 75
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2847 75
                break;
2848
        }
2849
2850 140
        $collection->setInitialized(true);
2851 140
    }
2852
2853
    /**
2854
     * Gets the identity map of the UnitOfWork.
2855
     *
2856
     * @return array
2857
     */
2858 2
    public function getIdentityMap()
2859
    {
2860 2
        return $this->identityMap;
2861
    }
2862
2863
    /**
2864
     * Gets the original data of an entity. The original data is the data that was
2865
     * present at the time the entity was reconstituted from the database.
2866
     *
2867
     * @param object $entity
2868
     *
2869
     * @return array
2870
     */
2871 114
    public function getOriginalEntityData($entity)
2872
    {
2873 114
        $oid = spl_object_hash($entity);
2874
2875 114
        if (isset($this->originalEntityData[$oid])) {
2876 111
            return $this->originalEntityData[$oid];
2877
        }
2878
2879 4
        return array();
2880
    }
2881
2882
    /**
2883
     * @ignore
2884
     *
2885
     * @param object $entity
2886
     * @param array  $data
2887
     *
2888
     * @return void
2889
     */
2890
    public function setOriginalEntityData($entity, array $data)
2891
    {
2892
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2893
    }
2894
2895
    /**
2896
     * INTERNAL:
2897
     * Sets a property value of the original data array of an entity.
2898
     *
2899
     * @ignore
2900
     *
2901
     * @param string $oid
2902
     * @param string $property
2903
     * @param mixed  $value
2904
     *
2905
     * @return void
2906
     */
2907 323
    public function setOriginalEntityProperty($oid, $property, $value)
2908
    {
2909 323
        $this->originalEntityData[$oid][$property] = $value;
2910 323
    }
2911
2912
    /**
2913
     * Gets the identifier of an entity.
2914
     * The returned value is always an array of identifier values. If the entity
2915
     * has a composite identifier then the identifier values are in the same
2916
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2917
     *
2918
     * @param object $entity
2919
     *
2920
     * @return array The identifier values.
2921
     */
2922 835
    public function getEntityIdentifier($entity)
2923
    {
2924 835
        return $this->entityIdentifiers[spl_object_hash($entity)];
2925
    }
2926
2927
    /**
2928
     * Processes an entity instance to extract their identifier values.
2929
     *
2930
     * @param object $entity The entity instance.
2931
     *
2932
     * @return mixed A scalar value.
2933
     *
2934
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2935
     */
2936 126
    public function getSingleIdentifierValue($entity)
2937
    {
2938 126
        $class = $this->em->getClassMetadata(get_class($entity));
2939
2940 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...
2941
            throw ORMInvalidArgumentException::invalidCompositeIdentifier();
2942
        }
2943
2944 126
        $values = $this->isInIdentityMap($entity)
2945 113
            ? $this->getEntityIdentifier($entity)
2946 126
            : $class->getIdentifierValues($entity);
2947
2948 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...
2949
    }
2950
2951
    /**
2952
     * Tries to find an entity with the given identifier in the identity map of
2953
     * this UnitOfWork.
2954
     *
2955
     * @param mixed  $id            The entity identifier to look for.
2956
     * @param string $rootClassName The name of the root class of the mapped entity hierarchy.
2957
     *
2958
     * @return object|bool Returns the entity with the specified identifier if it exists in
2959
     *                     this UnitOfWork, FALSE otherwise.
2960
     */
2961 513
    public function tryGetById($id, $rootClassName)
2962
    {
2963 513
        $idHash = implode(' ', (array) $id);
2964
2965 513
        if (isset($this->identityMap[$rootClassName][$idHash])) {
2966 76
            return $this->identityMap[$rootClassName][$idHash];
2967
        }
2968
2969 498
        return false;
2970
    }
2971
2972
    /**
2973
     * Schedules an entity for dirty-checking at commit-time.
2974
     *
2975
     * @param object $entity The entity to schedule for dirty-checking.
2976
     *
2977
     * @return void
2978
     *
2979
     * @todo Rename: scheduleForSynchronization
2980
     */
2981 5
    public function scheduleForDirtyCheck($entity)
2982
    {
2983 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...
2984
2985 5
        $this->scheduledForSynchronization[$rootClassName][spl_object_hash($entity)] = $entity;
2986 5
    }
2987
2988
    /**
2989
     * Checks whether the UnitOfWork has any pending insertions.
2990
     *
2991
     * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise.
2992
     */
2993
    public function hasPendingInsertions()
2994
    {
2995
        return ! empty($this->entityInsertions);
2996
    }
2997
2998
    /**
2999
     * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the
3000
     * number of entities in the identity map.
3001
     *
3002
     * @return integer
3003
     */
3004 1
    public function size()
3005
    {
3006
        $countArray = array_map(function ($item) { return count($item); }, $this->identityMap);
3007
3008 1
        return array_sum($countArray);
3009
    }
3010
3011
    /**
3012
     * Gets the EntityPersister for an Entity.
3013
     *
3014
     * @param string $entityName The name of the Entity.
3015
     *
3016
     * @return \Doctrine\ORM\Persisters\Entity\EntityPersister
3017
     */
3018 1059
    public function getEntityPersister($entityName)
3019
    {
3020 1059
        if (isset($this->persisters[$entityName])) {
3021 839
            return $this->persisters[$entityName];
3022
        }
3023
3024 1059
        $class = $this->em->getClassMetadata($entityName);
3025
3026
        switch (true) {
3027 1059
            case ($class->isInheritanceTypeNone()):
3028 1022
                $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...
3029 1022
                break;
3030
3031 357
            case ($class->isInheritanceTypeSingleTable()):
3032 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...
3033 211
                break;
3034
3035 336
            case ($class->isInheritanceTypeJoined()):
3036 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...
3037 336
                break;
3038
3039
            default:
3040
                throw new \RuntimeException('No persister found for entity.');
3041
        }
3042
3043 1059
        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...
3044 118
            $persister = $this->em->getConfiguration()
3045 118
                ->getSecondLevelCacheConfiguration()
3046 118
                ->getCacheFactory()
3047 118
                ->buildCachedEntityPersister($this->em, $persister, $class);
3048
        }
3049
3050 1059
        $this->persisters[$entityName] = $persister;
3051
3052 1059
        return $this->persisters[$entityName];
3053
    }
3054
3055
    /**
3056
     * Gets a collection persister for a collection-valued association.
3057
     *
3058
     * @param array $association
3059
     *
3060
     * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister
3061
     */
3062 562
    public function getCollectionPersister(array $association)
3063
    {
3064 562
        $role = isset($association['cache'])
3065 75
            ? $association['sourceEntity'] . '::' . $association['fieldName']
3066 562
            : $association['type'];
3067
3068 562
        if (isset($this->collectionPersisters[$role])) {
3069 441
            return $this->collectionPersisters[$role];
3070
        }
3071
3072 562
        $persister = ClassMetadata::ONE_TO_MANY === $association['type']
3073 402
            ? new OneToManyPersister($this->em)
3074 562
            : new ManyToManyPersister($this->em);
3075
3076 562
        if ($this->hasCache && isset($association['cache'])) {
3077 74
            $persister = $this->em->getConfiguration()
3078 74
                ->getSecondLevelCacheConfiguration()
3079 74
                ->getCacheFactory()
3080 74
                ->buildCachedCollectionPersister($this->em, $persister, $association);
3081
        }
3082
3083 562
        $this->collectionPersisters[$role] = $persister;
3084
3085 562
        return $this->collectionPersisters[$role];
3086
    }
3087
3088
    /**
3089
     * INTERNAL:
3090
     * Registers an entity as managed.
3091
     *
3092
     * @param object $entity The entity.
3093
     * @param array  $id     The identifier values.
3094
     * @param array  $data   The original entity data.
3095
     *
3096
     * @return void
3097
     */
3098 223
    public function registerManaged($entity, array $id, array $data)
3099
    {
3100 223
        $oid = spl_object_hash($entity);
3101
3102 223
        $this->entityIdentifiers[$oid]  = $id;
3103 223
        $this->entityStates[$oid]       = self::STATE_MANAGED;
3104 223
        $this->originalEntityData[$oid] = $data;
3105
3106 223
        $this->addToIdentityMap($entity);
3107
3108 222
        if ($entity instanceof NotifyPropertyChanged && ( ! $entity instanceof GhostObjectInterface || $entity->isProxyInitialized())) {
3109 2
            $entity->addPropertyChangedListener($this);
3110
        }
3111 222
    }
3112
3113
    /**
3114
     * INTERNAL:
3115
     * Clears the property changeset of the entity with the given OID.
3116
     *
3117
     * @param string $oid The entity's OID.
3118
     *
3119
     * @return void
3120
     */
3121
    public function clearEntityChangeSet($oid)
3122
    {
3123
        $this->entityChangeSets[$oid] = array();
3124
    }
3125
3126
    /* PropertyChangedListener implementation */
3127
3128
    /**
3129
     * Notifies this UnitOfWork of a property change in an entity.
3130
     *
3131
     * @param object $entity       The entity that owns the property.
3132
     * @param string $propertyName The name of the property that changed.
3133
     * @param mixed  $oldValue     The old value of the property.
3134
     * @param mixed  $newValue     The new value of the property.
3135
     *
3136
     * @return void
3137
     */
3138 3
    public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
3139
    {
3140 3
        $oid   = spl_object_hash($entity);
3141 3
        $class = $this->em->getClassMetadata(get_class($entity));
3142
3143 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...
3144
3145 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...
3146 1
            return; // ignore non-persistent fields
3147
        }
3148
3149
        // Update changeset and mark entity for synchronization
3150 3
        $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
3151
3152 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...
3153 3
            $this->scheduleForDirtyCheck($entity);
3154
        }
3155 3
    }
3156
3157
    /**
3158
     * Gets the currently scheduled entity insertions in this UnitOfWork.
3159
     *
3160
     * @return array
3161
     */
3162 2
    public function getScheduledEntityInsertions()
3163
    {
3164 2
        return $this->entityInsertions;
3165
    }
3166
3167
    /**
3168
     * Gets the currently scheduled entity updates in this UnitOfWork.
3169
     *
3170
     * @return array
3171
     */
3172 2
    public function getScheduledEntityUpdates()
3173
    {
3174 2
        return $this->entityUpdates;
3175
    }
3176
3177
    /**
3178
     * Gets the currently scheduled entity deletions in this UnitOfWork.
3179
     *
3180
     * @return array
3181
     */
3182 1
    public function getScheduledEntityDeletions()
3183
    {
3184 1
        return $this->entityDeletions;
3185
    }
3186
3187
    /**
3188
     * Gets the currently scheduled complete collection deletions
3189
     *
3190
     * @return array
3191
     */
3192 1
    public function getScheduledCollectionDeletions()
3193
    {
3194 1
        return $this->collectionDeletions;
3195
    }
3196
3197
    /**
3198
     * Gets the currently scheduled collection inserts, updates and deletes.
3199
     *
3200
     * @return array
3201
     */
3202
    public function getScheduledCollectionUpdates()
3203
    {
3204
        return $this->collectionUpdates;
3205
    }
3206
3207
    /**
3208
     * Helper method to initialize a lazy loading proxy or persistent collection.
3209
     *
3210
     * @param object $obj
3211
     *
3212
     * @return void
3213
     */
3214 2
    public function initializeObject($obj)
3215
    {
3216 2
        if ($obj instanceof GhostObjectInterface) {
3217 1
            $obj->initializeProxy();
3218
3219 1
            return;
3220
        }
3221
3222 1
        if ($obj instanceof PersistentCollection) {
3223 1
            $obj->initialize();
3224
        }
3225 1
    }
3226
3227
    /**
3228
     * Helper method to show an object as string.
3229
     *
3230
     * @param object $obj
3231
     *
3232
     * @return string
3233
     */
3234 1
    private static function objToStr($obj)
3235
    {
3236 1
        return method_exists($obj, '__toString') ? (string) $obj : get_class($obj).'@'.spl_object_hash($obj);
3237
    }
3238
3239
    /**
3240
     * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit().
3241
     *
3242
     * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information
3243
     * on this object that might be necessary to perform a correct update.
3244
     *
3245
     * @param object $object
3246
     *
3247
     * @return void
3248
     *
3249
     * @throws ORMInvalidArgumentException
3250
     */
3251 6
    public function markReadOnly($object)
3252
    {
3253 6
        if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
3254 1
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3255
        }
3256
3257 5
        $this->readOnlyObjects[spl_object_hash($object)] = true;
3258 5
    }
3259
3260
    /**
3261
     * Is this entity read only?
3262
     *
3263
     * @param object $object
3264
     *
3265
     * @return bool
3266
     *
3267
     * @throws ORMInvalidArgumentException
3268
     */
3269 3
    public function isReadOnly($object)
3270
    {
3271 3
        if ( ! is_object($object)) {
3272
            throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
3273
        }
3274
3275 3
        return isset($this->readOnlyObjects[spl_object_hash($object)]);
3276
    }
3277
3278
    /**
3279
     * Perform whatever processing is encapsulated here after completion of the transaction.
3280
     */
3281 992
    private function afterTransactionComplete()
3282
    {
3283
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3284 88
            $persister->afterTransactionComplete();
3285 992
        });
3286 992
    }
3287
3288
    /**
3289
     * Perform whatever processing is encapsulated here after completion of the rolled-back.
3290
     */
3291
    private function afterTransactionRolledBack()
3292
    {
3293 11
        $this->performCallbackOnCachedPersister(function (CachedPersister $persister) {
3294 3
            $persister->afterTransactionRolledBack();
3295 11
        });
3296 11
    }
3297
3298
    /**
3299
     * Performs an action after the transaction.
3300
     *
3301
     * @param callable $callback
3302
     */
3303 997
    private function performCallbackOnCachedPersister(callable $callback)
3304
    {
3305 997
        if ( ! $this->hasCache) {
3306 909
            return;
3307
        }
3308
3309 88
        foreach (array_merge($this->persisters, $this->collectionPersisters) as $persister) {
3310 88
            if ($persister instanceof CachedPersister) {
3311 88
                $callback($persister);
3312
            }
3313
        }
3314 88
    }
3315
3316 1001
    private function dispatchOnFlushEvent()
3317
    {
3318 1001
        if ($this->evm->hasListeners(Events::onFlush)) {
3319 4
            $this->evm->dispatchEvent(Events::onFlush, new OnFlushEventArgs($this->em));
3320
        }
3321 1001
    }
3322
3323 996
    private function dispatchPostFlushEvent()
3324
    {
3325 996
        if ($this->evm->hasListeners(Events::postFlush)) {
3326 5
            $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
3327
        }
3328 995
    }
3329
3330
    /**
3331
     * Verifies if two given entities actually are the same based on identifier comparison
3332
     *
3333
     * @param object $entity1
3334
     * @param object $entity2
3335
     *
3336
     * @return bool
3337
     */
3338 42
    private function isIdentifierEquals($entity1, $entity2)
3339
    {
3340 42
        if ($entity1 === $entity2) {
3341
            return true;
3342
        }
3343
3344 42
        $class = $this->em->getClassMetadata(get_class($entity1));
3345
3346 42
        if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
3347 37
            return false;
3348
        }
3349
3350 5
        $oid1 = spl_object_hash($entity1);
3351 5
        $oid2 = spl_object_hash($entity2);
3352
3353 5
        $id1 = isset($this->entityIdentifiers[$oid1])
3354 5
            ? $this->entityIdentifiers[$oid1]
3355 5
            : $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...
3356 5
        $id2 = isset($this->entityIdentifiers[$oid2])
3357 5
            ? $this->entityIdentifiers[$oid2]
3358 5
            : $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...
3359
3360 5
        return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
3361
    }
3362
3363
    /**
3364
     * @param object $entity
3365
     * @param object $managedCopy
3366
     *
3367
     * @throws ORMException
3368
     * @throws OptimisticLockException
3369
     * @throws TransactionRequiredException
3370
     */
3371 33
    private function mergeEntityStateIntoManagedCopy($entity, $managedCopy)
3372
    {
3373 33
        $class = $this->em->getClassMetadata(get_class($entity));
3374
3375 33
        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...
3376 33
            $name = $prop->name;
3377
3378 33
            $prop->setAccessible(true);
3379
3380 33
            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...
3381 33
                if ( ! $class->isIdentifier($name)) {
3382 33
                    $prop->setValue($managedCopy, $prop->getValue($entity));
3383
                }
3384
            } else {
3385 29
                $assoc2 = $class->associationMappings[$name];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3386
3387 29
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3388 23
                    $other = $prop->getValue($entity);
3389 23
                    if ($other === null) {
3390 11
                        $prop->setValue($managedCopy, null);
3391
                    } else {
3392 15
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ORM\Proxy does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
3393
                            // do not merge fields marked lazy that have not been fetched.
3394
                            continue;
3395
                        }
3396
3397 15
                        if ( ! $assoc2['isCascadeMerge']) {
3398 9
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3399 4
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3400 4
                                $relatedId   = $targetClass->getIdentifierValues($other);
3401
3402 4
                                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...
3403 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...
3404
                                } else {
3405 2
                                    $other = $this->em->getProxyFactory()->getProxy(
3406 2
                                        $assoc2['targetEntity'],
3407
                                        $relatedId
3408
                                    );
3409 2
                                    $this->registerManaged($other, $relatedId, array());
3410
                                }
3411
                            }
3412
3413 23
                            $prop->setValue($managedCopy, $other);
3414
                        }
3415
                    }
3416
                } else {
3417 18
                    $mergeCol = $prop->getValue($entity);
3418
3419 18
                    if ($mergeCol instanceof PersistentCollection && ! $mergeCol->isInitialized()) {
3420
                        // do not merge fields marked lazy that have not been fetched.
3421
                        // keep the lazy persistent collection of the managed copy.
3422 7
                        continue;
3423
                    }
3424
3425 13
                    $managedCol = $prop->getValue($managedCopy);
3426
3427 13
                    if ( ! $managedCol) {
3428 3
                        $managedCol = new PersistentCollection(
3429 3
                            $this->em,
3430 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...
3431 3
                            new ArrayCollection
3432
                        );
3433 3
                        $managedCol->setOwner($managedCopy, $assoc2);
3434 3
                        $prop->setValue($managedCopy, $managedCol);
3435
3436 3
                        $this->originalEntityData[spl_object_hash($entity)][$name] = $managedCol;
3437
                    }
3438
3439 13
                    if ($assoc2['isCascadeMerge']) {
3440 8
                        $managedCol->initialize();
3441
3442
                        // clear and set dirty a managed collection if its not also the same collection to merge from.
3443 8
                        if ( ! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
3444 1
                            $managedCol->unwrap()->clear();
3445 1
                            $managedCol->setDirty(true);
3446
3447 1
                            if ($assoc2['isOwningSide']
3448 1
                                && $assoc2['type'] == ClassMetadata::MANY_TO_MANY
3449 1
                                && $class->isChangeTrackingNotify()
3450
                            ) {
3451
                                $this->scheduleForDirtyCheck($managedCopy);
3452
                            }
3453
                        }
3454
                    }
3455
                }
3456
            }
3457
3458 33
            if ($class->isChangeTrackingNotify()) {
3459
                // Just treat all properties as changed, there is no other choice.
3460 33
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
3461
            }
3462
        }
3463 33
    }
3464
3465
    /**
3466
     * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
3467
     * Unit of work able to fire deferred events, related to loading events here.
3468
     *
3469
     * @internal should be called internally from object hydrators
3470
     */
3471 867
    public function hydrationComplete()
3472
    {
3473 867
        $this->hydrationCompleteHandler->hydrationComplete();
3474 867
    }
3475
}
3476