Completed
Pull Request — master (#6017)
by Jeremy
12:19
created

UnitOfWork   F

Complexity

Total Complexity 500

Size/Duplication

Total Lines 3425
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 38

Test Coverage

Coverage 93.1%

Importance

Changes 0
Metric Value
wmc 500
lcom 1
cbo 38
dl 0
loc 3425
ccs 1147
cts 1232
cp 0.931
rs 0.5217
c 0
b 0
f 0

94 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
F commit() 0 110 26
A computeScheduleInsertsChangeSets() 0 8 2
C computeSingleEntityChangeSet() 0 33 11
A executeExtraUpdates() 0 11 2
A getEntityChangeSet() 0 11 2
F computeChangeSet() 0 183 44
C computeChangeSets() 0 45 11
C computeAssociationChanges() 0 60 14
B persistNew() 0 27 4
C recomputeSingleEntityChangeSet() 0 52 17
C executeInserts() 0 47 7
B executeUpdates() 0 29 6
B executeDeletions() 0 32 5
C getCommitOrder() 0 67 12
C scheduleForInsert() 0 29 8
A isScheduledForInsert() 0 4 1
B scheduleForUpdate() 0 16 5
A scheduleExtraUpdate() 0 13 2
A isScheduledForUpdate() 0 4 1
A isScheduledForDirtyCheck() 0 6 1
B scheduleForDelete() 0 27 5
A isScheduledForDelete() 0 4 1
A isEntityScheduled() 0 8 3
A addToIdentityMap() 0 20 4
C getEntityState() 0 69 13
A removeFromIdentityMap() 0 23 3
A getByIdHash() 0 4 1
A tryGetByIdHash() 0 8 2
A isInIdentityMap() 0 13 2
A containsIdHash() 0 4 1
A persist() 0 6 1
C doPersist() 0 48 7
A remove() 0 6 1
C doRemove() 0 40 7
A merge() 0 6 1
F doMerge() 0 102 19
A isLoaded() 0 4 2
A updateAssociationWithMergedEntity() 0 20 3
A detach() 0 6 1
C doDetach() 0 34 7
A refresh() 0 6 1
A doRefresh() 0 23 3
C cascadeRefresh() 0 34 7
C cascadeDetach() 0 34 7
C cascadeMerge() 0 30 7
C cascadePersist() 0 51 9
D cascadeRemove() 0 40 9
C lock() 0 53 13
A getCommitOrderCalculator() 0 4 1
B clear() 0 31 5
A scheduleOrphanRemoval() 0 4 1
A cancelOrphanRemoval() 0 4 1
A scheduleCollectionDeletion() 0 10 1
A isCollectionScheduledForDeletion() 0 4 1
A newInstance() 0 10 2
F createEntity() 0 284 61
B triggerEagerLoads() 0 22 4
A loadCollection() 0 17 3
A getIdentityMap() 0 4 1
A getOriginalEntityData() 0 8 2
A setOriginalEntityData() 0 4 1
A setOriginalEntityProperty() 0 4 1
A getEntityIdentifier() 0 4 1
A getSingleIdentifierValue() 0 14 4
A tryGetById() 0 8 2
A scheduleForDirtyCheck() 0 6 1
A hasPendingInsertions() 0 4 1
A size() 0 6 1
C getEntityPersister() 0 36 7
B getCollectionPersister() 0 25 6
A registerManaged() 0 14 4
A clearEntityChangeSet() 0 4 1
A propertyChanged() 0 18 4
A getScheduledEntityInsertions() 0 4 1
A getScheduledEntityUpdates() 0 4 1
A getScheduledEntityDeletions() 0 4 1
A getScheduledCollectionDeletions() 0 4 1
A getScheduledCollectionUpdates() 0 4 1
A initializeObject() 0 12 3
A objToStr() 0 4 2
A markReadOnly() 0 8 3
A isReadOnly() 0 8 2
A afterTransactionComplete() 0 6 1
A afterTransactionRolledBack() 0 6 1
A performCallbackOnCachedPersister() 0 12 4
A dispatchOnFlushEvent() 0 6 2
A dispatchPostFlushEvent() 0 6 2
B isIdentifierEquals() 0 24 6
D mergeEntityStateIntoManagedCopy() 0 91 21
A hydrationComplete() 0 4 1
A clearIdentityMapForEntityName() 0 12 3
A clearEntityInsertionsForEntityName() 0 9 4
A convertSingleFieldIdentifierToPHPValue() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like UnitOfWork often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UnitOfWork, and based on these observations, apply Extract Interface, too.

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\Collections\ArrayCollection;
23
use Doctrine\Common\Collections\Collection;
24
use Doctrine\Common\NotifyPropertyChanged;
25
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
26
use Doctrine\Common\Persistence\ObjectManagerAware;
27
use Doctrine\Common\PropertyChangedListener;
28
use Doctrine\DBAL\LockMode;
29
use Doctrine\ORM\Cache\Persister\CachedPersister;
30
use Doctrine\ORM\Event\LifecycleEventArgs;
31
use Doctrine\ORM\Event\ListenersInvoker;
32
use Doctrine\ORM\Event\OnFlushEventArgs;
33
use Doctrine\ORM\Event\PostFlushEventArgs;
34
use Doctrine\ORM\Event\PreFlushEventArgs;
35
use Doctrine\ORM\Event\PreUpdateEventArgs;
36
use Doctrine\ORM\Internal\HydrationCompleteHandler;
37
use Doctrine\ORM\Mapping\ClassMetadata;
38
use Doctrine\ORM\Mapping\Reflection\ReflectionPropertiesGetter;
39
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
40
use Doctrine\ORM\Persisters\Collection\OneToManyPersister;
41
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
42
use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
43
use Doctrine\ORM\Persisters\Entity\SingleTablePersister;
44
use Doctrine\ORM\Proxy\Proxy;
45
use Doctrine\ORM\Utility\IdentifierFlattener;
46
use Exception;
47
use InvalidArgumentException;
48
use UnexpectedValueException;
49
50
/**
51
 * The UnitOfWork is responsible for tracking changes to objects during an
52
 * "object-level" transaction and for writing out changes to the database
53
 * in the correct order.
54
 *
55
 * Internal note: This class contains highly performance-sensitive code.
56
 *
57
 * @since       2.0
58
 * @author      Benjamin Eberlei <[email protected]>
59
 * @author      Guilherme Blanco <[email protected]>
60
 * @author      Jonathan Wage <[email protected]>
61
 * @author      Roman Borschel <[email protected]>
62
 * @author      Rob Caiger <[email protected]>
63
 */
64
class UnitOfWork implements PropertyChangedListener
65
{
66
    /**
67
     * An entity is in MANAGED state when its persistence is managed by an EntityManager.
68
     */
69
    const STATE_MANAGED = 1;
70
71
    /**
72
     * An entity is new if it has just been instantiated (i.e. using the "new" operator)
73
     * and is not (yet) managed by an EntityManager.
74
     */
75
    const STATE_NEW = 2;
76
77
    /**
78
     * A detached entity is an instance with persistent state and identity that is not
79
     * (or no longer) associated with an EntityManager (and a UnitOfWork).
80
     */
81
    const STATE_DETACHED = 3;
82
83
    /**
84
     * A removed entity instance is an instance with a persistent identity,
85
     * associated with an EntityManager, whose persistent state will be deleted
86
     * on commit.
87
     */
88
    const STATE_REMOVED = 4;
89
90
    /**
91
     * Hint used to collect all primary keys of associated entities during hydration
92
     * and execute it in a dedicated query afterwards
93
     * @see https://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html?highlight=eager#temporarily-change-fetch-mode-in-dql
94
     */
95
    const HINT_DEFEREAGERLOAD = 'deferEagerLoad';
96
97
    /**
98
     * The identity map that holds references to all managed entities that have
99
     * an identity. The entities are grouped by their class name.
100
     * Since all classes in a hierarchy must share the same identifier set,
101
     * we always take the root class name of the hierarchy.
102
     *
103
     * @var array
104
     */
105
    private $identityMap = array();
106
107
    /**
108
     * Map of all identifiers of managed entities.
109
     * Keys are object ids (spl_object_hash).
110
     *
111
     * @var array
112
     */
113
    private $entityIdentifiers = array();
114
115
    /**
116
     * Map of the original entity data of managed entities.
117
     * Keys are object ids (spl_object_hash). This is used for calculating changesets
118
     * at commit time.
119
     *
120
     * Internal note: Note that PHPs "copy-on-write" behavior helps a lot with memory usage.
121
     *                A value will only really be copied if the value in the entity is modified
122
     *                by the user.
123
     *
124
     * @var array
125
     */
126
    private $originalEntityData = array();
127
128
    /**
129
     * Map of entity changes. Keys are object ids (spl_object_hash).
130
     * Filled at the beginning of a commit of the UnitOfWork and cleaned at the end.
131
     *
132
     * @var array
133
     */
134
    private $entityChangeSets = array();
135
136
    /**
137
     * The (cached) states of any known entities.
138
     * Keys are object ids (spl_object_hash).
139
     *
140
     * @var array
141
     */
142
    private $entityStates = array();
143
144
    /**
145
     * Map of entities that are scheduled for dirty checking at commit time.
146
     * This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT.
147
     * Keys are object ids (spl_object_hash).
148
     *
149
     * @var array
150
     */
151
    private $scheduledForSynchronization = array();
152
153
    /**
154
     * A list of all pending entity insertions.
155
     *
156
     * @var array
157
     */
158
    private $entityInsertions = array();
159
160
    /**
161
     * A list of all pending entity updates.
162
     *
163
     * @var array
164
     */
165
    private $entityUpdates = array();
166
167
    /**
168
     * Any pending extra updates that have been scheduled by persisters.
169
     *
170
     * @var array
171
     */
172
    private $extraUpdates = array();
173
174
    /**
175
     * A list of all pending entity deletions.
176
     *
177
     * @var array
178
     */
179
    private $entityDeletions = array();
180
181
    /**
182
     * All pending collection deletions.
183
     *
184
     * @var array
185
     */
186
    private $collectionDeletions = array();
187
188
    /**
189
     * All pending collection updates.
190
     *
191
     * @var array
192
     */
193
    private $collectionUpdates = array();
194
195
    /**
196
     * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork.
197
     * At the end of the UnitOfWork all these collections will make new snapshots
198
     * of their data.
199
     *
200
     * @var array
201
     */
202
    private $visitedCollections = array();
203
204
    /**
205
     * The EntityManager that "owns" this UnitOfWork instance.
206
     *
207
     * @var EntityManagerInterface
208
     */
209
    private $em;
210
211
    /**
212
     * The entity persister instances used to persist entity instances.
213
     *
214
     * @var array
215
     */
216
    private $persisters = array();
217
218
    /**
219
     * The collection persister instances used to persist collections.
220
     *
221
     * @var array
222
     */
223
    private $collectionPersisters = array();
224
225
    /**
226
     * The EventManager used for dispatching events.
227
     *
228
     * @var \Doctrine\Common\EventManager
229
     */
230
    private $evm;
231
232
    /**
233
     * The ListenersInvoker used for dispatching events.
234
     *
235
     * @var \Doctrine\ORM\Event\ListenersInvoker
236
     */
237
    private $listenersInvoker;
238
239
    /**
240
     * The IdentifierFlattener used for manipulating identifiers
241
     *
242
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
243
     */
244
    private $identifierFlattener;
245
246
    /**
247
     * Orphaned entities that are scheduled for removal.
248
     *
249
     * @var array
250
     */
251
    private $orphanRemovals = array();
252
253
    /**
254
     * Read-Only objects are never evaluated
255
     *
256
     * @var array
257
     */
258
    private $readOnlyObjects = array();
259
260
    /**
261
     * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
262
     *
263
     * @var array
264
     */
265
    private $eagerLoadingEntities = array();
266
267
    /**
268
     * @var boolean
269
     */
270
    protected $hasCache = false;
271
272
    /**
273
     * Helper for handling completion of hydration
274
     *
275
     * @var HydrationCompleteHandler
276
     */
277
    private $hydrationCompleteHandler;
278
279
    /**
280
     * @var ReflectionPropertiesGetter
281
     */
282
    private $reflectionPropertiesGetter;
283
284
    /**
285
     * Initializes a new UnitOfWork instance, bound to the given EntityManager.
286
     *
287
     * @param EntityManagerInterface $em
288
     */
289 2358
    public function __construct(EntityManagerInterface $em)
290
    {
291 2358
        $this->em                         = $em;
292 2358
        $this->evm                        = $em->getEventManager();
293 2358
        $this->listenersInvoker           = new ListenersInvoker($em);
294 2358
        $this->hasCache                   = $em->getConfiguration()->isSecondLevelCacheEnabled();
295 2358
        $this->identifierFlattener        = new IdentifierFlattener($this, $em->getMetadataFactory());
296 2358
        $this->hydrationCompleteHandler   = new HydrationCompleteHandler($this->listenersInvoker, $em);
297 2358
        $this->reflectionPropertiesGetter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
298 2358
    }
299
300
    /**
301
     * Commits the UnitOfWork, executing all operations that have been postponed
302
     * up to this point. The state of all managed entities will be synchronized with
303
     * the database.
304
     *
305
     * The operations are executed in the following order:
306
     *
307
     * 1) All entity insertions
308
     * 2) All entity updates
309
     * 3) All collection deletions
310
     * 4) All collection updates
311
     * 5) All entity deletions
312
     *
313
     * @param null|object|array $entity
314
     *
315
     * @return void
316
     *
317
     * @throws \Exception
318
     */
319 1024
    public function commit($entity = null)
320
    {
321
        // Raise preFlush
322 1024
        if ($this->evm->hasListeners(Events::preFlush)) {
323 2
            $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em));
324
        }
325
326
        // Compute changes done since last commit.
327 1024
        if ($entity === null) {
328 1016
            $this->computeChangeSets();
329 16
        } elseif (is_object($entity)) {
330 15
            $this->computeSingleEntityChangeSet($entity);
331 1
        } elseif (is_array($entity)) {
332 1
            foreach ($entity as $object) {
333 1
                $this->computeSingleEntityChangeSet($object);
334
            }
335
        }
336
337 1021
        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...
338 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...
339 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...
340 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...
341 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...
342 1021
                $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...
343 25
            $this->dispatchOnFlushEvent();
344 25
            $this->dispatchPostFlushEvent();
345
346 25
            return; // Nothing to do.
347
        }
348
349 1017
        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...
350 16
            foreach ($this->orphanRemovals as $orphan) {
351 16
                $this->remove($orphan);
352
            }
353
        }
354
355 1017
        $this->dispatchOnFlushEvent();
356
357
        // Now we need a commit order to maintain referential integrity
358 1017
        $commitOrder = $this->getCommitOrder();
359
360 1017
        $conn = $this->em->getConnection();
361 1017
        $conn->beginTransaction();
362
363
        try {
364
            // Collection deletions (deletions of complete collections)
365 1017
            foreach ($this->collectionDeletions as $collectionToDelete) {
366 19
                $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
367
            }
368
369 1017
            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...
370 1013
                foreach ($commitOrder as $class) {
371 1013
                    $this->executeInserts($class);
372
                }
373
            }
374
375 1016
            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...
376 116
                foreach ($commitOrder as $class) {
377 116
                    $this->executeUpdates($class);
378
                }
379
            }
380
381
            // Extra updates that were requested by persisters.
382 1012
            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...
383 40
                $this->executeExtraUpdates();
384
            }
385
386
            // Collection updates (deleteRows, updateRows, insertRows)
387 1012
            foreach ($this->collectionUpdates as $collectionToUpdate) {
388 533
                $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate);
389
            }
390
391
            // Entity deletions come last and need to be in reverse commit order
392 1012
            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...
393 63
                for ($count = count($commitOrder), $i = $count - 1; $i >= 0 && $this->entityDeletions; --$i) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityDeletions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
394 63
                    $this->executeDeletions($commitOrder[$i]);
395
                }
396
            }
397
398 1012
            $conn->commit();
399 11
        } catch (Exception $e) {
400 11
            $this->em->close();
401 11
            $conn->rollBack();
402
403 11
            $this->afterTransactionRolledBack();
404
405 11
            throw $e;
406
        }
407
408 1012
        $this->afterTransactionComplete();
409
410
        // Take new snapshots from visited collections
411 1012
        foreach ($this->visitedCollections as $coll) {
412 532
            $coll->takeSnapshot();
413
        }
414
415 1012
        $this->dispatchPostFlushEvent();
416
417
        // Clear up
418 1011
        $this->entityInsertions =
419 1011
        $this->entityUpdates =
420 1011
        $this->entityDeletions =
421 1011
        $this->extraUpdates =
422 1011
        $this->entityChangeSets =
423 1011
        $this->collectionUpdates =
424 1011
        $this->collectionDeletions =
425 1011
        $this->visitedCollections =
426 1011
        $this->scheduledForSynchronization =
427 1011
        $this->orphanRemovals = array();
428 1011
    }
429
430
    /**
431
     * Computes the changesets of all entities scheduled for insertion.
432
     *
433
     * @return void
434
     */
435 1023
    private function computeScheduleInsertsChangeSets()
436
    {
437 1023
        foreach ($this->entityInsertions as $entity) {
438 1015
            $class = $this->em->getClassMetadata(get_class($entity));
439
440 1015
            $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...
441
        }
442 1021
    }
443
444
    /**
445
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
446
     *
447
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
448
     * 2. Read Only entities are skipped.
449
     * 3. Proxies are skipped.
450
     * 4. Only if entity is properly managed.
451
     *
452
     * @param object $entity
453
     *
454
     * @return void
455
     *
456
     * @throws \InvalidArgumentException
457
     */
458 16
    private function computeSingleEntityChangeSet($entity)
459
    {
460 16
        $state = $this->getEntityState($entity);
461
462 16
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
463 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
464
        }
465
466 15
        $class = $this->em->getClassMetadata(get_class($entity));
467
468 15
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
469 14
            $this->persist($entity);
470
        }
471
472
        // Compute changes for INSERTed entities first. This must always happen even in this case.
473 15
        $this->computeScheduleInsertsChangeSets();
474
475 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...
476
            return;
477
        }
478
479
        // Ignore uninitialized proxy objects
480 15
        if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

Loading history...
576
        }
577
578 1025
        $actualData = array();
579
580 1025
        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...
581 1025
            $value = $refProp->getValue($entity);
582
583 1025
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
584 781
                if ($value instanceof PersistentCollection) {
585 201
                    if ($value->getOwner() === $entity) {
586 201
                        continue;
587
                    }
588
589 5
                    $value = new ArrayCollection($value->getValues());
590
                }
591
592
                // If $value is not a Collection then use an ArrayCollection.
593 776
                if ( ! $value instanceof Collection) {
594 242
                    $value = new ArrayCollection($value);
595
                }
596
597 776
                $assoc = $class->associationMappings[$name];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
726 640
                continue;
727
            }
728
729 869
            $this->computeAssociationChanges($assoc, $val);
730
731 861
            if ( ! isset($this->entityChangeSets[$oid]) &&
732 861
                $assoc['isOwningSide'] &&
733 861
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
734 861
                $val instanceof PersistentCollection &&
735 861
                $val->isDirty()) {
736
737 35
                $this->entityChangeSets[$oid]   = array();
738 35
                $this->originalEntityData[$oid] = $actualData;
739 861
                $this->entityUpdates[$oid]      = $entity;
740
            }
741
        }
742 1017
    }
743
744
    /**
745
     * Computes all the changes that have been done to entities and collections
746
     * since the last commit and stores these changes in the _entityChangeSet map
747
     * temporarily for access by the persisters, until the UoW commit is finished.
748
     *
749
     * @return void
750
     */
751 1016
    public function computeChangeSets()
752
    {
753
        // Compute changes for INSERTed entities first. This must always happen.
754 1016
        $this->computeScheduleInsertsChangeSets();
755
756
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
757 1014
        foreach ($this->identityMap as $className => $entities) {
758 451
            $class = $this->em->getClassMetadata($className);
759
760
            // Skip class if instances are read-only
761 451
            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...
762 1
                continue;
763
            }
764
765
            // If change tracking is explicit or happens through notification, then only compute
766
            // changes on entities of that type that are explicitly marked for synchronization.
767
            switch (true) {
768 450
                case ($class->isChangeTrackingDeferredImplicit()):
769 448
                    $entitiesToProcess = $entities;
770 448
                    break;
771
772 3
                case (isset($this->scheduledForSynchronization[$className])):
773 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
774 3
                    break;
775
776
                default:
777 1
                    $entitiesToProcess = array();
778
779
            }
780
781 450
            foreach ($entitiesToProcess as $entity) {
782
                // Ignore uninitialized proxy objects
783 430
                if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
784 36
                    continue;
785
                }
786
787
                // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here.
788 429
                $oid = spl_object_hash($entity);
789
790 429
                if ( ! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) {
791 450
                    $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...
792
                }
793
            }
794
        }
795 1014
    }
796
797
    /**
798
     * Computes the changes of an association.
799
     *
800
     * @param array $assoc The association mapping.
801
     * @param mixed $value The value of the association.
802
     *
803
     * @throws ORMInvalidArgumentException
804
     * @throws ORMException
805
     *
806
     * @return void
807
     */
808 869
    private function computeAssociationChanges($assoc, $value)
809
    {
810 869
        if ($value instanceof Proxy && ! $value->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
811 29
            return;
812
        }
813
814 868
        if ($value instanceof PersistentCollection && $value->isDirty()) {
815 535
            $coid = spl_object_hash($value);
816
817 535
            $this->collectionUpdates[$coid] = $value;
818 535
            $this->visitedCollections[$coid] = $value;
819
        }
820
821
        // Look through the entities, and in any of their associations,
822
        // for transient (new) entities, recursively. ("Persistence by reachability")
823
        // Unwrap. Uninitialized collections will simply be empty.
824 868
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
825 868
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
826
827 868
        foreach ($unwrappedValue as $key => $entry) {
828 724
            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...
829 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...
830
            }
831
832 718
            $state = $this->getEntityState($entry, self::STATE_NEW);
833
834 718
            if ( ! ($entry instanceof $assoc['targetEntity'])) {
835
                throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']);
836
            }
837
838
            switch ($state) {
839 718
                case self::STATE_NEW:
840 39
                    if ( ! $assoc['isCascadePersist']) {
841 4
                        throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
842
                    }
843
844 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...
845 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...
846 35
                    break;
847
848 712
                case self::STATE_REMOVED:
849
                    // Consume the $value as array (it's either an array or an ArrayAccess)
850
                    // and remove the element from Collection.
851 4
                    if ($assoc['type'] & ClassMetadata::TO_MANY) {
852 3
                        unset($value[$key]);
853
                    }
854 4
                    break;
855
856 712
                case self::STATE_DETACHED:
857
                    // Can actually not happen right now as we assume STATE_NEW,
858
                    // so the exception will be raised from the DBAL layer (constraint violation).
859
                    throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
860
                    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...
861
862 715
                default:
863
                    // MANAGED associated entities are already taken into account
864
                    // during changeset calculation anyway, since they are in the identity map.
865
            }
866
        }
867 860
    }
868
869
    /**
870
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
871
     * @param object                              $entity
872
     *
873
     * @return void
874
     */
875 1041
    private function persistNew($class, $entity)
876
    {
877 1041
        $oid    = spl_object_hash($entity);
878 1041
        $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist);
879
880 1041
        if ($invoke !== ListenersInvoker::INVOKE_NONE) {
881 139
            $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
882
        }
883
884 1041
        $idGen = $class->idGenerator;
885
886 1041
        if ( ! $idGen->isPostInsertGenerator()) {
887 269
            $idValue = $idGen->generate($this->em, $entity);
0 ignored issues
show
Compatibility introduced by
$this->em of type object<Doctrine\ORM\EntityManagerInterface> is not a sub-type of object<Doctrine\ORM\EntityManager>. It seems like you assume a concrete implementation of the interface Doctrine\ORM\EntityManagerInterface to be always present.

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1452 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...
1453
        }
1454
1455
        switch (true) {
1456 10
            case ($class->isIdentifierNatural()):
0 ignored issues
show
Bug introduced by
The method isIdentifierNatural() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. Did you maybe mean isIdentifier()?

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

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

Loading history...
1457
                // Check for a version field, if available, to avoid a db lookup.
1458 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...
1459 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...
1460
                        ? self::STATE_DETACHED
1461 1
                        : self::STATE_NEW;
1462
                }
1463
1464
                // Last try before db lookup: check the identity map.
1465 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...
1466 1
                    return self::STATE_DETACHED;
1467
                }
1468
1469
                // db lookup
1470 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...
1471
                    return self::STATE_DETACHED;
1472
                }
1473
1474 4
                return self::STATE_NEW;
1475
1476 5
            case ( ! $class->idGenerator->isPostInsertGenerator()):
0 ignored issues
show
Bug introduced by
Accessing idGenerator on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1477
                // if we have a pre insert generator we can't be sure that having an id
1478
                // really means that the entity exists. We have to verify this through
1479
                // the last resort: a db lookup
1480
1481
                // Last try before db lookup: check the identity map.
1482
                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...
1483
                    return self::STATE_DETACHED;
1484
                }
1485
1486
                // db lookup
1487
                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...
1488
                    return self::STATE_DETACHED;
1489
                }
1490
1491
                return self::STATE_NEW;
1492
1493
            default:
1494 5
                return self::STATE_DETACHED;
1495
        }
1496
    }
1497
1498
    /**
1499
     * INTERNAL:
1500
     * Removes an entity from the identity map. This effectively detaches the
1501
     * entity from the persistence management of Doctrine.
1502
     *
1503
     * @ignore
1504
     *
1505
     * @param object $entity
1506
     *
1507
     * @return boolean
1508
     *
1509
     * @throws ORMInvalidArgumentException
1510
     */
1511 77
    public function removeFromIdentityMap($entity)
1512
    {
1513 77
        $oid           = spl_object_hash($entity);
1514 77
        $classMetadata = $this->em->getClassMetadata(get_class($entity));
1515 77
        $idHash        = implode(' ', $this->entityIdentifiers[$oid]);
1516
1517 77
        if ($idHash === '') {
1518
            throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
1519
        }
1520
1521 77
        $className = $classMetadata->rootEntityName;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1591
    }
1592
1593
    /**
1594
     * INTERNAL:
1595
     * Checks whether an identifier hash exists in the identity map.
1596
     *
1597
     * @ignore
1598
     *
1599
     * @param string $idHash
1600
     * @param string $rootClassName
1601
     *
1602
     * @return boolean
1603
     */
1604
    public function containsIdHash($idHash, $rootClassName)
1605
    {
1606
        return isset($this->identityMap[$rootClassName][$idHash]);
1607
    }
1608
1609
    /**
1610
     * Persists an entity as part of the current unit of work.
1611
     *
1612
     * @param object $entity The entity to persist.
1613
     *
1614
     * @return void
1615
     */
1616 1038
    public function persist($entity)
1617
    {
1618 1038
        $visited = array();
1619
1620 1038
        $this->doPersist($entity, $visited);
1621 1031
    }
1622
1623
    /**
1624
     * Persists an entity as part of the current unit of work.
1625
     *
1626
     * This method is internally called during persist() cascades as it tracks
1627
     * the already visited entities to prevent infinite recursions.
1628
     *
1629
     * @param object $entity  The entity to persist.
1630
     * @param array  $visited The already visited entities.
1631
     *
1632
     * @return void
1633
     *
1634
     * @throws ORMInvalidArgumentException
1635
     * @throws UnexpectedValueException
1636
     */
1637 1038
    private function doPersist($entity, array &$visited)
1638
    {
1639 1038
        $oid = spl_object_hash($entity);
1640
1641 1038
        if (isset($visited[$oid])) {
1642 109
            return; // Prevent infinite recursion
1643
        }
1644
1645 1038
        $visited[$oid] = $entity; // Mark visited
1646
1647 1038
        $class = $this->em->getClassMetadata(get_class($entity));
1648
1649
        // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
1650
        // If we would detect DETACHED here we would throw an exception anyway with the same
1651
        // consequences (not recoverable/programming error), so just assuming NEW here
1652
        // lets us avoid some database lookups for entities with natural identifiers.
1653 1038
        $entityState = $this->getEntityState($entity, self::STATE_NEW);
1654
1655
        switch ($entityState) {
1656 1038
            case self::STATE_MANAGED:
1657
                // Nothing to do, except if policy is "deferred explicit"
1658 234
                if ($class->isChangeTrackingDeferredExplicit()) {
1659 2
                    $this->scheduleForDirtyCheck($entity);
1660
                }
1661 234
                break;
1662
1663 1038
            case self::STATE_NEW:
1664 1037
                $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...
1665 1037
                break;
1666
1667 1
            case self::STATE_REMOVED:
1668
                // Entity becomes managed again
1669 1
                unset($this->entityDeletions[$oid]);
1670 1
                $this->addToIdentityMap($entity);
1671
1672 1
                $this->entityStates[$oid] = self::STATE_MANAGED;
1673 1
                break;
1674
1675
            case self::STATE_DETACHED:
1676
                // Can actually not happen right now since we assume STATE_NEW.
1677
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
1678
1679
            default:
1680
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1681
        }
1682
1683 1038
        $this->cascadePersist($entity, $visited);
1684 1031
    }
1685
1686
    /**
1687
     * Deletes an entity as part of the current unit of work.
1688
     *
1689
     * @param object $entity The entity to remove.
1690
     *
1691
     * @return void
1692
     */
1693 65
    public function remove($entity)
1694
    {
1695 65
        $visited = array();
1696
1697 65
        $this->doRemove($entity, $visited);
1698 65
    }
1699
1700
    /**
1701
     * Deletes an entity as part of the current unit of work.
1702
     *
1703
     * This method is internally called during delete() cascades as it tracks
1704
     * the already visited entities to prevent infinite recursions.
1705
     *
1706
     * @param object $entity  The entity to delete.
1707
     * @param array  $visited The map of the already visited entities.
1708
     *
1709
     * @return void
1710
     *
1711
     * @throws ORMInvalidArgumentException If the instance is a detached entity.
1712
     * @throws UnexpectedValueException
1713
     */
1714 65
    private function doRemove($entity, array &$visited)
1715
    {
1716 65
        $oid = spl_object_hash($entity);
1717
1718 65
        if (isset($visited[$oid])) {
1719 1
            return; // Prevent infinite recursion
1720
        }
1721
1722 65
        $visited[$oid] = $entity; // mark visited
1723
1724
        // Cascade first, because scheduleForDelete() removes the entity from the identity map, which
1725
        // can cause problems when a lazy proxy has to be initialized for the cascade operation.
1726 65
        $this->cascadeRemove($entity, $visited);
1727
1728 65
        $class       = $this->em->getClassMetadata(get_class($entity));
1729 65
        $entityState = $this->getEntityState($entity);
1730
1731
        switch ($entityState) {
1732 65
            case self::STATE_NEW:
1733 65
            case self::STATE_REMOVED:
1734
                // nothing to do
1735 2
                break;
1736
1737 65
            case self::STATE_MANAGED:
1738 65
                $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preRemove);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
1739
1740 65
                if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1741 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...
1742
                }
1743
1744 65
                $this->scheduleForDelete($entity);
1745 65
                break;
1746
1747
            case self::STATE_DETACHED:
1748
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1749
            default:
1750
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1751
        }
1752
1753 65
    }
1754
1755
    /**
1756
     * Merges the state of the given detached entity into this UnitOfWork.
1757
     *
1758
     * @param object $entity
1759
     *
1760
     * @return object The managed copy of the entity.
1761
     *
1762
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1763
     *         attribute and the version check against the managed copy fails.
1764
     *
1765
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1766
     */
1767 41
    public function merge($entity)
1768
    {
1769 41
        $visited = array();
1770
1771 41
        return $this->doMerge($entity, $visited);
1772
    }
1773
1774
    /**
1775
     * Executes a merge operation on an entity.
1776
     *
1777
     * @param object      $entity
1778
     * @param array       $visited
1779
     * @param object|null $prevManagedCopy
1780
     * @param array|null  $assoc
1781
     *
1782
     * @return object The managed copy of the entity.
1783
     *
1784
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1785
     *         attribute and the version check against the managed copy fails.
1786
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1787
     * @throws EntityNotFoundException
1788
     */
1789 41
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, array $assoc = [])
1790
    {
1791 41
        $oid = spl_object_hash($entity);
1792
1793 41
        if (isset($visited[$oid])) {
1794 4
            $managedCopy = $visited[$oid];
1795
1796 4
            if ($prevManagedCopy !== null) {
1797 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
1798
            }
1799
1800 4
            return $managedCopy;
1801
        }
1802
1803 41
        $class = $this->em->getClassMetadata(get_class($entity));
1804
1805
        // First we assume DETACHED, although it can still be NEW but we can avoid
1806
        // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
1807
        // we need to fetch it from the db anyway in order to merge.
1808
        // MANAGED entities are ignored by the merge operation.
1809 41
        $managedCopy = $entity;
1810
1811 41
        if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) {
1812
            // Try to look the entity up in the identity map.
1813 40
            $id = $class->getIdentifierValues($entity);
1814
1815
            // If there is no ID, it is actually NEW.
1816 40
            if ( ! $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
1817 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...
1818
1819 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...
1820
            } else {
1821 35
                $flatId = ($class->containsForeignIdentifier)
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1822 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...
1823 35
                    : $id;
1824
1825 35
                $managedCopy = $this->tryGetById($flatId, $class->rootEntityName);
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug Compatibility introduced by
The expression $this->tryGetById($flatI...class->rootEntityName); of type object|boolean adds the type boolean to the return on line 1889 which is incompatible with the return type documented by Doctrine\ORM\UnitOfWork::doMerge of type object.
Loading history...
1826
1827 35
                if ($managedCopy) {
1828
                    // We have the entity in-memory already, just make sure its not removed.
1829 14
                    if ($this->getEntityState($managedCopy) == self::STATE_REMOVED) {
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1825 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...
1830 14
                        throw ORMInvalidArgumentException::entityIsRemoved($managedCopy, "merge");
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1825 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...
1831
                    }
1832
                } else {
1833
                    // We need to fetch the managed copy in order to merge.
1834 24
                    $managedCopy = $this->em->find($class->name, $flatId);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1835
                }
1836
1837 35
                if ($managedCopy === null) {
1838
                    // If the identifier is ASSIGNED, it is NEW, otherwise an error
1839
                    // since the managed entity was not found.
1840 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...
1841 1
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
1842 1
                            $class->getName(),
1843 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...
1844
                        );
1845
                    }
1846
1847 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...
1848 1
                    $class->setIdentifierValues($managedCopy, $id);
1849
1850 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...
1851
                }
1852
            }
1853
1854 39
            if ($class->isVersioned && $this->isLoaded($managedCopy) && $this->isLoaded($entity)) {
0 ignored issues
show
Bug introduced by
Accessing isVersioned on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1825 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...
1855 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...
1856 4
                $managedCopyVersion = $reflField->getValue($managedCopy);
1857 4
                $entityVersion      = $reflField->getValue($entity);
1858
1859
                // Throw exception if versions don't match.
1860 4
                if ($managedCopyVersion != $entityVersion) {
1861 1
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $entityVersion, $managedCopyVersion);
1862
                }
1863
            }
1864
1865 38
            $visited[$oid] = $managedCopy; // mark visited
1866
1867 38
            if ($this->isLoaded($entity)) {
1868 31
                if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) {
1869 4
                    $managedCopy->__load();
1870
                }
1871
1872 31
                $this->mergeEntityStateIntoManagedCopy($entity, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1825 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...
1873
            }
1874
1875 38
            if ($class->isChangeTrackingDeferredExplicit()) {
1876
                $this->scheduleForDirtyCheck($entity);
1877
            }
1878
        }
1879
1880 39
        if ($prevManagedCopy !== null) {
1881 6
            $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1825 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...
1882
        }
1883
1884
        // Mark the managed copy visited as well
1885 39
        $visited[spl_object_hash($managedCopy)] = $managedCopy;
1886
1887 39
        $this->cascadeMerge($entity, $managedCopy, $visited);
0 ignored issues
show
Bug introduced by
It seems like $managedCopy defined by $this->tryGetById($flatI...$class->rootEntityName) on line 1825 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...
1888
1889 39
        return $managedCopy;
1890
    }
1891
1892
    /**
1893
     * Tests if an entity is loaded - must either be a loaded proxy or not a proxy
1894
     *
1895
     * @param object $entity
1896
     *
1897
     * @return bool
1898
     */
1899 39
    private function isLoaded($entity)
1900
    {
1901 39
        return !($entity instanceof Proxy) || $entity->__isInitialized();
1902
    }
1903
1904
    /**
1905
     * Sets/adds associated managed copies into the previous entity's association field
1906
     *
1907
     * @param object $entity
1908
     * @param array  $association
1909
     * @param object $previousManagedCopy
1910
     * @param object $managedCopy
1911
     *
1912
     * @return void
1913
     */
1914 6
    private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy)
1915
    {
1916 6
        $assocField = $association['fieldName'];
1917 6
        $prevClass  = $this->em->getClassMetadata(get_class($previousManagedCopy));
1918
1919 6
        if ($association['type'] & ClassMetadata::TO_ONE) {
1920 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...
1921
1922 6
            return;
1923
        }
1924
1925 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...
1926 1
        $value[] = $managedCopy;
1927
1928 1
        if ($association['type'] == ClassMetadata::ONE_TO_MANY) {
1929 1
            $class = $this->em->getClassMetadata(get_class($entity));
1930
1931 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...
1932
        }
1933 1
    }
1934
1935
    /**
1936
     * Detaches an entity from the persistence management. It's persistence will
1937
     * no longer be managed by Doctrine.
1938
     *
1939
     * @param object $entity The entity to detach.
1940
     *
1941
     * @return void
1942
     */
1943 12
    public function detach($entity)
1944
    {
1945 12
        $visited = array();
1946
1947 12
        $this->doDetach($entity, $visited);
1948 12
    }
1949
1950
    /**
1951
     * Executes a detach operation on the given entity.
1952
     *
1953
     * @param object  $entity
1954
     * @param array   $visited
1955
     * @param boolean $noCascade if true, don't cascade detach operation.
1956
     *
1957
     * @return void
1958
     */
1959 15
    private function doDetach($entity, array &$visited, $noCascade = false)
1960
    {
1961 15
        $oid = spl_object_hash($entity);
1962
1963 15
        if (isset($visited[$oid])) {
1964
            return; // Prevent infinite recursion
1965
        }
1966
1967 15
        $visited[$oid] = $entity; // mark visited
1968
1969 15
        switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
1970 15
            case self::STATE_MANAGED:
1971 13
                if ($this->isInIdentityMap($entity)) {
1972 12
                    $this->removeFromIdentityMap($entity);
1973
                }
1974
1975
                unset(
1976 13
                    $this->entityInsertions[$oid],
1977 13
                    $this->entityUpdates[$oid],
1978 13
                    $this->entityDeletions[$oid],
1979 13
                    $this->entityIdentifiers[$oid],
1980 13
                    $this->entityStates[$oid],
1981 13
                    $this->originalEntityData[$oid]
1982
                );
1983 13
                break;
1984 3
            case self::STATE_NEW:
1985 3
            case self::STATE_DETACHED:
1986 3
                return;
1987
        }
1988
1989 13
        if ( ! $noCascade) {
1990 13
            $this->cascadeDetach($entity, $visited);
1991
        }
1992 13
    }
1993
1994
    /**
1995
     * Refreshes the state of the given entity from the database, overwriting
1996
     * any local, unpersisted changes.
1997
     *
1998
     * @param object $entity The entity to refresh.
1999
     *
2000
     * @return void
2001
     *
2002
     * @throws InvalidArgumentException If the entity is not MANAGED.
2003
     */
2004 17
    public function refresh($entity)
2005
    {
2006 17
        $visited = array();
2007
2008 17
        $this->doRefresh($entity, $visited);
2009 17
    }
2010
2011
    /**
2012
     * Executes a refresh operation on an entity.
2013
     *
2014
     * @param object $entity  The entity to refresh.
2015
     * @param array  $visited The already visited entities during cascades.
2016
     *
2017
     * @return void
2018
     *
2019
     * @throws ORMInvalidArgumentException If the entity is not MANAGED.
2020
     */
2021 17
    private function doRefresh($entity, array &$visited)
2022
    {
2023 17
        $oid = spl_object_hash($entity);
2024
2025 17
        if (isset($visited[$oid])) {
2026
            return; // Prevent infinite recursion
2027
        }
2028
2029 17
        $visited[$oid] = $entity; // mark visited
2030
2031 17
        $class = $this->em->getClassMetadata(get_class($entity));
2032
2033 17
        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
2034
            throw ORMInvalidArgumentException::entityNotManaged($entity);
2035
        }
2036
2037 17
        $this->getEntityPersister($class->name)->refresh(
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2190
2191
            switch (true) {
2192 652
                case ($relatedEntities instanceof PersistentCollection):
2193
                    // Unwrap so that foreach() does not initialize
2194 21
                    $relatedEntities = $relatedEntities->unwrap();
2195
                    // break; is commented intentionally!
2196
2197
                case ($relatedEntities instanceof Collection):
2198 592
                case (is_array($relatedEntities)):
2199 556
                    if (($assoc['type'] & ClassMetadata::TO_MANY) <= 0) {
2200 3
                        throw ORMInvalidArgumentException::invalidAssociation(
2201 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...
2202
                            $assoc,
2203
                            $relatedEntities
2204
                        );
2205
                    }
2206
2207 553
                    foreach ($relatedEntities as $relatedEntity) {
2208 282
                        $this->doPersist($relatedEntity, $visited);
2209
                    }
2210
2211 553
                    break;
2212
2213 582
                case ($relatedEntities !== null):
2214 246
                    if (! $relatedEntities instanceof $assoc['targetEntity']) {
2215 4
                        throw ORMInvalidArgumentException::invalidAssociation(
2216 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...
2217
                            $assoc,
2218
                            $relatedEntities
2219
                        );
2220
                    }
2221
2222 242
                    $this->doPersist($relatedEntities, $visited);
2223 242
                    break;
2224
2225 646
                default:
2226
                    // Do nothing
2227
            }
2228
        }
2229 1031
    }
2230
2231
    /**
2232
     * Cascades the delete operation to associated entities.
2233
     *
2234
     * @param object $entity
2235
     * @param array  $visited
2236
     *
2237
     * @return void
2238
     */
2239 65
    private function cascadeRemove($entity, array &$visited)
2240
    {
2241 65
        $class = $this->em->getClassMetadata(get_class($entity));
2242
2243 65
        $associationMappings = array_filter(
2244 65
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2316 1
                    $entity->__load();
2317
                }
2318
2319 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...
2320
2321 4
                if ($entityVersion != $lockVersion) {
2322 2
                    throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion);
2323
                }
2324
2325 2
                break;
2326
2327 3
            case LockMode::NONE === $lockMode:
2328 3
            case LockMode::PESSIMISTIC_READ === $lockMode:
2329 1
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
2330 3
                if (!$this->em->getConnection()->isTransactionActive()) {
2331 2
                    throw TransactionRequiredException::transactionRequired();
2332
                }
2333
2334 1
                $oid = spl_object_hash($entity);
2335
2336 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...
2337 1
                    array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
2338
                    $lockMode
2339
                );
2340 1
                break;
2341
2342
            default:
2343
                // Do nothing
2344
        }
2345 3
    }
2346
2347
    /**
2348
     * Gets the CommitOrderCalculator used by the UnitOfWork to order commits.
2349
     *
2350
     * @return \Doctrine\ORM\Internal\CommitOrderCalculator
2351
     */
2352 1017
    public function getCommitOrderCalculator()
2353
    {
2354 1017
        return new Internal\CommitOrderCalculator();
2355
    }
2356
2357
    /**
2358
     * Clears the UnitOfWork.
2359
     *
2360
     * @param string|null $entityName if given, only entities of this type will get detached.
2361
     *
2362
     * @return void
2363
     */
2364 1231
    public function clear($entityName = null)
2365
    {
2366 1231
        if ($entityName !== null && !is_string($entityName)) {
2367 1
            throw ORMException::invalidEntityName($entityName);
2368
        }
2369
2370 1230
        if ($entityName === null) {
2371 1229
            $this->identityMap =
2372 1229
            $this->entityIdentifiers =
2373 1229
            $this->originalEntityData =
2374 1229
            $this->entityChangeSets =
2375 1229
            $this->entityStates =
2376 1229
            $this->scheduledForSynchronization =
2377 1229
            $this->entityInsertions =
2378 1229
            $this->entityUpdates =
2379 1229
            $this->entityDeletions =
2380 1229
            $this->collectionDeletions =
2381 1229
            $this->collectionUpdates =
2382 1229
            $this->extraUpdates =
2383 1229
            $this->readOnlyObjects =
2384 1229
            $this->visitedCollections =
2385 1229
            $this->orphanRemovals = array();
2386
        } else {
2387 3
            $this->clearIdentityMapForEntityName($entityName);
2388 3
            $this->clearEntityInsertionsForEntityName($entityName);
2389
        }
2390
2391 1230
        if ($this->evm->hasListeners(Events::onClear)) {
2392 7
            $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
2393
        }
2394 1230
    }
2395
2396
    /**
2397
     * INTERNAL:
2398
     * Schedules an orphaned entity for removal. The remove() operation will be
2399
     * invoked on that entity at the beginning of the next commit of this
2400
     * UnitOfWork.
2401
     *
2402
     * @ignore
2403
     *
2404
     * @param object $entity
2405
     *
2406
     * @return void
2407
     */
2408 17
    public function scheduleOrphanRemoval($entity)
2409
    {
2410 17
        $this->orphanRemovals[spl_object_hash($entity)] = $entity;
2411 17
    }
2412
2413
    /**
2414
     * INTERNAL:
2415
     * Cancels a previously scheduled orphan removal.
2416
     *
2417
     * @ignore
2418
     *
2419
     * @param object $entity
2420
     *
2421
     * @return void
2422
     */
2423 114
    public function cancelOrphanRemoval($entity)
2424
    {
2425 114
        unset($this->orphanRemovals[spl_object_hash($entity)]);
2426 114
    }
2427
2428
    /**
2429
     * INTERNAL:
2430
     * Schedules a complete collection for removal when this UnitOfWork commits.
2431
     *
2432
     * @param PersistentCollection $coll
2433
     *
2434
     * @return void
2435
     */
2436 14
    public function scheduleCollectionDeletion(PersistentCollection $coll)
2437
    {
2438 14
        $coid = spl_object_hash($coll);
2439
2440
        // TODO: if $coll is already scheduled for recreation ... what to do?
2441
        // Just remove $coll from the scheduled recreations?
2442 14
        unset($this->collectionUpdates[$coid]);
2443
2444 14
        $this->collectionDeletions[$coid] = $coll;
2445 14
    }
2446
2447
    /**
2448
     * @param PersistentCollection $coll
2449
     *
2450
     * @return bool
2451
     */
2452
    public function isCollectionScheduledForDeletion(PersistentCollection $coll)
2453
    {
2454
        return isset($this->collectionDeletions[spl_object_hash($coll)]);
2455
    }
2456
2457
    /**
2458
     * @param ClassMetadata $class
2459
     *
2460
     * @return \Doctrine\Common\Persistence\ObjectManagerAware|object
2461
     */
2462 678
    private function newInstance($class)
2463
    {
2464 678
        $entity = $class->newInstance();
2465
2466 678
        if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
2467 4
            $entity->injectObjectManager($this->em, $class);
2468
        }
2469
2470 678
        return $entity;
2471
    }
2472
2473
    /**
2474
     * INTERNAL:
2475
     * Creates an entity. Used for reconstitution of persistent entities.
2476
     *
2477
     * Internal note: Highly performance-sensitive method.
2478
     *
2479
     * @ignore
2480
     *
2481
     * @param string $className The name of the entity class.
2482
     * @param array  $data      The data for the entity.
2483
     * @param array  $hints     Any hints to account for during reconstitution/lookup of the entity.
2484
     *
2485
     * @return object The managed entity instance.
2486
     *
2487
     * @todo Rename: getOrCreateEntity
2488
     */
2489 816
    public function createEntity($className, array $data, &$hints = array())
2490
    {
2491 816
        $class = $this->em->getClassMetadata($className);
2492
        //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]);
2493
2494 816
        $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...
2495 816
        $idHash = implode(' ', $id);
2496
2497 816
        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...
2498 312
            $entity = $this->identityMap[$class->rootEntityName][$idHash];
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2514
                }
2515
2516 2
                return $unmanagedProxy;
2517
            }
2518
2519 310
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2520 22
                $entity->__setInitialized(true);
2521
2522 22
                $overrideLocalValues = true;
2523
2524 22
                if ($entity instanceof NotifyPropertyChanged) {
2525 22
                    $entity->addPropertyChangedListener($this);
2526
                }
2527
            } else {
2528 290
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2529
2530
                // If only a specific entity is set to refresh, check that it's the one
2531 290
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2532 71
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2533
                }
2534
            }
2535
2536 310
            if ($overrideLocalValues) {
2537
                // inject ObjectManager upon refresh.
2538 113
                if ($entity instanceof ObjectManagerAware) {
2539 3
                    $entity->injectObjectManager($this->em, $class);
2540
                }
2541
2542 310
                $this->originalEntityData[$oid] = $data;
2543
            }
2544
        } else {
2545 674
            $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...
2546 674
            $oid    = spl_object_hash($entity);
2547
2548 674
            $this->entityIdentifiers[$oid]  = $id;
2549 674
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2550 674
            $this->originalEntityData[$oid] = $data;
2551
2552 674
            $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...
2553
2554 674
            if ($entity instanceof NotifyPropertyChanged) {
2555 2
                $entity->addPropertyChangedListener($this);
2556
            }
2557
2558 674
            $overrideLocalValues = true;
2559
        }
2560
2561 815
        if ( ! $overrideLocalValues) {
2562 220
            return $entity;
2563
        }
2564
2565 712
        foreach ($data as $field => $value) {
2566 712
            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...
2567 712
                $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...
2568
            }
2569
        }
2570
2571
        // Loading the entity right here, if its in the eager loading map get rid of it there.
2572 712
        unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
2573
2574 712
        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...
2575
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2576
        }
2577
2578
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2579 712
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2580 33
            return $entity;
2581
        }
2582
2583 679
        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...
2584
            // Check if the association is not among the fetch-joined associations already.
2585 590
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2586 261
                continue;
2587
            }
2588
2589 568
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2590
2591
            switch (true) {
2592 568
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2593 488
                    if ( ! $assoc['isOwningSide']) {
2594
2595
                        // use the given entity association
2596 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2597
2598 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2599
2600 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...
2601 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...
2602
2603 2
                            continue 2;
2604
                        }
2605
2606
                        // Inverse side of x-to-one can never be lazy
2607 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...
2608
2609 62
                        continue 2;
2610
                    }
2611
2612
                    // use the entity association
2613 488
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2614 38
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2634
                        ) {
2635
                            // the missing key is part of target's entity primary key
2636 7
                            $associatedId = array();
2637 481
                            break;
2638
                        }
2639
                    }
2640
2641 481
                    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...
2642
                        // Foreign key is NULL
2643 287
                        $class->reflFields[$field]->setValue($entity, null);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2644 287
                        $this->originalEntityData[$oid][$field] = null;
2645
2646 287
                        continue;
2647
                    }
2648
2649 286
                    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...
2650 283
                        $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...
2651
                    }
2652
2653
                    // Foreign key is set
2654
                    // Check identity map first
2655
                    // FIXME: Can break easily with composite keys if join column values are in
2656
                    //        wrong order. The correct order is the one in ClassMetadata#identifier.
2657 286
                    $relatedIdHash = implode(' ', $associatedId);
2658
2659
                    switch (true) {
2660 286
                        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...
2661 168
                            $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...
2662
2663
                            // If this is an uninitialized proxy, we are deferring eager loads,
2664
                            // this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
2665
                            // then we can append this entity for eager loading!
2666 168
                            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...
2667 168
                                isset($hints[self::HINT_DEFEREAGERLOAD]) &&
2668 168
                                !$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...
2669 168
                                $newValue instanceof Proxy &&
2670 168
                                $newValue->__isInitialized__ === false) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2671
2672
                                $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...
2673
                            }
2674
2675 168
                            break;
2676
2677 193
                        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...
2678
                            // If it might be a subtype, it can not be lazy. There isn't even
2679
                            // a way to solve this with deferred eager loading, which means putting
2680
                            // an entity with subclasses at a *-to-one location is really bad! (performance-wise)
2681 31
                            $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
2682 31
                            break;
2683
2684
                        default:
2685
                            switch (true) {
2686
                                // We are negating the condition here. Other cases will assume it is valid!
2687 164
                                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...
2688 157
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2689 157
                                    break;
2690
2691
                                // Deferred eager load only works for single identifier classes
2692 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...
2693
                                    // TODO: Is there a faster approach?
2694 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...
2695
2696 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2697 7
                                    break;
2698
2699
                                default:
2700
                                    // TODO: This is very imperformant, ignore it?
2701
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2702
                                    break;
2703
                            }
2704
2705
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2706 164
                            $newValueOid = spl_object_hash($newValue);
2707 164
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2708 164
                            $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...
2709
2710
                            if (
2711 164
                                $newValue instanceof NotifyPropertyChanged &&
2712 164
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2713
                            ) {
2714
                                $newValue->addPropertyChangedListener($this);
2715
                            }
2716 164
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2717
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2718 164
                            break;
2719
                    }
2720
2721 286
                    $this->originalEntityData[$oid][$field] = $newValue;
2722 286
                    $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...
2723
2724 286
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2725 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...
2726 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...
2727
                    }
2728
2729 286
                    break;
2730
2731
                default:
2732
                    // Ignore if its a cached collection
2733 490
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2734
                        break;
2735
                    }
2736
2737
                    // use the given collection
2738 490
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2739
2740 3
                        $data[$field]->setOwner($entity, $assoc);
2741
2742 3
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2743 3
                        $this->originalEntityData[$oid][$field] = $data[$field];
2744
2745 3
                        break;
2746
                    }
2747
2748
                    // Inject collection
2749 490
                    $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...
2750 490
                    $pColl->setOwner($entity, $assoc);
2751 490
                    $pColl->setInitialized(false);
2752
2753 490
                    $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...
2754 490
                    $reflField->setValue($entity, $pColl);
2755
2756 490
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2757 4
                        $this->loadCollection($pColl);
2758 4
                        $pColl->takeSnapshot();
2759
                    }
2760
2761 490
                    $this->originalEntityData[$oid][$field] = $pColl;
2762 568
                    break;
2763
            }
2764
        }
2765
2766 679
        if ($overrideLocalValues) {
2767
            // defer invoking of postLoad event to hydration complete step
2768 679
            $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...
2769
        }
2770
2771 679
        return $entity;
2772
    }
2773
2774
    /**
2775
     * @return void
2776
     */
2777 874
    public function triggerEagerLoads()
2778
    {
2779 874
        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...
2780 874
            return;
2781
        }
2782
2783
        // avoid infinite recursion
2784 7
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2785 7
        $this->eagerLoadingEntities = array();
2786
2787 7
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2788 7
            if ( ! $ids) {
2789
                continue;
2790
            }
2791
2792 7
            $class = $this->em->getClassMetadata($entityName);
2793
2794 7
            $this->getEntityPersister($entityName)->loadAll(
2795 7
                array_combine($class->identifier, array(array_values($ids)))
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

Loading history...
3329
3330 3
        return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
3331
    }
3332
3333
    /**
3334
     * @param object $entity
3335
     * @param object $managedCopy
3336
     *
3337
     * @throws ORMException
3338
     * @throws OptimisticLockException
3339
     * @throws TransactionRequiredException
3340
     */
3341 31
    private function mergeEntityStateIntoManagedCopy($entity, $managedCopy)
3342
    {
3343 31
        $class = $this->em->getClassMetadata(get_class($entity));
3344
3345 31
        foreach ($this->reflectionPropertiesGetter->getProperties($class->name) as $prop) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
3351 31
                if ( ! $class->isIdentifier($name)) {
3352 31
                    $prop->setValue($managedCopy, $prop->getValue($entity));
3353
                }
3354
            } else {
3355 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...
3356
3357 29
                if ($assoc2['type'] & ClassMetadata::TO_ONE) {
3358 25
                    $other = $prop->getValue($entity);
3359 25
                    if ($other === null) {
3360 12
                        $prop->setValue($managedCopy, null);
3361
                    } else {
3362 16
                        if ($other instanceof Proxy && !$other->__isInitialized()) {
3363
                            // do not merge fields marked lazy that have not been fetched.
3364 4
                            continue;
3365
                        }
3366
3367 12
                        if ( ! $assoc2['isCascadeMerge']) {
3368 6
                            if ($this->getEntityState($other) === self::STATE_DETACHED) {
3369 3
                                $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
3370 3
                                $relatedId   = $targetClass->getIdentifierValues($other);
3371
3372 3
                                if ($targetClass->subClasses) {
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

Loading history...
3401 4
                            new ArrayCollection
3402
                        );
3403 4
                        $managedCol->setOwner($managedCopy, $assoc2);
3404 4
                        $prop->setValue($managedCopy, $managedCol);
3405
                    }
3406
3407 14
                    if ($assoc2['isCascadeMerge']) {
3408 9
                        $managedCol->initialize();
3409
3410
                        // clear and set dirty a managed collection if its not also the same collection to merge from.
3411 9
                        if ( ! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
3412 1
                            $managedCol->unwrap()->clear();
3413 1
                            $managedCol->setDirty(true);
3414
3415 1
                            if ($assoc2['isOwningSide']
3416 1
                                && $assoc2['type'] == ClassMetadata::MANY_TO_MANY
3417 1
                                && $class->isChangeTrackingNotify()
3418
                            ) {
3419
                                $this->scheduleForDirtyCheck($managedCopy);
3420
                            }
3421
                        }
3422
                    }
3423
                }
3424
            }
3425
3426 31
            if ($class->isChangeTrackingNotify()) {
3427
                // Just treat all properties as changed, there is no other choice.
3428 31
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
3429
            }
3430
        }
3431 31
    }
3432
3433
    /**
3434
     * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle.
3435
     * Unit of work able to fire deferred events, related to loading events here.
3436
     *
3437
     * @internal should be called internally from object hydrators
3438
     */
3439 886
    public function hydrationComplete()
3440
    {
3441 886
        $this->hydrationCompleteHandler->hydrationComplete();
3442 886
    }
3443
3444
    /**
3445
     * @param string $entityName
3446
     */
3447 3
    private function clearIdentityMapForEntityName($entityName)
3448
    {
3449 3
        if (! isset($this->identityMap[$entityName])) {
3450
            return;
3451
        }
3452
3453 3
        $visited = [];
3454
3455 3
        foreach ($this->identityMap[$entityName] as $entity) {
3456 3
            $this->doDetach($entity, $visited, false);
3457
        }
3458 3
    }
3459
3460
    /**
3461
     * @param string $entityName
3462
     */
3463 3
    private function clearEntityInsertionsForEntityName($entityName)
3464
    {
3465 3
        foreach ($this->entityInsertions as $hash => $entity) {
3466
            // note: performance optimization - `instanceof` is much faster than a function call
3467 1
            if ($entity instanceof $entityName && get_class($entity) === $entityName) {
3468 1
                unset($this->entityInsertions[$hash]);
3469
            }
3470
        }
3471 3
    }
3472
3473
    /**
3474
     * @param ClassMetadata $class
3475
     * @param mixed         $identifierValue
3476
     *
3477
     * @return mixed the identifier after type conversion
3478
     *
3479
     * @throws \Doctrine\ORM\Mapping\MappingException if the entity has more than a single identifier
3480
     */
3481 927
    private function convertSingleFieldIdentifierToPHPValue(ClassMetadata $class, $identifierValue)
3482
    {
3483 927
        return $this->em->getConnection()->convertToPHPValue(
3484
            $identifierValue,
3485 927
            $class->getTypeOfField($class->getSingleIdentifierFieldName())
0 ignored issues
show
Bug introduced by
It seems like $class->getTypeOfField($...eIdentifierFieldName()) targeting Doctrine\ORM\Mapping\Cla...aInfo::getTypeOfField() can also be of type null or object<Doctrine\DBAL\Types\Type>; however, Doctrine\DBAL\Connection::convertToPHPValue() does only seem to accept string, maybe add an additional type check?

This check looks at variables that 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...
3486
        );
3487
    }
3488
}
3489