Completed
Pull Request — master (#5579)
by Huberty
09:06
created

UnitOfWork   F

Complexity

Total Complexity 502

Size/Duplication

Total Lines 3429
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 38

Test Coverage

Coverage 92.64%

Importance

Changes 11
Bugs 4 Features 1
Metric Value
wmc 502
c 11
b 4
f 1
lcom 1
cbo 38
dl 0
loc 3429
ccs 1145
cts 1236
cp 0.9264
rs 0.5217

93 Methods

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
398 63
                    $this->executeDeletions($commitOrder[$i]);
399
                }
400
            }
401
402 994
            $conn->commit();
403 11
        } catch (Exception $e) {
404 11
            $this->em->close();
405 11
            $conn->rollback();
406
407 11
            $this->afterTransactionRolledBack();
408
409 11
            throw $e;
410
        }
411
412 994
        $this->afterTransactionComplete();
413
414
        // Take new snapshots from visited collections
415 994
        foreach ($this->visitedCollections as $coll) {
416 522
            $coll->takeSnapshot();
417
        }
418
419 994
        $this->dispatchPostFlushEvent();
420
421 993
        $this->postCommitClear($entity);
422 993
    }
423
424
    /**
425
     * @param null|object|array $entity
426
     */
427 993
    private function postCommitClear($entity = null) {
428
429
        // Clear up
430 993
        $this->entityInsertions =
431 993
        $this->entityUpdates =
432 993
        $this->entityDeletions =
433 993
        $this->extraUpdates =
434 993
        $this->collectionUpdates =
435 993
        $this->collectionDeletions =
436 993
        $this->visitedCollections =
437 993
        $this->orphanRemovals = array();
438
439 993
        if (null === $entity) {
440 986
            $this->entityChangeSets = $this->scheduledForSynchronization = array();
441 986
            return;
442
        }
443
444 14
        if (is_object($entity)) {
445 13
            $entity = [$entity];
446
        }
447
448 14
        foreach ($entity as $object) {
449 14
            $oid = spl_object_hash($object);
450 14
            $class = $this->em->getClassMetadata(get_class($object));
451 14
            $this->clearEntityChangeSet($oid);
452 14
            $this->clearScheduledForSynchronization($class, $oid);
453
        }
454 14
    }
455
456
    /**
457
     * Computes the changesets of all entities scheduled for insertion.
458
     *
459
     * @return void
460
     */
461 1005
    private function computeScheduleInsertsChangeSets()
462
    {
463 1005
        foreach ($this->entityInsertions as $entity) {
464 997
            $class = $this->em->getClassMetadata(get_class($entity));
465
466 997
            $this->computeChangeSet($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
467
        }
468 1003
    }
469
470
    /**
471
     * Only flushes the given entity according to a ruleset that keeps the UoW consistent.
472
     *
473
     * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
474
     * 2. Read Only entities are skipped.
475
     * 3. Proxies are skipped.
476
     * 4. Only if entity is properly managed.
477
     *
478
     * @param object $entity
479
     *
480
     * @return void
481
     *
482
     * @throws \InvalidArgumentException
483
     */
484 17
    private function computeSingleEntityChangeSet($entity)
485
    {
486 17
        $state = $this->getEntityState($entity);
487
488 17
        if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
489 1
            throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
490
        }
491
492 16
        $class = $this->em->getClassMetadata(get_class($entity));
493
494 16
        if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
495 15
            $this->persist($entity);
496
        }
497
498
        // Compute changes for INSERTed entities first. This must always happen even in this case.
499 16
        $this->computeScheduleInsertsChangeSets();
500
501 16
        if ($class->isReadOnly) {
0 ignored issues
show
Bug introduced by
Accessing isReadOnly on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
606 1007
            $value = $refProp->getValue($entity);
607
608 1007
            if ($class->isCollectionValuedAssociation($name) && $value !== null) {
609 769
                if ($value instanceof PersistentCollection) {
610 197
                    if ($value->getOwner() === $entity) {
611 197
                        continue;
612
                    }
613
614 5
                    $value = new ArrayCollection($value->getValues());
615
                }
616
617
                // If $value is not a Collection then use an ArrayCollection.
618 764
                if ( ! $value instanceof Collection) {
619 236
                    $value = new ArrayCollection($value);
620
                }
621
622 764
                $assoc = $class->associationMappings[$name];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
632
633 764
                $actualData[$name] = $value;
634
635 764
                continue;
636
            }
637
638 1007
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) && ($name !== $class->versionField)) {
0 ignored issues
show
Bug introduced by
Accessing versionField on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
639 1007
                $actualData[$name] = $value;
640
            }
641
        }
642
643 1007
        if ( ! isset($this->originalEntityData[$oid])) {
644
            // Entity is either NEW or MANAGED but not yet fully persisted (only has an id).
645
            // These result in an INSERT.
646 1003
            $this->originalEntityData[$oid] = $actualData;
647 1003
            $changeSet = array();
648
649 1003
            foreach ($actualData as $propName => $actualValue) {
650 988
                if ( ! isset($class->associationMappings[$propName])) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
651 937
                    $changeSet[$propName] = array(null, $actualValue);
652
653 937
                    continue;
654
                }
655
656 886
                $assoc = $class->associationMappings[$propName];
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
751 632
                continue;
752
            }
753
754 857
            $this->computeAssociationChanges($assoc, $val);
755
756 849
            if ( ! isset($this->entityChangeSets[$oid]) &&
757 849
                $assoc['isOwningSide'] &&
758 849
                $assoc['type'] == ClassMetadata::MANY_TO_MANY &&
759 849
                $val instanceof PersistentCollection &&
760 849
                $val->isDirty()) {
761
762 34
                $this->entityChangeSets[$oid]   = array();
763 34
                $this->originalEntityData[$oid] = $actualData;
764 849
                $this->entityUpdates[$oid]      = $entity;
765
            }
766
        }
767 999
    }
768
769
    /**
770
     * Computes all the changes that have been done to entities and collections
771
     * since the last commit and stores these changes in the _entityChangeSet map
772
     * temporarily for access by the persisters, until the UoW commit is finished.
773
     *
774
     * @return void
775
     */
776 998
    public function computeChangeSets()
777
    {
778
        // Compute changes for INSERTed entities first. This must always happen.
779 998
        $this->computeScheduleInsertsChangeSets();
780
781
        // Compute changes for other MANAGED entities. Change tracking policies take effect here.
782 996
        foreach ($this->identityMap as $className => $entities) {
783 444
            $class = $this->em->getClassMetadata($className);
784
785
            // Skip class if instances are read-only
786 444
            if ($class->isReadOnly) {
0 ignored issues
show
Bug introduced by
Accessing isReadOnly on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
787 1
                continue;
788
            }
789
790
            // If change tracking is explicit or happens through notification, then only compute
791
            // changes on entities of that type that are explicitly marked for synchronization.
792
            switch (true) {
793 443
                case ($class->isChangeTrackingDeferredImplicit()):
794 441
                    $entitiesToProcess = $entities;
795 441
                    break;
796
797 3
                case (isset($this->scheduledForSynchronization[$className])):
798 3
                    $entitiesToProcess = $this->scheduledForSynchronization[$className];
799 3
                    break;
800
801
                default:
802 1
                    $entitiesToProcess = array();
803
804
            }
805
806 443
            foreach ($entitiesToProcess as $entity) {
807
                // Ignore uninitialized proxy objects
808 423
                if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

Loading history...
817
                }
818
            }
819
        }
820 996
    }
821
822
    /**
823
     * Computes the changes of an association.
824
     *
825
     * @param array $assoc The association mapping.
826
     * @param mixed $value The value of the association.
827
     *
828
     * @throws ORMInvalidArgumentException
829
     * @throws ORMException
830
     *
831
     * @return void
832
     */
833 857
    private function computeAssociationChanges($assoc, $value)
834
    {
835 857
        if ($value instanceof Proxy && ! $value->__isInitialized__) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
836 27
            return;
837
        }
838
839 856
        if ($value instanceof PersistentCollection && $value->isDirty()) {
840 525
            $coid = spl_object_hash($value);
841
842 525
            $this->collectionUpdates[$coid] = $value;
843 525
            $this->visitedCollections[$coid] = $value;
844
        }
845
846
        // Look through the entities, and in any of their associations,
847
        // for transient (new) entities, recursively. ("Persistence by reachability")
848
        // Unwrap. Uninitialized collections will simply be empty.
849 856
        $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap();
850 856
        $targetClass    = $this->em->getClassMetadata($assoc['targetEntity']);
851
852 856
        foreach ($unwrappedValue as $key => $entry) {
853 714
            if (! ($entry instanceof $targetClass->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

Loading history...
913
914 260
            if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
915 1
                $idValue = array($class->identifier[0] => $idValue);
916
917 1
                $class->setIdentifierValues($entity, $idValue);
918
            }
919
920 260
            $this->entityIdentifiers[$oid] = $idValue;
921
        }
922
923 1015
        $this->entityStates[$oid] = self::STATE_MANAGED;
924
925 1015
        $this->scheduleForInsert($entity);
926 1015
    }
927
928
    /**
929
     * INTERNAL:
930
     * Computes the changeset of an individual entity, independently of the
931
     * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
932
     *
933
     * The passed entity must be a managed entity. If the entity already has a change set
934
     * because this method is invoked during a commit cycle then the change sets are added.
935
     * whereby changes detected in this method prevail.
936
     *
937
     * @ignore
938
     *
939
     * @param ClassMetadata $class  The class descriptor of the entity.
940
     * @param object        $entity The entity for which to (re)calculate the change set.
941
     *
942
     * @return void
943
     *
944
     * @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
945
     */
946 16
    public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
947
    {
948 16
        $oid = spl_object_hash($entity);
949
950 16
        if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
951
            throw ORMInvalidArgumentException::entityNotManaged($entity);
952
        }
953
954
        // skip if change tracking is "NOTIFY"
955 16
        if ($class->isChangeTrackingNotify()) {
956
            return;
957
        }
958
959 16
        if ( ! $class->isInheritanceTypeNone()) {
960 3
            $class = $this->em->getClassMetadata(get_class($entity));
961
        }
962
963 16
        $actualData = array();
964
965 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...
966 16
            if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
967 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...
968 16
                && ! $class->isCollectionValuedAssociation($name)) {
969 16
                $actualData[$name] = $refProp->getValue($entity);
970
            }
971
        }
972
973 16
        if ( ! isset($this->originalEntityData[$oid])) {
974
            throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
975
        }
976
977 16
        $originalData = $this->originalEntityData[$oid];
978 16
        $changeSet = array();
979
980 16
        foreach ($actualData as $propName => $actualValue) {
981 16
            $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
982
983 16
            if ($orgValue !== $actualValue) {
984 16
                $changeSet[$propName] = array($orgValue, $actualValue);
985
            }
986
        }
987
988 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...
989 7
            if (isset($this->entityChangeSets[$oid])) {
990 6
                $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
991 1
            } else if ( ! isset($this->entityInsertions[$oid])) {
992 1
                $this->entityChangeSets[$oid] = $changeSet;
993 1
                $this->entityUpdates[$oid]    = $entity;
994
            }
995 7
            $this->originalEntityData[$oid] = $actualData;
996
        }
997 16
    }
998
999
    /**
1000
     * Executes all entity insertions for entities of the specified type.
1001
     *
1002
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1003
     *
1004
     * @return void
1005
     */
1006 995
    private function executeInserts($class)
1007
    {
1008 995
        $entities   = array();
1009 995
        $className  = $class->name;
1010 995
        $persister  = $this->getEntityPersister($className);
1011 995
        $invoke     = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
1012
1013 995
        foreach ($this->entityInsertions as $oid => $entity) {
1014
1015 995
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1016 847
                continue;
1017
            }
1018
1019 995
            $persister->addInsert($entity);
1020
1021 995
            unset($this->entityInsertions[$oid]);
1022
1023 995
            if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1024 995
                $entities[] = $entity;
1025
            }
1026
        }
1027
1028 995
        $postInsertIds = $persister->executeInserts();
1029
1030 995
        if ($postInsertIds) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $postInsertIds of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
1031
            // Persister returned post-insert IDs
1032 912
            foreach ($postInsertIds as $postInsertId) {
1033 912
                $id      = $postInsertId['generatedId'];
1034 912
                $entity  = $postInsertId['entity'];
1035 912
                $oid     = spl_object_hash($entity);
1036 912
                $idField = $class->identifier[0];
1037
1038 912
                $class->reflFields[$idField]->setValue($entity, $id);
1039
1040 912
                $this->entityIdentifiers[$oid] = array($idField => $id);
1041 912
                $this->entityStates[$oid] = self::STATE_MANAGED;
1042 912
                $this->originalEntityData[$oid][$idField] = $id;
1043
1044 912
                $this->addToIdentityMap($entity);
1045
            }
1046
        }
1047
1048 995
        foreach ($entities as $entity) {
1049 134
            $this->listenersInvoker->invoke($class, Events::postPersist, $entity, new LifecycleEventArgs($entity, $this->em), $invoke);
1050
        }
1051 995
    }
1052
1053
    /**
1054
     * Executes all entity updates for entities of the specified type.
1055
     *
1056
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
1057
     *
1058
     * @return void
1059
     */
1060 115
    private function executeUpdates($class)
1061
    {
1062 115
        $className          = $class->name;
1063 115
        $persister          = $this->getEntityPersister($className);
1064 115
        $preUpdateInvoke    = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate);
1065 115
        $postUpdateInvoke   = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate);
1066
1067 115
        foreach ($this->entityUpdates as $oid => $entity) {
1068
1069 115
            if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1160
1161 999
            $newNodes[] = $class;
1162
        }
1163
1164
        // Calculate dependencies for new nodes
1165 999
        while ($class = array_pop($newNodes)) {
1166 999
            foreach ($class->associationMappings as $assoc) {
1167 878
                if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
1168 838
                    continue;
1169
                }
1170
1171 831
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
1172
1173 831
                if ( ! $calc->hasNode($targetClass->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
1175
1176 642
                    $newNodes[] = $targetClass;
1177
                }
1178
1179 831
                $joinColumns = reset($assoc['joinColumns']);
1180 831
                $isNullable  = isset($joinColumns['nullable']) ? $joinColumns['nullable'] : false;
1181
1182 831
                $calc->addDependency($targetClass->name, $class->name, $isNullable ? 0 : 1);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Consider the following code example.

<?php

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

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

print $a . " - " . $c;

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

Instead, the list call could have been.

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

Loading history...
1697 1011
                break;
1698
1699 1
            case self::STATE_REMOVED:
1700
                // Entity becomes managed again
1701 1
                unset($this->entityDeletions[$oid]);
1702 1
                $this->addToIdentityMap($entity);
1703
1704 1
                $this->entityStates[$oid] = self::STATE_MANAGED;
1705 1
                break;
1706
1707
            case self::STATE_DETACHED:
1708
                // Can actually not happen right now since we assume STATE_NEW.
1709
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
1710
1711
            default:
1712
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1713
        }
1714
1715 1012
        $this->cascadePersist($entity, $visited);
1716 1005
    }
1717
1718
    /**
1719
     * Deletes an entity as part of the current unit of work.
1720
     *
1721
     * @param object $entity The entity to remove.
1722
     *
1723
     * @return void
1724
     */
1725 65
    public function remove($entity)
1726
    {
1727 65
        $visited = array();
1728
1729 65
        $this->doRemove($entity, $visited);
1730 65
    }
1731
1732
    /**
1733
     * Deletes an entity as part of the current unit of work.
1734
     *
1735
     * This method is internally called during delete() cascades as it tracks
1736
     * the already visited entities to prevent infinite recursions.
1737
     *
1738
     * @param object $entity  The entity to delete.
1739
     * @param array  $visited The map of the already visited entities.
1740
     *
1741
     * @return void
1742
     *
1743
     * @throws ORMInvalidArgumentException If the instance is a detached entity.
1744
     * @throws UnexpectedValueException
1745
     */
1746 65
    private function doRemove($entity, array &$visited)
1747
    {
1748 65
        $oid = spl_object_hash($entity);
1749
1750 65
        if (isset($visited[$oid])) {
1751 1
            return; // Prevent infinite recursion
1752
        }
1753
1754 65
        $visited[$oid] = $entity; // mark visited
1755
1756
        // Cascade first, because scheduleForDelete() removes the entity from the identity map, which
1757
        // can cause problems when a lazy proxy has to be initialized for the cascade operation.
1758 65
        $this->cascadeRemove($entity, $visited);
1759
1760 65
        $class       = $this->em->getClassMetadata(get_class($entity));
1761 65
        $entityState = $this->getEntityState($entity);
1762
1763
        switch ($entityState) {
1764 65
            case self::STATE_NEW:
1765 65
            case self::STATE_REMOVED:
1766
                // nothing to do
1767 2
                break;
1768
1769 65
            case self::STATE_MANAGED:
1770 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...
1771
1772 65
                if ($invoke !== ListenersInvoker::INVOKE_NONE) {
1773 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...
1774
                }
1775
1776 65
                $this->scheduleForDelete($entity);
1777 65
                break;
1778
1779
            case self::STATE_DETACHED:
1780
                throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
1781
            default:
1782
                throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
1783
        }
1784
1785 65
    }
1786
1787
    /**
1788
     * Merges the state of the given detached entity into this UnitOfWork.
1789
     *
1790
     * @param object $entity
1791
     *
1792
     * @return object The managed copy of the entity.
1793
     *
1794
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1795
     *         attribute and the version check against the managed copy fails.
1796
     *
1797
     * @todo Require active transaction!? OptimisticLockException may result in undefined state!?
1798
     */
1799 40
    public function merge($entity)
1800
    {
1801 40
        $visited = array();
1802
1803 40
        return $this->doMerge($entity, $visited);
1804
    }
1805
1806
    /**
1807
     * Executes a merge operation on an entity.
1808
     *
1809
     * @param object      $entity
1810
     * @param array       $visited
1811
     * @param object|null $prevManagedCopy
1812
     * @param array|null  $assoc
1813
     *
1814
     * @return object The managed copy of the entity.
1815
     *
1816
     * @throws OptimisticLockException If the entity uses optimistic locking through a version
1817
     *         attribute and the version check against the managed copy fails.
1818
     * @throws ORMInvalidArgumentException If the entity instance is NEW.
1819
     * @throws EntityNotFoundException
1820
     */
1821 40
    private function doMerge($entity, array &$visited, $prevManagedCopy = null, $assoc = null)
1822
    {
1823 40
        $oid = spl_object_hash($entity);
1824
1825 40
        if (isset($visited[$oid])) {
1826 4
            $managedCopy = $visited[$oid];
1827
1828 4
            if ($prevManagedCopy !== null) {
1829 4
                $this->updateAssociationWithMergedEntity($entity, $assoc, $prevManagedCopy, $managedCopy);
0 ignored issues
show
Bug introduced by
It seems like $assoc defined by parameter $assoc on line 1821 can also be of type null; however, Doctrine\ORM\UnitOfWork:...ationWithMergedEntity() does only seem to accept array, maybe add an additional type check?

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

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

An additional type check may prevent trouble.

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

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

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

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

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

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

An additional type check may prevent trouble.

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2186 1
                    continue;
2187
                }
2188
2189 8
                if ($relatedEntities instanceof PersistentCollection) {
2190
                    // Unwrap so that foreach() does not initialize
2191 5
                    $relatedEntities = $relatedEntities->unwrap();
2192
                }
2193
2194 8
                foreach ($relatedEntities as $relatedEntity) {
2195 8
                    $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
2196
                }
2197 7
            } else if ($relatedEntities !== null) {
2198 14
                $this->doMerge($relatedEntities, $visited, $managedCopy, $assoc);
2199
            }
2200
        }
2201 38
    }
2202
2203
    /**
2204
     * Cascades the save operation to associated entities.
2205
     *
2206
     * @param object $entity
2207
     * @param array  $visited
2208
     *
2209
     * @return void
2210
     */
2211 1012
    private function cascadePersist($entity, array &$visited)
2212
    {
2213 1012
        $class = $this->em->getClassMetadata(get_class($entity));
2214
2215 1012
        $associationMappings = array_filter(
2216 1012
            $class->associationMappings,
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2538 311
            $oid = spl_object_hash($entity);
2539
2540
            if (
2541 311
                isset($hints[Query::HINT_REFRESH])
2542 311
                && isset($hints[Query::HINT_REFRESH_ENTITY])
2543 311
                && ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
2544 311
                && $unmanagedProxy instanceof Proxy
2545 311
                && $this->isIdentifierEquals($unmanagedProxy, $entity)
2546
            ) {
2547
                // DDC-1238 - we have a managed instance, but it isn't the provided one.
2548
                // Therefore we clear its identifier. Also, we must re-fetch metadata since the
2549
                // refreshed object may be anything
2550
2551 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...
2552 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...
2553
                }
2554
2555 2
                return $unmanagedProxy;
2556
            }
2557
2558 309
            if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
2559 21
                $entity->__setInitialized(true);
2560
2561 21
                $overrideLocalValues = true;
2562
2563 21
                if ($entity instanceof NotifyPropertyChanged) {
2564 21
                    $entity->addPropertyChangedListener($this);
2565
                }
2566
            } else {
2567 290
                $overrideLocalValues = isset($hints[Query::HINT_REFRESH]);
2568
2569
                // If only a specific entity is set to refresh, check that it's the one
2570 290
                if (isset($hints[Query::HINT_REFRESH_ENTITY])) {
2571 72
                    $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity;
2572
                }
2573
            }
2574
2575 309
            if ($overrideLocalValues) {
2576
                // inject ObjectManager upon refresh.
2577 112
                if ($entity instanceof ObjectManagerAware) {
2578 3
                    $entity->injectObjectManager($this->em, $class);
2579
                }
2580
2581 309
                $this->originalEntityData[$oid] = $data;
2582
            }
2583
        } else {
2584 659
            $entity = $this->newInstance($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
2585 659
            $oid    = spl_object_hash($entity);
2586
2587 659
            $this->entityIdentifiers[$oid]  = $id;
2588 659
            $this->entityStates[$oid]       = self::STATE_MANAGED;
2589 659
            $this->originalEntityData[$oid] = $data;
2590
2591 659
            $this->identityMap[$class->rootEntityName][$idHash] = $entity;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2592
2593 659
            if ($entity instanceof NotifyPropertyChanged) {
2594 2
                $entity->addPropertyChangedListener($this);
2595
            }
2596
2597 659
            $overrideLocalValues = true;
2598
        }
2599
2600 799
        if ( ! $overrideLocalValues) {
2601 219
            return $entity;
2602
        }
2603
2604 696
        foreach ($data as $field => $value) {
2605 696
            if (isset($class->fieldMappings[$field])) {
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2614
            unset($this->eagerLoadingEntities[$class->rootEntityName]);
2615
        }
2616
2617
        // Properly initialize any unfetched associations, if partial objects are not allowed.
2618 696
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
2619 33
            return $entity;
2620
        }
2621
2622 663
        foreach ($class->associationMappings as $field => $assoc) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2623
            // Check if the association is not among the fetch-joined associations already.
2624 580
            if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
2625 254
                continue;
2626
            }
2627
2628 558
            $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
2629
2630
            switch (true) {
2631 558
                case ($assoc['type'] & ClassMetadata::TO_ONE):
2632 478
                    if ( ! $assoc['isOwningSide']) {
2633
2634
                        // use the given entity association
2635 64
                        if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2636
2637 2
                            $this->originalEntityData[$oid][$field] = $data[$field];
2638
2639 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...
2640 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...
2641
2642 2
                            continue 2;
2643
                        }
2644
2645
                        // Inverse side of x-to-one can never be lazy
2646 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...
2647
2648 62
                        continue 2;
2649
                    }
2650
2651
                    // use the entity association
2652 478
                    if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_hash($data[$field])])) {
2653 37
                        $class->reflFields[$field]->setValue($entity, $data[$field]);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2654 37
                        $this->originalEntityData[$oid][$field] = $data[$field];
2655
2656 37
                        continue;
2657
                    }
2658
2659 471
                    $associatedId = array();
2660
2661
                    // TODO: Is this even computed right in all cases of composite keys?
2662 471
                    foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
2663 471
                        $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
2664
2665 471
                        if ($joinColumnValue !== null) {
2666 282
                            if ($targetClass->containsForeignIdentifier) {
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2727 155
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2728 155
                                    break;
2729
2730
                                // Deferred eager load only works for single identifier classes
2731 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...
2732
                                    // TODO: Is there a faster approach?
2733 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...
2734
2735 7
                                    $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
2736 7
                                    break;
2737
2738
                                default:
2739
                                    // TODO: This is very imperformant, ignore it?
2740
                                    $newValue = $this->em->find($assoc['targetEntity'], $associatedId);
2741
                                    break;
2742
                            }
2743
2744
                            // PERF: Inlined & optimized code from UnitOfWork#registerManaged()
2745 162
                            $newValueOid = spl_object_hash($newValue);
2746 162
                            $this->entityIdentifiers[$newValueOid] = $associatedId;
2747 162
                            $this->identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue;
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2748
2749
                            if (
2750 162
                                $newValue instanceof NotifyPropertyChanged &&
2751 162
                                ( ! $newValue instanceof Proxy || $newValue->__isInitialized())
2752
                            ) {
2753
                                $newValue->addPropertyChangedListener($this);
2754
                            }
2755 162
                            $this->entityStates[$newValueOid] = self::STATE_MANAGED;
2756
                            // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
2757 162
                            break;
2758
                    }
2759
2760 282
                    $this->originalEntityData[$oid][$field] = $newValue;
2761 282
                    $class->reflFields[$field]->setValue($entity, $newValue);
0 ignored issues
show
Bug introduced by
Accessing reflFields on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2762
2763 282
                    if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
2764 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...
2765 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...
2766
                    }
2767
2768 282
                    break;
2769
2770
                default:
2771
                    // Ignore if its a cached collection
2772 480
                    if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) {
2773
                        break;
2774
                    }
2775
2776
                    // use the given collection
2777 480
                    if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) {
2778
2779 2
                        $data[$field]->setOwner($entity, $assoc);
2780
2781 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...
2782 2
                        $this->originalEntityData[$oid][$field] = $data[$field];
2783
2784 2
                        break;
2785
                    }
2786
2787
                    // Inject collection
2788 480
                    $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection);
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2793 480
                    $reflField->setValue($entity, $pColl);
2794
2795 480
                    if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
2796 4
                        $this->loadCollection($pColl);
2797 4
                        $pColl->takeSnapshot();
2798
                    }
2799
2800 480
                    $this->originalEntityData[$oid][$field] = $pColl;
2801 558
                    break;
2802
            }
2803
        }
2804
2805 663
        if ($overrideLocalValues) {
2806
            // defer invoking of postLoad event to hydration complete step
2807 663
            $this->hydrationCompleteHandler->deferPostLoadInvoking($class, $entity);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
2808
        }
2809
2810 663
        return $entity;
2811
    }
2812
2813
    /**
2814
     * @return void
2815
     */
2816 857
    public function triggerEagerLoads()
2817
    {
2818 857
        if ( ! $this->eagerLoadingEntities) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->eagerLoadingEntities of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2819 857
            return;
2820
        }
2821
2822
        // avoid infinite recursion
2823 7
        $eagerLoadingEntities       = $this->eagerLoadingEntities;
2824 7
        $this->eagerLoadingEntities = array();
2825
2826 7
        foreach ($eagerLoadingEntities as $entityName => $ids) {
2827 7
            if ( ! $ids) {
2828
                continue;
2829
            }
2830
2831 7
            $class = $this->em->getClassMetadata($entityName);
2832
2833 7
            $this->getEntityPersister($entityName)->loadAll(
2834 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...
2835
            );
2836
        }
2837 7
    }
2838
2839
    /**
2840
     * Initializes (loads) an uninitialized persistent collection of an entity.
2841
     *
2842
     * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize.
2843
     *
2844
     * @return void
2845
     *
2846
     * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
2847
     */
2848 142
    public function loadCollection(PersistentCollection $collection)
2849
    {
2850 142
        $assoc     = $collection->getMapping();
2851 142
        $persister = $this->getEntityPersister($assoc['targetEntity']);
2852
2853 142
        switch ($assoc['type']) {
2854 142
            case ClassMetadata::ONE_TO_MANY:
2855 75
                $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection);
2856 75
                break;
2857
2858 76
            case ClassMetadata::MANY_TO_MANY:
2859 76
                $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
2860 76
                break;
2861
        }
2862
2863 142
        $collection->setInitialized(true);
2864 142
    }
2865
2866
    /**
2867
     * Gets the identity map of the UnitOfWork.
2868
     *
2869
     * @return array
2870
     */
2871 2
    public function getIdentityMap()
2872
    {
2873 2
        return $this->identityMap;
2874
    }
2875
2876
    /**
2877
     * Gets the original data of an entity. The original data is the data that was
2878
     * present at the time the entity was reconstituted from the database.
2879
     *
2880
     * @param object $entity
2881
     *
2882
     * @return array
2883
     */
2884 114
    public function getOriginalEntityData($entity)
2885
    {
2886 114
        $oid = spl_object_hash($entity);
2887
2888 114
        if (isset($this->originalEntityData[$oid])) {
2889 111
            return $this->originalEntityData[$oid];
2890
        }
2891
2892 4
        return array();
2893
    }
2894
2895
    /**
2896
     * @ignore
2897
     *
2898
     * @param object $entity
2899
     * @param array  $data
2900
     *
2901
     * @return void
2902
     */
2903
    public function setOriginalEntityData($entity, array $data)
2904
    {
2905
        $this->originalEntityData[spl_object_hash($entity)] = $data;
2906
    }
2907
2908
    /**
2909
     * INTERNAL:
2910
     * Sets a property value of the original data array of an entity.
2911
     *
2912
     * @ignore
2913
     *
2914
     * @param string $oid
2915
     * @param string $property
2916
     * @param mixed  $value
2917
     *
2918
     * @return void
2919
     */
2920 307
    public function setOriginalEntityProperty($oid, $property, $value)
2921
    {
2922 307
        $this->originalEntityData[$oid][$property] = $value;
2923 307
    }
2924
2925
    /**
2926
     * Gets the identifier of an entity.
2927
     * The returned value is always an array of identifier values. If the entity
2928
     * has a composite identifier then the identifier values are in the same
2929
     * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
2930
     *
2931
     * @param object $entity
2932
     *
2933
     * @return array The identifier values.
2934
     */
2935 836
    public function getEntityIdentifier($entity)
2936
    {
2937 836
        return $this->entityIdentifiers[spl_object_hash($entity)];
2938
    }
2939
2940
    /**
2941
     * Processes an entity instance to extract their identifier values.
2942
     *
2943
     * @param object $entity The entity instance.
2944
     *
2945
     * @return mixed A scalar value.
2946
     *
2947
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
2948
     */
2949 126
    public function getSingleIdentifierValue($entity)
2950
    {
2951 126
        $class = $this->em->getClassMetadata(get_class($entity));
2952
2953 126
        if ($class->isIdentifierComposite) {
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
2962
    }
2963
2964
    /**
2965
     * Tries to find an entity with the given identifier in the identity map of
2966
     * this UnitOfWork.
2967
     *
2968
     * @param mixed  $id            The entity identifier to look for.
2969
     * @param string $rootClassName The name of the root class of the mapped entity hierarchy.
2970
     *
2971
     * @return object|bool Returns the entity with the specified identifier if it exists in
2972
     *                     this UnitOfWork, FALSE otherwise.
2973
     */
2974 515
    public function tryGetById($id, $rootClassName)
2975
    {
2976 515
        $idHash = implode(' ', (array) $id);
2977
2978 515
        if (isset($this->identityMap[$rootClassName][$idHash])) {
2979 78
            return $this->identityMap[$rootClassName][$idHash];
2980
        }
2981
2982 501
        return false;
2983
    }
2984
2985
    /**
2986
     * Schedules an entity for dirty-checking at commit-time.
2987
     *
2988
     * @param object $entity The entity to schedule for dirty-checking.
2989
     *
2990
     * @return void
2991
     *
2992
     * @todo Rename: scheduleForSynchronization
2993
     */
2994 5
    public function scheduleForDirtyCheck($entity)
2995
    {
2996 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...
2997
2998 5
        $this->scheduledForSynchronization[$rootClassName][spl_object_hash($entity)] = $entity;
2999 5
    }
3000
3001
    /**
3002
     * Checks whether the UnitOfWork has any pending insertions.
3003
     *
3004
     * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise.
3005
     */
3006
    public function hasPendingInsertions()
3007
    {
3008
        return ! empty($this->entityInsertions);
3009
    }
3010
3011
    /**
3012
     * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the
3013
     * number of entities in the identity map.
3014
     *
3015
     * @return integer
3016
     */
3017 1
    public function size()
3018
    {
3019
        $countArray = array_map(function ($item) { return count($item); }, $this->identityMap);
3020
3021 1
        return array_sum($countArray);
3022
    }
3023
3024
    /**
3025
     * Gets the EntityPersister for an Entity.
3026
     *
3027
     * @param string $entityName The name of the Entity.
3028
     *
3029
     * @return \Doctrine\ORM\Persisters\Entity\EntityPersister
3030
     */
3031 1061
    public function getEntityPersister($entityName)
3032
    {
3033 1061
        if (isset($this->persisters[$entityName])) {
3034 838
            return $this->persisters[$entityName];
3035
        }
3036
3037 1061
        $class = $this->em->getClassMetadata($entityName);
3038
3039
        switch (true) {
3040 1061
            case ($class->isInheritanceTypeNone()):
3041 1024
                $persister = new BasicEntityPersister($this->em, $class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

Loading history...
3042 1024
                break;
3043
3044 357
            case ($class->isInheritanceTypeSingleTable()):
3045 211
                $persister = new SingleTablePersister($this->em, $class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

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

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

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

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

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

Loading history...
3050 336
                break;
3051
3052
            default:
3053
                throw new \RuntimeException('No persister found for entity.');
3054
        }
3055
3056 1061
        if ($this->hasCache && $class->cache !== null) {
0 ignored issues
show
Bug introduced by
Accessing cache on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

Available Fixes

  1. Adding an additional type check:

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

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

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

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

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