Failed Conditions
Pull Request — 2.7 (#8027)
by
unknown
07:00
created

ObjectHydrator::prepare()   B

Complexity

Conditions 9
Paths 16

Size

Total Lines 49
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 16.9615

Importance

Changes 0
Metric Value
eloc 25
c 0
b 0
f 0
dl 0
loc 49
ccs 14
cts 26
cp 0.5385
rs 8.0555
cc 9
nc 16
nop 0
crap 16.9615
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Internal\Hydration;
6
7
use Doctrine\Common\Collections\Collection;
8
use Doctrine\ORM\Mapping\ClassMetadata;
9
use Doctrine\ORM\Mapping\ManyToManyAssociationMetadata;
0 ignored issues
show
Bug introduced by
The type Doctrine\ORM\Mapping\ManyToManyAssociationMetadata was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Doctrine\ORM\Mapping\ToManyAssociationMetadata;
0 ignored issues
show
Bug introduced by
The type Doctrine\ORM\Mapping\ToManyAssociationMetadata was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Doctrine\ORM\Mapping\ToOneAssociationMetadata;
0 ignored issues
show
Bug introduced by
The type Doctrine\ORM\Mapping\ToOneAssociationMetadata was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Doctrine\ORM\PersistentCollection;
13
use Doctrine\ORM\Query;
14
use Doctrine\ORM\UnitOfWork;
15
use PDO;
16
use ProxyManager\Proxy\GhostObjectInterface;
0 ignored issues
show
Bug introduced by
The type ProxyManager\Proxy\GhostObjectInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
18
/**
19
 * The ObjectHydrator constructs an object graph out of an SQL result set.
20
 *
21
 * Internal note: Highly performance-sensitive code.
22
 */
23
class ObjectHydrator extends AbstractHydrator
24
{
25
    /**
26
     * @var mixed[][]
27
     */
28
    private $identifierMap = [];
29
30
    /**
31
     * @var mixed[]
32
     */
33
    private $resultPointers = [];
34
35
    /**
36
     * @var string[]
37
     */
38
    private $idTemplate = [];
39
40
    /**
41
     * @var int
42
     */
43
    private $resultCounter = 0;
44
45
    /**
46
     * @var bool
47
     */
48
    private $rootAliases = [];
49
50
    /**
51
     * @var Collection[]|object[][]
52
     */
53
    private $initializedCollections = [];
54
55
    /**
56
     * @var Collection[]|object[][]
57
     */
58
    private $existingCollections = [];
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 106
    protected function prepare()
64
    {
65 106
        if (! isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
66 97
            $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true;
67
        }
68
69 106
        foreach ($this->rsm->aliasMap as $dqlAlias => $className) {
70 102
            $this->identifierMap[$dqlAlias] = [];
71 102
            $this->idTemplate[$dqlAlias]    = '';
72
73
            // Remember which associations are "fetch joined", so that we know where to inject
74
            // collection stubs or proxies and where not.
75 102
            if (! isset($this->rsm->relationMap[$dqlAlias])) {
76 102
                continue;
77
            }
78
79 42
            $parent = $this->rsm->parentAliasMap[$dqlAlias];
80
81 42
            if (! isset($this->rsm->aliasMap[$parent])) {
82 1
                throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent);
83
            }
84
85 41
            $sourceClassName = $this->rsm->aliasMap[$parent];
86 41
            $sourceClass     = $this->getClassMetadata($sourceClassName);
87 41
            $association     = $sourceClass->getProperty($this->rsm->relationMap[$dqlAlias]);
0 ignored issues
show
Bug introduced by
The method getProperty() does not exist on Doctrine\ORM\Mapping\ClassMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

87
            /** @scrutinizer ignore-call */ 
88
            $association     = $sourceClass->getProperty($this->rsm->relationMap[$dqlAlias]);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
88
89
            $this->hints['fetched'][$parent][$association->getName()] = true;
90
91
            if ($association instanceof ManyToManyAssociationMetadata) {
92
                continue;
93
            }
94
95
            // Mark any non-collection opposite sides as fetched, too.
96
            if ($association->getMappedBy()) {
97
                $this->hints['fetched'][$dqlAlias][$association->getMappedBy()] = true;
98
99
                continue;
100
            }
101
102
            // handle fetch-joined owning side bi-directional one-to-one associations
103
            if ($association->getInversedBy()) {
104
                $class        = $this->getClassMetadata($className);
105
                $inverseAssoc = $class->getProperty($association->getInversedBy());
106
107
                if (! ($inverseAssoc instanceof ToOneAssociationMetadata)) {
108
                    continue;
109
                }
110
111
                $this->hints['fetched'][$dqlAlias][$inverseAssoc->getName()] = true;
112
            }
113
        }
114 64
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119 34
    protected function cleanup()
120
    {
121 34
        $eagerLoad = (isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD])) && $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] === true;
122
123 34
        parent::cleanup();
124
125 34
        $this->identifierMap          =
126 34
        $this->initializedCollections =
127 34
        $this->existingCollections    =
128 34
        $this->resultPointers         = [];
129
130 34
        if ($eagerLoad) {
131 34
            $this->uow->triggerEagerLoads();
132
        }
133
134 34
        $this->uow->hydrationComplete();
135 34
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140 63
    protected function hydrateAllData()
141
    {
142 63
        $result = [];
143
144 63
        while ($row = $this->stmt->fetch(PDO::FETCH_ASSOC)) {
145 31
            $this->hydrateRowData($row, $result);
146
        }
147
148
        // Take snapshots from all newly initialized collections
149 34
        foreach ($this->initializedCollections as $coll) {
150
            $coll->takeSnapshot();
151
        }
152
153 34
        return $result;
154
    }
155
156
    /**
157
     * Initializes a related collection.
158
     *
159
     * @param object        $entity         The entity to which the collection belongs.
160
     * @param ClassMetadata $class
161
     * @param string        $fieldName      The name of the field on the entity that holds the collection.
162
     * @param string        $parentDqlAlias Alias of the parent fetch joining this collection.
163
     *
164
     * @return \Doctrine\ORM\PersistentCollection
165
     */
166
    private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
167
    {
168
        /** @var ToManyAssociationMetadata $association */
169
        $association = $class->getProperty($fieldName);
170
        $value       = $association->getValue($entity);
171
        $oid         = spl_object_id($entity);
172
173
        if (! $value instanceof PersistentCollection) {
174
            $value = $association->wrap($entity, $value, $this->em);
175
176
            $association->setValue($entity, $value);
177
178
            $this->uow->setOriginalEntityProperty($oid, $fieldName, $value);
179
180
            $this->initializedCollections[$oid . $fieldName] = $value;
181
        } elseif (isset($this->hints[Query::HINT_REFRESH]) ||
182
            (isset($this->hints['fetched'][$parentDqlAlias][$fieldName]) && ! $value->isInitialized())
183
        ) {
184
            // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
185
            $value->setDirty(false);
186
            $value->setInitialized(true);
187
            $value->unwrap()->clear();
188
189
            $this->initializedCollections[$oid . $fieldName] = $value;
190
        } else {
191
            // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
192
            $this->existingCollections[$oid . $fieldName] = $value;
193
        }
194
195
        return $value;
196
    }
197
198
    /**
199
     * Gets an entity instance.
200
     *
201
     * @param mixed[] $data     The instance data.
202
     * @param string  $dqlAlias The DQL alias of the entity's class.
203
     *
204
     * @return object The entity.
205
     *
206
     * @throws HydrationException
207
     */
208
    private function getEntity(array $data, $dqlAlias)
209
    {
210
        $className = $this->rsm->aliasMap[$dqlAlias];
211
212
        if (isset($this->rsm->discriminatorColumns[$dqlAlias])) {
213
            $fieldName = $this->rsm->discriminatorColumns[$dqlAlias];
214
215
            if (! isset($this->rsm->metaMappings[$fieldName])) {
216
                throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $fieldName, $dqlAlias);
217
            }
218
219
            $discrColumn = $this->rsm->metaMappings[$fieldName];
220
221
            if (! isset($data[$discrColumn])) {
222
                throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias);
223
            }
224
225
            if ($data[$discrColumn] === '') {
226
                throw HydrationException::emptyDiscriminatorValue($dqlAlias);
227
            }
228
229
            $discrMap           = $this->metadataCache[$className]->discriminatorMap;
230
            $discriminatorValue = (string) $data[$discrColumn];
231
232
            if (! isset($discrMap[$discriminatorValue])) {
233
                throw HydrationException::invalidDiscriminatorValue($discriminatorValue, array_keys($discrMap));
234
            }
235
236
            $className = $discrMap[$discriminatorValue];
237
238
            unset($data[$discrColumn]);
239
        }
240
241
        if (isset($this->hints[Query::HINT_REFRESH_ENTITY], $this->rootAliases[$dqlAlias])) {
242
            $id = $this->em->getIdentifierFlattener()->flattenIdentifier($this->metadataCache[$className], $data);
0 ignored issues
show
Bug introduced by
The method getIdentifierFlattener() does not exist on Doctrine\ORM\EntityManagerInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

242
            $id = $this->em->/** @scrutinizer ignore-call */ getIdentifierFlattener()->flattenIdentifier($this->metadataCache[$className], $data);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
243
244
            $this->em->getUnitOfWork()->registerManaged($this->hints[Query::HINT_REFRESH_ENTITY], $id, $data);
245
        }
246
247
        $this->hints['fetchAlias'] = $dqlAlias;
248
249
        return $this->uow->createEntity($className, $data, $this->hints);
250
    }
251
252
    /**
253
     * @param string  $className
254
     * @param mixed[] $data
255
     *
256
     * @return mixed
257
     */
258
    private function getEntityFromIdentityMap($className, array $data)
259
    {
260
        /* @var ClassMetadata $class */
261
        $class = $this->metadataCache[$className];
262
        $id    = $this->em->getIdentifierFlattener()->flattenIdentifier($class, $data);
263
264
        return $this->uow->tryGetById($id, $class->getRootClassName());
0 ignored issues
show
Bug introduced by
The method getRootClassName() does not exist on Doctrine\ORM\Mapping\ClassMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

264
        return $this->uow->tryGetById($id, $class->/** @scrutinizer ignore-call */ getRootClassName());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
265
    }
266
267
    /**
268
     * Hydrates a single row in an SQL result set.
269
     *
270
     * @internal
271
     * First, the data of the row is split into chunks where each chunk contains data
272
     * that belongs to a particular component/class. Afterwards, all these chunks
273
     * are processed, one after the other. For each chunk of class data only one of the
274
     * following code paths is executed:
275
     *
276
     * Path A: The data chunk belongs to a joined/associated object and the association
277
     *         is collection-valued.
278
     * Path B: The data chunk belongs to a joined/associated object and the association
279
     *         is single-valued.
280
     * Path C: The data chunk belongs to a root result element/object that appears in the topmost
281
     *         level of the hydrated result. A typical example are the objects of the type
282
     *         specified by the FROM clause in a DQL query.
283
     *
284
     * @param mixed[] $row    The data of the row to process.
285
     * @param mixed[] $result The result array to fill.
286
     */
287 31
    protected function hydrateRowData(array $row, array &$result)
288
    {
289
        // Initialize
290 31
        $id                 = $this->idTemplate; // initialize the id-memory
291 31
        $nonemptyComponents = [];
292
        // Split the row data into chunks of class data.
293 31
        $rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
294
295
        // reset result pointers for each data row
296
        $this->resultPointers = [];
297
298
        // Hydrate the data chunks
299
        foreach ($rowData['data'] as $dqlAlias => $data) {
300
            $entityName = $this->rsm->aliasMap[$dqlAlias];
301
302
            if (isset($this->rsm->parentAliasMap[$dqlAlias])) {
303
                // It's a joined result
304
305
                $parentAlias = $this->rsm->parentAliasMap[$dqlAlias];
306
                // we need the $path to save into the identifier map which entities were already
307
                // seen for this parent-child relationship
308
                $path = $parentAlias . '.' . $dqlAlias;
309
310
                // We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
311
                if (! isset($nonemptyComponents[$parentAlias])) {
312
                    // TODO: Add special case code where we hydrate the right join objects into identity map at least
313
                    continue;
314
                }
315
316
                $parentClass   = $this->metadataCache[$this->rsm->aliasMap[$parentAlias]];
317
                $relationField = $this->rsm->relationMap[$dqlAlias];
318
                $association   = $parentClass->getProperty($relationField);
319
320
                // Get a reference to the parent object to which the joined element belongs.
321
                if ($this->rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
322
                    $objectClass  = $this->resultPointers[$parentAlias];
323
                    $parentObject = $objectClass[key($objectClass)];
324
                } elseif (isset($this->resultPointers[$parentAlias])) {
325
                    $parentObject = $this->resultPointers[$parentAlias];
326
                } else {
327
                    // Parent object of relation not found, mark as not-fetched again
328
                    $element = $this->getEntity($data, $dqlAlias);
329
330
                    // Update result pointer and provide initial fetch data for parent
331
                    $this->resultPointers[$dqlAlias]               = $element;
332
                    $rowData['data'][$parentAlias][$relationField] = $element;
333
334
                    // Mark as not-fetched again
335
                    unset($this->hints['fetched'][$parentAlias][$relationField]);
336
                    continue;
337
                }
338
339
                $oid = spl_object_id($parentObject);
340
341
                // Check the type of the relation (many or single-valued)
342
                if (! ($association instanceof ToOneAssociationMetadata)) {
343
                    // PATH A: Collection-valued association
344
                    $reflFieldValue = $association->getValue($parentObject);
345
346
                    if (isset($nonemptyComponents[$dqlAlias])) {
347
                        $collKey = $oid . $relationField;
348
                        if (isset($this->initializedCollections[$collKey])) {
349
                            $reflFieldValue = $this->initializedCollections[$collKey];
350
                        } elseif (! isset($this->existingCollections[$collKey])) {
351
                            $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
352
                        }
353
354
                        $indexExists  = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
355
                        $index        = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
356
                        $indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false;
357
358
                        if (! $indexExists || ! $indexIsValid) {
359
                            if (isset($this->existingCollections[$collKey])) {
360
                                $element = $this->getEntityFromIdentityMap($entityName, $data);
361
362
                                // Collection exists, only look for the element in the identity map.
363
                                if ($element) {
364
                                    $this->resultPointers[$dqlAlias] = $element;
365
                                } else {
366
                                    unset($this->resultPointers[$dqlAlias]);
367
                                }
368
                            } else {
369
                                $element = $this->getEntity($data, $dqlAlias);
370
371
                                if (isset($this->rsm->indexByMap[$dqlAlias])) {
372
                                    $indexValue = $row[$this->rsm->indexByMap[$dqlAlias]];
373
                                    $reflFieldValue->hydrateSet($indexValue, $element);
374
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
375
                                } else {
376
                                    $reflFieldValue->hydrateAdd($element);
377
                                    $reflFieldValue->last();
378
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
379
                                }
380
                                // Update result pointer
381
                                $this->resultPointers[$dqlAlias] = $element;
382
                            }
383
                        } else {
384
                            // Update result pointer
385
                            $this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
386
                        }
387
                    } elseif (! $reflFieldValue) {
388
                        $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
0 ignored issues
show
Unused Code introduced by
The assignment to $reflFieldValue is dead and can be removed.
Loading history...
389
                    } elseif ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
390
                        $reflFieldValue->setInitialized(true);
391
                    }
392
                } else {
393
                    // PATH B: Single-valued association
394
                    $reflFieldValue = $association->getValue($parentObject);
395
396
                    if (! $reflFieldValue || isset($this->hints[Query::HINT_REFRESH]) ||
397
                        ($reflFieldValue instanceof GhostObjectInterface && ! $reflFieldValue->isProxyInitialized())) {
398
                        // we only need to take action if this value is null,
399
                        // we refresh the entity or its an uninitialized proxy.
400
                        if (isset($nonemptyComponents[$dqlAlias])) {
401
                            $element = $this->getEntity($data, $dqlAlias);
402
403
                            $association->setValue($parentObject, $element);
404
                            $this->uow->setOriginalEntityProperty($oid, $relationField, $element);
405
406
                            $mappedBy    = $association->getMappedBy();
407
                            $targetClass = $this->metadataCache[$association->getTargetEntity()];
408
409
                            if ($association->isOwningSide()) {
410
                                // TODO: Just check hints['fetched'] here?
411
                                // If there is an inverse mapping on the target class its bidirectional
412
                                if ($association->getInversedBy()) {
413
                                    $inverseAssociation = $targetClass->getProperty($association->getInversedBy());
414
415
                                    if ($inverseAssociation instanceof ToOneAssociationMetadata) {
416
                                        $inverseAssociation->setValue($element, $parentObject);
417
418
                                        $this->uow->setOriginalEntityProperty(
419
                                            spl_object_id($element),
420
                                            $inverseAssociation->getName(),
421
                                            $parentObject
422
                                        );
423
                                    }
424
                                }
425
                            } else {
426
                                // For sure bidirectional, as there is no inverse side in unidirectional mappings
427
                                $inverseAssociation = $targetClass->getProperty($mappedBy);
428
429
                                $inverseAssociation->setValue($element, $parentObject);
430
431
                                $this->uow->setOriginalEntityProperty(
432
                                    spl_object_id($element),
433
                                    $mappedBy,
434
                                    $parentObject
435
                                );
436
                            }
437
438
                            // Update result pointer
439
                            $this->resultPointers[$dqlAlias] = $element;
440
                        } else {
441
                            $association->setValue($parentObject, null);
442
443
                            $this->uow->setOriginalEntityProperty($oid, $relationField, null);
444
                        }
445
                    // else leave $reflFieldValue null for single-valued associations
446
                    } else {
447
                        // Update result pointer
448
                        $this->resultPointers[$dqlAlias] = $reflFieldValue;
449
                    }
450
                }
451
            } else {
452
                // PATH C: Its a root result element
453
                $this->rootAliases[$dqlAlias] = true; // Mark as root alias
454
                $entityKey                    = $this->rsm->entityMappings[$dqlAlias] ?: 0;
455
456
                // if this row has a NULL value for the root result id then make it a null result.
457
                if (! isset($nonemptyComponents[$dqlAlias])) {
458
                    if ($this->rsm->isMixed) {
459
                        $result[] = [$entityKey => null];
460
                    } else {
461
                        $result[] = null;
462
                    }
463
                    $resultKey = $this->resultCounter;
464
                    ++$this->resultCounter;
465
                    continue;
466
                }
467
468
                // check for existing result from the iterations before
469
                if (! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
470
                    $element = $this->getEntity($data, $dqlAlias);
471
472
                    if ($this->rsm->isMixed) {
473
                        $element = [$entityKey => $element];
474
                    }
475
476
                    if (isset($this->rsm->indexByMap[$dqlAlias])) {
477
                        $resultKey = $row[$this->rsm->indexByMap[$dqlAlias]];
478
479
                        if (isset($this->hints['collection'])) {
480
                            $this->hints['collection']->hydrateSet($resultKey, $element);
481
                        }
482
483
                        $result[$resultKey] = $element;
484
                    } else {
485
                        $resultKey = $this->resultCounter;
486
                        ++$this->resultCounter;
487
488
                        if (isset($this->hints['collection'])) {
489
                            $this->hints['collection']->hydrateAdd($element);
490
                        }
491
492
                        $result[] = $element;
493
                    }
494
495
                    $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
496
497
                    // Update result pointer
498
                    $this->resultPointers[$dqlAlias] = $element;
499
                } else {
500
                    // Update result pointer
501
                    $index                           = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
502
                    $this->resultPointers[$dqlAlias] = $result[$index];
503
                    $resultKey                       = $index;
504
                }
505
            }
506
507
            if (isset($this->hints[Query::HINT_INTERNAL_ITERATION]) && $this->hints[Query::HINT_INTERNAL_ITERATION]) {
508
                $this->uow->hydrationComplete();
509
            }
510
        }
511
512
        if (! isset($resultKey)) {
513
            $this->resultCounter++;
514
        }
515
516
        // Append scalar values to mixed result sets
517
        if (isset($rowData['scalars'])) {
518
            if (! isset($resultKey)) {
519
                $resultKey = (isset($this->rsm->indexByMap['scalars']))
520
                    ? $row[$this->rsm->indexByMap['scalars']]
521
                    : $this->resultCounter - 1;
522
            }
523
524
            foreach ($rowData['scalars'] as $name => $value) {
525
                $result[$resultKey][$name] = $value;
526
            }
527
        }
528
529
        // Append new object to mixed result sets
530
        if (isset($rowData['newObjects'])) {
531
            if (! isset($resultKey)) {
532
                $resultKey = $this->resultCounter - 1;
533
            }
534
535
            $hasNoScalars = ! (isset($rowData['scalars']) && $rowData['scalars']);
536
537
            foreach ($rowData['newObjects'] as $objIndex => $newObject) {
538
                $class = $newObject['class'];
539
                $args  = $newObject['args'];
540
                $obj   = $class->newInstanceArgs($args);
541
542
                if ($hasNoScalars && \count($rowData['newObjects']) === 1) {
543
                    $result[$resultKey] = $obj;
544
545
                    continue;
546
                }
547
548
                $result[$resultKey][$objIndex] = $obj;
549
            }
550
        }
551
    }
552
553
    /**
554
     * When executed in a hydrate() loop we may have to clear internal state to
555
     * decrease memory consumption.
556
     *
557
     * @param mixed $eventArgs
558
     */
559 69
    public function onClear($eventArgs)
560
    {
561 69
        parent::onClear($eventArgs);
562
563 69
        $aliases = array_keys($this->identifierMap);
564
565 69
        $this->identifierMap = array_fill_keys($aliases, []);
566 69
    }
567
}
568