Failed Conditions
Pull Request — master (#6649)
by Marco
17:00
created

ObjectHydrator::getEntity()   C

Complexity

Conditions 14
Paths 64

Size

Total Lines 71
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 14.0336

Importance

Changes 0
Metric Value
dl 0
loc 71
ccs 34
cts 36
cp 0.9444
rs 5.5568
c 0
b 0
f 0
cc 14
eloc 37
nc 64
nop 2
crap 14.0336

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Internal\Hydration;
21
22
use Doctrine\ORM\UnitOfWork;
23
use PDO;
24
use Doctrine\ORM\Mapping\ClassMetadata;
25
use Doctrine\ORM\PersistentCollection;
26
use Doctrine\ORM\Query;
27
use Doctrine\Common\Collections\ArrayCollection;
28
use Doctrine\ORM\Proxy\Proxy;
29
30
/**
31
 * The ObjectHydrator constructs an object graph out of an SQL result set.
32
 *
33
 * Internal note: Highly performance-sensitive code.
34
 *
35
 * @since  2.0
36
 * @author Roman Borschel <[email protected]>
37
 * @author Guilherme Blanco <[email protected]>
38
 * @author Fabio B. Silva <[email protected]>
39
 */
40
class ObjectHydrator extends AbstractHydrator
41
{
42
    /**
43
     * @var array
44
     */
45
    private $identifierMap = [];
46
47
    /**
48
     * @var object[] indexed by oid
49
     */
50
    private $createdEntities = [];
51
52
    /**
53
     * @var array
54
     */
55
    private $resultPointers = [];
56
57
    /**
58
     * @var array
59
     */
60
    private $idTemplate = [];
61
62
    /**
63
     * @var integer
64
     */
65
    private $resultCounter = 0;
66
67
    /**
68
     * @var array
69
     */
70
    private $rootAliases = [];
71
72
    /**
73
     * @var array
74
     */
75
    private $initializedCollections = [];
76
77
    /**
78
     * @var array
79
     */
80
    private $existingCollections = [];
81
82
    /**
83
     * {@inheritdoc}
84
     */
85 686
    protected function prepare()
86
    {
87 686
        if ( ! isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
88 585
            $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true;
89
        }
90
91 686
        foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
92 652
            $this->identifierMap[$dqlAlias] = [];
93 652
            $this->idTemplate[$dqlAlias]    = '';
94
95
            // Remember which associations are "fetch joined", so that we know where to inject
96
            // collection stubs or proxies and where not.
97 652
            if ( ! isset($this->_rsm->relationMap[$dqlAlias])) {
98 652
                continue;
99
            }
100
101 331
            $parent = $this->_rsm->parentAliasMap[$dqlAlias];
102
103 331
            if ( ! isset($this->_rsm->aliasMap[$parent])) {
104 1
                throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent);
105
            }
106
107 330
            $sourceClassName = $this->_rsm->aliasMap[$parent];
108 330
            $sourceClass     = $this->getClassMetadata($sourceClassName);
109 330
            $assoc           = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
110
111 330
            $this->_hints['fetched'][$parent][$assoc['fieldName']] = true;
112
113 330
            if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) {
114 35
                continue;
115
            }
116
117
            // Mark any non-collection opposite sides as fetched, too.
118 309
            if ($assoc['mappedBy']) {
119 260
                $this->_hints['fetched'][$dqlAlias][$assoc['mappedBy']] = true;
120
121 260
                continue;
122
            }
123
124
            // handle fetch-joined owning side bi-directional one-to-one associations
125 68
            if ($assoc['inversedBy']) {
126 47
                $class        = $this->getClassMetadata($className);
127 47
                $inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
128
129 47
                if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
130 28
                    continue;
131
                }
132
133 41
                $this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true;
134
            }
135
        }
136 685
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 680
    protected function cleanup()
142
    {
143 680
        $eagerLoad = (isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) && $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] == true;
144
145 680
        parent::cleanup();
146
147 680
        $this->identifierMap =
148 680
        $this->initializedCollections =
149 680
        $this->existingCollections =
150 680
        $this->resultPointers = [];
151
152 680
        if ($eagerLoad) {
153 680
            $this->_uow->triggerEagerLoads();
154
        }
155
156 680
        $this->_uow->hydrationComplete();
157 680
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 679 View Code Duplication
    protected function hydrateAllData()
163
    {
164 679
        $result = [];
165
166 679
        while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
167 640
            $this->hydrateRowData($row, $result);
168
        }
169
170
        // Take snapshots from all newly initialized collections
171 676
        foreach ($this->initializedCollections as $coll) {
172 71
            $coll->takeSnapshot();
173
        }
174
175 676
        return $result;
176
    }
177
178
    /**
179
     * Initializes a related collection.
180
     *
181
     * @param object        $entity         The entity to which the collection belongs.
182
     * @param ClassMetadata $class
183
     * @param string        $fieldName      The name of the field on the entity that holds the collection.
184
     * @param string        $parentDqlAlias Alias of the parent fetch joining this collection.
185
     *
186
     * @return \Doctrine\ORM\PersistentCollection
187
     */
188 103
    private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
189
    {
190 103
        $oid      = spl_object_hash($entity);
191 103
        $relation = $class->associationMappings[$fieldName];
192 103
        $value    = $class->reflFields[$fieldName]->getValue($entity);
193
194 103
        if ($value === null || is_array($value)) {
195 67
            $value = new ArrayCollection((array) $value);
196
        }
197
198 103
        if ( ! $value instanceof PersistentCollection) {
199 67
            $value = new PersistentCollection(
200 67
                $this->_em, $this->_metadataCache[$relation['targetEntity']], $value
201
            );
202 67
            $value->setOwner($entity, $relation);
203
204 67
            $class->reflFields[$fieldName]->setValue($entity, $value);
205 67
            $this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
206
207 67
            $this->initializedCollections[$oid . $fieldName] = $value;
208
        } else if (
209 40
            isset($this->_hints[Query::HINT_REFRESH]) ||
210 40
            isset($this->_hints['fetched'][$parentDqlAlias][$fieldName]) &&
211 40
             ! $value->isInitialized()
212
        ) {
213
            // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
214 6
            $value->setDirty(false);
215 6
            $value->setInitialized(true);
216 6
            $value->unwrap()->clear();
217
218 6
            $this->initializedCollections[$oid . $fieldName] = $value;
219
        } else {
220
            // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
221 35
            $this->existingCollections[$oid . $fieldName] = $value;
222
        }
223
224 103
        return $value;
225
    }
226
227
    /**
228
     * Gets an entity instance.
229
     *
230
     * @param array  $data     The instance data.
231
     * @param string $dqlAlias The DQL alias of the entity's class.
232
     *
233
     * @return object The entity.
234
     *
235
     * @throws HydrationException
236
     */
237 610
    private function getEntity(array $data, $dqlAlias)
238
    {
239 610
        $className = $this->_rsm->aliasMap[$dqlAlias];
240
241 610
        if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
242 69
            $fieldName = $this->_rsm->discriminatorColumns[$dqlAlias];
243
244 69
            if ( ! isset($this->_rsm->metaMappings[$fieldName])) {
245 1
                throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $fieldName, $dqlAlias);
246
            }
247
248 68
            $discrColumn = $this->_rsm->metaMappings[$fieldName];
249
250 68
            if ( ! isset($data[$discrColumn])) {
251 1
                throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias);
252
            }
253
254 68
            if ($data[$discrColumn] === "") {
255
                throw HydrationException::emptyDiscriminatorValue($dqlAlias);
256
            }
257
258 68
            $discrMap = $this->_metadataCache[$className]->discriminatorMap;
259 68
            $discriminatorValue = (string) $data[$discrColumn];
260
261 68
            if ( ! isset($discrMap[$discriminatorValue])) {
262 1
                throw HydrationException::invalidDiscriminatorValue($discriminatorValue, array_keys($discrMap));
263
            }
264
265 67
            $className = $discrMap[$discriminatorValue];
266
267 67
            unset($data[$discrColumn]);
268
        }
269
270 608
        if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->rootAliases[$dqlAlias])) {
271 24
            $this->registerManaged($this->_metadataCache[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
272
        }
273
274 608
        $this->_hints['fetchAlias'] = $dqlAlias;
275
276
        // super slow, but trying it out for now
277 608
        $metadata  = $this->_metadataCache[$className] ?? $this->_metadataCache[$className] = $this->_em->getClassMetadata($className);
278 608
        $idColumns = [];
279
280 608
        foreach ($metadata->identifier as $idFieldName) {
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...
281 608
            $idColumns[] = isset($metadata->associationMappings[$idFieldName])
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...
282 38
                ? $metadata->associationMappings[$idFieldName]['joinColumns'][0]['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...
283 608
                : $idFieldName;
284
        }
285
286 608
        $idKeys   = array_flip($idColumns);
287
        $idValues = array_intersect_key(array_filter($data, function ($idValue) { return null !== $idValue; }), $idKeys);
288
289
290 608
        if (count($idValues) === count($idKeys)) {
291 608
            if (! $this->getEntityFromIdentityMap($className, $data)) {
292 466
                $entity = $this->_uow->createEntity($className, $data, $this->_hints);
293
294 466
                $this->createdEntities[\spl_object_hash($entity)] = true;
295
296 466
                return $entity;
297
            }
298
        }
299
300 250
        $entity = $this->_uow->createEntity($className, $data, $this->_hints);
301
302 250
        if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
303
            $this->createdEntities[\spl_object_hash($entity)] = true;
304
        }
305
306 250
        return $entity;
307
    }
308
309
    /**
310
     * @param string $className
311
     * @param array  $data
312
     *
313
     * @return mixed
314
     */
315 608
    private function getEntityFromIdentityMap($className, array $data)
316
    {
317
        // TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
318 608
        $class = $this->_metadataCache[$className];
319
320
        /* @var $class ClassMetadata */
321 608
        if ($class->isIdentifierComposite) {
322 37
            $idHash = '';
323
324 37 View Code Duplication
            foreach ($class->identifier as $fieldName) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
325 37
                $idHash .= ' ' . (isset($class->associationMappings[$fieldName])
326 29
                    ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
327 37
                    : $data[$fieldName]);
328
            }
329
330 37
            return $this->_uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName);
331
        }
332
333 600
        if (isset($class->associationMappings[$class->identifier[0]])) {
334 18
            return $this->_uow->tryGetByIdHash($data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']], $class->rootEntityName);
335
        }
336
337 598
        return $this->_uow->tryGetByIdHash($data[$class->identifier[0]], $class->rootEntityName);
338
    }
339
340
    /**
341
     * Hydrates a single row in an SQL result set.
342
     *
343
     * @internal
344
     * First, the data of the row is split into chunks where each chunk contains data
345
     * that belongs to a particular component/class. Afterwards, all these chunks
346
     * are processed, one after the other. For each chunk of class data only one of the
347
     * following code paths is executed:
348
     *
349
     * Path A: The data chunk belongs to a joined/associated object and the association
350
     *         is collection-valued.
351
     * Path B: The data chunk belongs to a joined/associated object and the association
352
     *         is single-valued.
353
     * Path C: The data chunk belongs to a root result element/object that appears in the topmost
354
     *         level of the hydrated result. A typical example are the objects of the type
355
     *         specified by the FROM clause in a DQL query.
356
     *
357
     * @param array $row    The data of the row to process.
358
     * @param array $result The result array to fill.
359
     *
360
     * @return void
361
     */
362 645
    protected function hydrateRowData(array $row, array &$result)
363
    {
364
        // Initialize
365 645
        $id = $this->idTemplate; // initialize the id-memory
366 645
        $nonemptyComponents = [];
367
        // Split the row data into chunks of class data.
368 645
        $rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
369
370
        // reset result pointers for each data row
371 645
        $this->resultPointers = [];
372
373
        // Hydrate the data chunks
374 645
        foreach ($rowData['data'] as $dqlAlias => $data) {
375 610
            $entityName = $this->_rsm->aliasMap[$dqlAlias];
376
377 610
            if (isset($this->_rsm->parentAliasMap[$dqlAlias])) {
378
                // It's a joined result
379
380 322
                $parentAlias = $this->_rsm->parentAliasMap[$dqlAlias];
381
                // we need the $path to save into the identifier map which entities were already
382
                // seen for this parent-child relationship
383 322
                $path = $parentAlias . '.' . $dqlAlias;
384
385
                // We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
386 322
                if ( ! isset($nonemptyComponents[$parentAlias])) {
387
                    // TODO: Add special case code where we hydrate the right join objects into identity map at least
388 2
                    continue;
389
                }
390
391 322
                $parentClass    = $this->_metadataCache[$this->_rsm->aliasMap[$parentAlias]];
392 322
                $relationField  = $this->_rsm->relationMap[$dqlAlias];
393 322
                $relation       = $parentClass->associationMappings[$relationField];
394 322
                $reflField      = $parentClass->reflFields[$relationField];
395
396
                // Get a reference to the parent object to which the joined element belongs.
397 322
                if ($this->_rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
398 18
                    $objectClass = $this->resultPointers[$parentAlias];
399 18
                    $parentObject = $objectClass[key($objectClass)];
400 306
                } else if (isset($this->resultPointers[$parentAlias])) {
401 306
                    $parentObject = $this->resultPointers[$parentAlias];
402
                } else {
403
                    // Parent object of relation not found, mark as not-fetched again
404 2
                    $element = $this->getEntity($data, $dqlAlias);
405
406
                    // Update result pointer and provide initial fetch data for parent
407 2
                    $this->resultPointers[$dqlAlias] = $element;
408 2
                    $rowData['data'][$parentAlias][$relationField] = $element;
409
410
                    // Mark as not-fetched again
411 2
                    unset($this->_hints['fetched'][$parentAlias][$relationField]);
412 2
                    continue;
413
                }
414
415 322
                $oid = spl_object_hash($parentObject);
416
417
                // Check the type of the relation (many or single-valued)
418 322
                if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
419
                    // PATH A: Collection-valued association
420 104
                    $reflFieldValue = $reflField->getValue($parentObject);
421
422 104
                    if (isset($nonemptyComponents[$dqlAlias])) {
423 100
                        $collKey = $oid . $relationField;
424 100
                        if (isset($this->initializedCollections[$collKey])) {
425 47
                            $reflFieldValue = $this->initializedCollections[$collKey];
426 100
                        } else if ( ! isset($this->existingCollections[$collKey])) {
427 100
                            $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
428
                        }
429
430 100
                        $indexExists    = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
431 100
                        $index          = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
432 100
                        $indexIsValid   = $index !== false ? isset($reflFieldValue[$index]) : false;
433
434 100
                        if ( ! $indexExists || ! $indexIsValid) {
435 100
                            if (isset($this->existingCollections[$collKey])) {
436
                                // Collection exists, only look for the element in the identity map.
437 35
                                if ($element = $this->getEntityFromIdentityMap($entityName, $data)) {
438 35
                                    $this->resultPointers[$dqlAlias] = $element;
439
                                } else {
440 35
                                    unset($this->resultPointers[$dqlAlias]);
441
                                }
442
                            } else {
443 68
                                $element = $this->getEntity($data, $dqlAlias);
444
445 68
                                if (isset($this->_rsm->indexByMap[$dqlAlias])) {
446 12
                                    $indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
447 12
                                    $reflFieldValue->hydrateSet($indexValue, $element);
448 12
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
449
                                } else {
450 56
                                    $reflFieldValue->hydrateAdd($element);
451 56
                                    $reflFieldValue->last();
452 56
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
453
                                }
454
                                // Update result pointer
455 100
                                $this->resultPointers[$dqlAlias] = $element;
456
                            }
457
                        } else {
458
                            // Update result pointer
459 100
                            $this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
460
                        }
461 9
                    } else if ( ! $reflFieldValue) {
462 5
                        $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
0 ignored issues
show
Unused Code introduced by
$reflFieldValue is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
463 6
                    } else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
464 104
                        $reflFieldValue->setInitialized(true);
465
                    }
466
467
                } else {
468
                    // PATH B: Single-valued association
469 240
                    $reflFieldValue = $reflField->getValue($parentObject);
470
471 240
                    if (isset($this->createdEntities[$oid]) || isset($this->_hints[Query::HINT_REFRESH])) {
472
//                    if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && !$reflFieldValue->__isInitialized__)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
473
                        // we only need to take action if this value is null,
474
                        // we refresh the entity or its an uninitialized proxy.
475 220
                        if (isset($nonemptyComponents[$dqlAlias])) {
476 120
                            $element = $this->getEntity($data, $dqlAlias);
477 119
                            $reflField->setValue($parentObject, $element);
478 119
                            $this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
479 119
                            $targetClass = $this->_metadataCache[$relation['targetEntity']];
480
481 119
                            if ($relation['isOwningSide']) {
482
                                // TODO: Just check hints['fetched'] here?
483
                                // If there is an inverse mapping on the target class its bidirectional
484 53
                                if ($relation['inversedBy']) {
485 36
                                    $inverseAssoc = $targetClass->associationMappings[$relation['inversedBy']];
486 36 View Code Duplication
                                    if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
487 13
                                        $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject);
488 36
                                        $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc['fieldName'], $parentObject);
489
                                    }
490 18
                                } else if ($parentClass === $targetClass && $relation['mappedBy']) {
491
                                    // Special case: bi-directional self-referencing one-one on the same class
492 53
                                    $targetClass->reflFields[$relationField]->setValue($element, $parentObject);
493
                                }
494 View Code Duplication
                            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
495
                                // For sure bidirectional, as there is no inverse side in unidirectional mappings
496 69
                                $targetClass->reflFields[$relation['mappedBy']]->setValue($element, $parentObject);
497 69
                                $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation['mappedBy'], $parentObject);
498
                            }
499
                            // Update result pointer
500 119
                            $this->resultPointers[$dqlAlias] = $element;
501
                        } else {
502 120
                            $this->_uow->setOriginalEntityProperty($oid, $relationField, null);
503 219
                            $reflField->setValue($parentObject, null);
504
                        }
505
                        // else leave $reflFieldValue null for single-valued associations
506
                    } else {
507
                        // Update result pointer
508 321
                        $this->resultPointers[$dqlAlias] = $reflFieldValue;
509
                    }
510
                }
511
            } else {
512
                // PATH C: Its a root result element
513 610
                $this->rootAliases[$dqlAlias] = true; // Mark as root alias
514 610
                $entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
515
516
                // if this row has a NULL value for the root result id then make it a null result.
517 610 View Code Duplication
                if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
518 6
                    if ($this->_rsm->isMixed) {
519 2
                        $result[] = [$entityKey => null];
520
                    } else {
521 4
                        $result[] = null;
522
                    }
523 6
                    $resultKey = $this->resultCounter;
524 6
                    ++$this->resultCounter;
525 6
                    continue;
526
                }
527
528
                // check for existing result from the iterations before
529 610
                if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
530 610
                    $element = $this->getEntity($data, $dqlAlias);
531
532 608
                    if ($this->_rsm->isMixed) {
533 41
                        $element = [$entityKey => $element];
534
                    }
535
536 608
                    if (isset($this->_rsm->indexByMap[$dqlAlias])) {
537 27
                        $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
538
539 27
                        if (isset($this->_hints['collection'])) {
540 10
                            $this->_hints['collection']->hydrateSet($resultKey, $element);
541
                        }
542
543 27
                        $result[$resultKey] = $element;
544
                    } else {
545 591
                        $resultKey = $this->resultCounter;
546 591
                        ++$this->resultCounter;
547
548 591
                        if (isset($this->_hints['collection'])) {
549 110
                            $this->_hints['collection']->hydrateAdd($element);
550
                        }
551
552 591
                        $result[] = $element;
553
                    }
554
555 608
                    $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
556
557
                    // Update result pointer
558 608
                    $this->resultPointers[$dqlAlias] = $element;
559
560
                } else {
561
                    // Update result pointer
562 78
                    $index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
563 78
                    $this->resultPointers[$dqlAlias] = $result[$index];
564 78
                    $resultKey = $index;
565
                }
566
            }
567
568 608 View Code Duplication
            if (isset($this->_hints[Query::HINT_INTERNAL_ITERATION]) && $this->_hints[Query::HINT_INTERNAL_ITERATION]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
569 608
                $this->_uow->hydrationComplete();
570
            }
571
        }
572
573 642
        if ( ! isset($resultKey) ) {
574 35
            $this->resultCounter++;
575
        }
576
577
        // Append scalar values to mixed result sets
578 642 View Code Duplication
        if (isset($rowData['scalars'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
579 54
            if ( ! isset($resultKey) ) {
580 22
                $resultKey = (isset($this->_rsm->indexByMap['scalars']))
581 2
                    ? $row[$this->_rsm->indexByMap['scalars']]
582 22
                    : $this->resultCounter - 1;
583
            }
584
585 54
            foreach ($rowData['scalars'] as $name => $value) {
586 54
                $result[$resultKey][$name] = $value;
587
            }
588
        }
589
590
        // Append new object to mixed result sets
591 642 View Code Duplication
        if (isset($rowData['newObjects'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
592 19
            if ( ! isset($resultKey) ) {
593 13
                $resultKey = $this->resultCounter - 1;
594
            }
595
596
597 19
            $scalarCount = (isset($rowData['scalars'])? count($rowData['scalars']): 0);
598
599 19
            foreach ($rowData['newObjects'] as $objIndex => $newObject) {
600 19
                $class  = $newObject['class'];
601 19
                $args   = $newObject['args'];
602 19
                $obj    = $class->newInstanceArgs($args);
603
604 19
                if ($scalarCount == 0 && count($rowData['newObjects']) == 1 ) {
605 10
                    $result[$resultKey] = $obj;
606
607 10
                    continue;
608
                }
609
610 9
                $result[$resultKey][$objIndex] = $obj;
611
            }
612
        }
613 642
    }
614
615
    /**
616
     * When executed in a hydrate() loop we may have to clear internal state to
617
     * decrease memory consumption.
618
     *
619
     * @param mixed $eventArgs
620
     *
621
     * @return void
622
     */
623 4
    public function onClear($eventArgs)
624
    {
625 4
        parent::onClear($eventArgs);
626
627 4
        $aliases             = array_keys($this->identifierMap);
628
629 4
        $this->identifierMap = array_fill_keys($aliases, []);
630 4
    }
631
}
632