Failed Conditions
Push — master ( 2ade86...13f838 )
by Jonathan
18s
created

Doctrine/ORM/Internal/Hydration/ObjectHydrator.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 array
49
     */
50
    private $resultPointers = [];
51
52
    /**
53
     * @var array
54
     */
55
    private $idTemplate = [];
56
57
    /**
58
     * @var integer
59
     */
60
    private $resultCounter = 0;
61
62
    /**
63
     * @var array
64
     */
65
    private $rootAliases = [];
66
67
    /**
68
     * @var array
69
     */
70
    private $initializedCollections = [];
71
72
    /**
73
     * @var array
74
     */
75
    private $existingCollections = [];
76
77
    /**
78
     * {@inheritdoc}
79
     */
80 684
    protected function prepare()
81
    {
82 684
        if ( ! isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
83 583
            $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true;
84
        }
85
86 684
        foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
87 650
            $this->identifierMap[$dqlAlias] = [];
88 650
            $this->idTemplate[$dqlAlias]    = '';
89
90
            // Remember which associations are "fetch joined", so that we know where to inject
91
            // collection stubs or proxies and where not.
92 650
            if ( ! isset($this->_rsm->relationMap[$dqlAlias])) {
93 650
                continue;
94
            }
95
96 329
            $parent = $this->_rsm->parentAliasMap[$dqlAlias];
97
98 329
            if ( ! isset($this->_rsm->aliasMap[$parent])) {
99 1
                throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent);
100
            }
101
102 328
            $sourceClassName = $this->_rsm->aliasMap[$parent];
103 328
            $sourceClass     = $this->getClassMetadata($sourceClassName);
104 328
            $assoc           = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
105
106 328
            $this->_hints['fetched'][$parent][$assoc['fieldName']] = true;
107
108 328
            if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) {
109 35
                continue;
110
            }
111
112
            // Mark any non-collection opposite sides as fetched, too.
113 307
            if ($assoc['mappedBy']) {
114 258
                $this->_hints['fetched'][$dqlAlias][$assoc['mappedBy']] = true;
115
116 258
                continue;
117
            }
118
119
            // handle fetch-joined owning side bi-directional one-to-one associations
120 68
            if ($assoc['inversedBy']) {
121 47
                $class        = $this->getClassMetadata($className);
122 47
                $inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
123
124 47
                if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
125 28
                    continue;
126
                }
127
128 41
                $this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true;
129
            }
130
        }
131 683
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 678
    protected function cleanup()
137
    {
138 678
        $eagerLoad = (isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) && $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] == true;
139
140 678
        parent::cleanup();
141
142 678
        $this->identifierMap =
143 678
        $this->initializedCollections =
144 678
        $this->existingCollections =
145 678
        $this->resultPointers = [];
146
147 678
        if ($eagerLoad) {
148 678
            $this->_uow->triggerEagerLoads();
149
        }
150
151 678
        $this->_uow->hydrationComplete();
152 678
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157 677 View Code Duplication
    protected function hydrateAllData()
158
    {
159 677
        $result = [];
160
161 677
        while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
162 638
            $this->hydrateRowData($row, $result);
163
        }
164
165
        // Take snapshots from all newly initialized collections
166 674
        foreach ($this->initializedCollections as $coll) {
167 71
            $coll->takeSnapshot();
168
        }
169
170 674
        return $result;
171
    }
172
173
    /**
174
     * Initializes a related collection.
175
     *
176
     * @param object        $entity         The entity to which the collection belongs.
177
     * @param ClassMetadata $class
178
     * @param string        $fieldName      The name of the field on the entity that holds the collection.
179
     * @param string        $parentDqlAlias Alias of the parent fetch joining this collection.
180
     *
181
     * @return \Doctrine\ORM\PersistentCollection
182
     */
183 103
    private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
184
    {
185 103
        $oid      = spl_object_hash($entity);
186 103
        $relation = $class->associationMappings[$fieldName];
187 103
        $value    = $class->reflFields[$fieldName]->getValue($entity);
188
189 103
        if ($value === null || is_array($value)) {
190 67
            $value = new ArrayCollection((array) $value);
191
        }
192
193 103
        if ( ! $value instanceof PersistentCollection) {
194 67
            $value = new PersistentCollection(
195 67
                $this->_em, $this->_metadataCache[$relation['targetEntity']], $value
196
            );
197 67
            $value->setOwner($entity, $relation);
198
199 67
            $class->reflFields[$fieldName]->setValue($entity, $value);
200 67
            $this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
201
202 67
            $this->initializedCollections[$oid . $fieldName] = $value;
203
        } else if (
204 40
            isset($this->_hints[Query::HINT_REFRESH]) ||
205 40
            isset($this->_hints['fetched'][$parentDqlAlias][$fieldName]) &&
206 40
             ! $value->isInitialized()
207
        ) {
208
            // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
209 6
            $value->setDirty(false);
210 6
            $value->setInitialized(true);
211 6
            $value->unwrap()->clear();
212
213 6
            $this->initializedCollections[$oid . $fieldName] = $value;
214
        } else {
215
            // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
216 35
            $this->existingCollections[$oid . $fieldName] = $value;
217
        }
218
219 103
        return $value;
220
    }
221
222
    /**
223
     * Gets an entity instance.
224
     *
225
     * @param array  $data     The instance data.
226
     * @param string $dqlAlias The DQL alias of the entity's class.
227
     *
228
     * @return object The entity.
229
     *
230
     * @throws HydrationException
231
     */
232 608
    private function getEntity(array $data, $dqlAlias)
233
    {
234 608
        $className = $this->_rsm->aliasMap[$dqlAlias];
235
236 608
        if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
237 69
            $fieldName = $this->_rsm->discriminatorColumns[$dqlAlias];
238
239 69
            if ( ! isset($this->_rsm->metaMappings[$fieldName])) {
240 1
                throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $fieldName, $dqlAlias);
241
            }
242
243 68
            $discrColumn = $this->_rsm->metaMappings[$fieldName];
244
245 68
            if ( ! isset($data[$discrColumn])) {
246 1
                throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias);
247
            }
248
249 68
            if ($data[$discrColumn] === "") {
250
                throw HydrationException::emptyDiscriminatorValue($dqlAlias);
251
            }
252
253 68
            $discrMap = $this->_metadataCache[$className]->discriminatorMap;
254 68
            $discriminatorValue = (string) $data[$discrColumn];
255
256 68
            if ( ! isset($discrMap[$discriminatorValue])) {
257 1
                throw HydrationException::invalidDiscriminatorValue($discriminatorValue, array_keys($discrMap));
258
            }
259
260 67
            $className = $discrMap[$discriminatorValue];
261
262 67
            unset($data[$discrColumn]);
263
        }
264
265 606
        if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->rootAliases[$dqlAlias])) {
266 24
            $this->registerManaged($this->_metadataCache[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
267
        }
268
269 606
        $this->_hints['fetchAlias'] = $dqlAlias;
270
271 606
        return $this->_uow->createEntity($className, $data, $this->_hints);
272
    }
273
274
    /**
275
     * @param string $className
276
     * @param array  $data
277
     *
278
     * @return mixed
279
     */
280 35
    private function getEntityFromIdentityMap($className, array $data)
281
    {
282
        // TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
283 35
        $class = $this->_metadataCache[$className];
284
285
        /* @var $class ClassMetadata */
286 35
        if ($class->isIdentifierComposite) {
287 1
            $idHash = '';
288
289 1 View Code Duplication
            foreach ($class->identifier as $fieldName) {
290 1
                $idHash .= ' ' . (isset($class->associationMappings[$fieldName])
291 1
                    ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
292 1
                    : $data[$fieldName]);
293
            }
294
295 1
            return $this->_uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName);
296 34
        } else if (isset($class->associationMappings[$class->identifier[0]])) {
297
            return $this->_uow->tryGetByIdHash($data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']], $class->rootEntityName);
298
        }
299
300 34
        return $this->_uow->tryGetByIdHash($data[$class->identifier[0]], $class->rootEntityName);
301
    }
302
303
    /**
304
     * Hydrates a single row in an SQL result set.
305
     *
306
     * @internal
307
     * First, the data of the row is split into chunks where each chunk contains data
308
     * that belongs to a particular component/class. Afterwards, all these chunks
309
     * are processed, one after the other. For each chunk of class data only one of the
310
     * following code paths is executed:
311
     *
312
     * Path A: The data chunk belongs to a joined/associated object and the association
313
     *         is collection-valued.
314
     * Path B: The data chunk belongs to a joined/associated object and the association
315
     *         is single-valued.
316
     * Path C: The data chunk belongs to a root result element/object that appears in the topmost
317
     *         level of the hydrated result. A typical example are the objects of the type
318
     *         specified by the FROM clause in a DQL query.
319
     *
320
     * @param array $row    The data of the row to process.
321
     * @param array $result The result array to fill.
322
     *
323
     * @return void
324
     */
325 643
    protected function hydrateRowData(array $row, array &$result)
326
    {
327
        // Initialize
328 643
        $id = $this->idTemplate; // initialize the id-memory
329 643
        $nonemptyComponents = [];
330
        // Split the row data into chunks of class data.
331 643
        $rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
332
333
        // reset result pointers for each data row
334 643
        $this->resultPointers = [];
335
336
        // Hydrate the data chunks
337 643
        foreach ($rowData['data'] as $dqlAlias => $data) {
338 608
            $entityName = $this->_rsm->aliasMap[$dqlAlias];
339
340 608
            if (isset($this->_rsm->parentAliasMap[$dqlAlias])) {
341
                // It's a joined result
342
343 320
                $parentAlias = $this->_rsm->parentAliasMap[$dqlAlias];
344
                // we need the $path to save into the identifier map which entities were already
345
                // seen for this parent-child relationship
346 320
                $path = $parentAlias . '.' . $dqlAlias;
347
348
                // We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
349 320
                if ( ! isset($nonemptyComponents[$parentAlias])) {
350
                    // TODO: Add special case code where we hydrate the right join objects into identity map at least
351 2
                    continue;
352
                }
353
354 320
                $parentClass    = $this->_metadataCache[$this->_rsm->aliasMap[$parentAlias]];
355 320
                $relationField  = $this->_rsm->relationMap[$dqlAlias];
356 320
                $relation       = $parentClass->associationMappings[$relationField];
357 320
                $reflField      = $parentClass->reflFields[$relationField];
358
359
                // Get a reference to the parent object to which the joined element belongs.
360 320
                if ($this->_rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
361 18
                    $objectClass = $this->resultPointers[$parentAlias];
362 18
                    $parentObject = $objectClass[key($objectClass)];
363 304
                } else if (isset($this->resultPointers[$parentAlias])) {
364 304
                    $parentObject = $this->resultPointers[$parentAlias];
365
                } else {
366
                    // Parent object of relation not found, mark as not-fetched again
367 2
                    $element = $this->getEntity($data, $dqlAlias);
368
369
                    // Update result pointer and provide initial fetch data for parent
370 2
                    $this->resultPointers[$dqlAlias] = $element;
371 2
                    $rowData['data'][$parentAlias][$relationField] = $element;
372
373
                    // Mark as not-fetched again
374 2
                    unset($this->_hints['fetched'][$parentAlias][$relationField]);
375 2
                    continue;
376
                }
377
378 320
                $oid = spl_object_hash($parentObject);
379
380
                // Check the type of the relation (many or single-valued)
381 320
                if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
382
                    // PATH A: Collection-valued association
383 104
                    $reflFieldValue = $reflField->getValue($parentObject);
384
385 104
                    if (isset($nonemptyComponents[$dqlAlias])) {
386 100
                        $collKey = $oid . $relationField;
387 100
                        if (isset($this->initializedCollections[$collKey])) {
388 47
                            $reflFieldValue = $this->initializedCollections[$collKey];
389 100
                        } else if ( ! isset($this->existingCollections[$collKey])) {
390 100
                            $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
391
                        }
392
393 100
                        $indexExists    = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
394 100
                        $index          = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
395 100
                        $indexIsValid   = $index !== false ? isset($reflFieldValue[$index]) : false;
396
397 100
                        if ( ! $indexExists || ! $indexIsValid) {
398 100
                            if (isset($this->existingCollections[$collKey])) {
399
                                // Collection exists, only look for the element in the identity map.
400 35
                                if ($element = $this->getEntityFromIdentityMap($entityName, $data)) {
401 35
                                    $this->resultPointers[$dqlAlias] = $element;
402
                                } else {
403 35
                                    unset($this->resultPointers[$dqlAlias]);
404
                                }
405
                            } else {
406 68
                                $element = $this->getEntity($data, $dqlAlias);
407
408 68
                                if (isset($this->_rsm->indexByMap[$dqlAlias])) {
409 12
                                    $indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
410 12
                                    $reflFieldValue->hydrateSet($indexValue, $element);
411 12
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
412
                                } else {
413 56
                                    $reflFieldValue->hydrateAdd($element);
414 56
                                    $reflFieldValue->last();
415 56
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
416
                                }
417
                                // Update result pointer
418 100
                                $this->resultPointers[$dqlAlias] = $element;
419
                            }
420
                        } else {
421
                            // Update result pointer
422 100
                            $this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
423
                        }
424 9
                    } else if ( ! $reflFieldValue) {
425 5
                        $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
426 6
                    } else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
427 104
                        $reflFieldValue->setInitialized(true);
428
                    }
429
430
                } else {
431
                    // PATH B: Single-valued association
432 238
                    $reflFieldValue = $reflField->getValue($parentObject);
433
434 238
                    if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && !$reflFieldValue->__isInitialized__)) {
435
                        // we only need to take action if this value is null,
436
                        // we refresh the entity or its an uninitialized proxy.
437 223
                        if (isset($nonemptyComponents[$dqlAlias])) {
438 118
                            $element = $this->getEntity($data, $dqlAlias);
439 117
                            $reflField->setValue($parentObject, $element);
440 117
                            $this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
441 117
                            $targetClass = $this->_metadataCache[$relation['targetEntity']];
442
443 117
                            if ($relation['isOwningSide']) {
444
                                // TODO: Just check hints['fetched'] here?
445
                                // If there is an inverse mapping on the target class its bidirectional
446 53
                                if ($relation['inversedBy']) {
447 36
                                    $inverseAssoc = $targetClass->associationMappings[$relation['inversedBy']];
448 36 View Code Duplication
                                    if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
0 ignored issues
show
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...
449 13
                                        $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject);
450 36
                                        $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc['fieldName'], $parentObject);
451
                                    }
452 18
                                } else if ($parentClass === $targetClass && $relation['mappedBy']) {
453
                                    // Special case: bi-directional self-referencing one-one on the same class
454 53
                                    $targetClass->reflFields[$relationField]->setValue($element, $parentObject);
455
                                }
456 View Code Duplication
                            } else {
457
                                // For sure bidirectional, as there is no inverse side in unidirectional mappings
458 67
                                $targetClass->reflFields[$relation['mappedBy']]->setValue($element, $parentObject);
459 67
                                $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation['mappedBy'], $parentObject);
460
                            }
461
                            // Update result pointer
462 117
                            $this->resultPointers[$dqlAlias] = $element;
463
                        } else {
464 125
                            $this->_uow->setOriginalEntityProperty($oid, $relationField, null);
465 222
                            $reflField->setValue($parentObject, null);
466
                        }
467
                        // else leave $reflFieldValue null for single-valued associations
468
                    } else {
469
                        // Update result pointer
470 319
                        $this->resultPointers[$dqlAlias] = $reflFieldValue;
471
                    }
472
                }
473
            } else {
474
                // PATH C: Its a root result element
475 608
                $this->rootAliases[$dqlAlias] = true; // Mark as root alias
476 608
                $entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
477
478
                // if this row has a NULL value for the root result id then make it a null result.
479 608 View Code Duplication
                if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
480 6
                    if ($this->_rsm->isMixed) {
481 2
                        $result[] = [$entityKey => null];
482
                    } else {
483 4
                        $result[] = null;
484
                    }
485 6
                    $resultKey = $this->resultCounter;
486 6
                    ++$this->resultCounter;
487 6
                    continue;
488
                }
489
490
                // check for existing result from the iterations before
491 608
                if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
492 608
                    $element = $this->getEntity($data, $dqlAlias);
493
494 606
                    if ($this->_rsm->isMixed) {
495 41
                        $element = [$entityKey => $element];
496
                    }
497
498 606
                    if (isset($this->_rsm->indexByMap[$dqlAlias])) {
499 27
                        $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
500
501 27
                        if (isset($this->_hints['collection'])) {
502 10
                            $this->_hints['collection']->hydrateSet($resultKey, $element);
503
                        }
504
505 27
                        $result[$resultKey] = $element;
506
                    } else {
507 589
                        $resultKey = $this->resultCounter;
508 589
                        ++$this->resultCounter;
509
510 589
                        if (isset($this->_hints['collection'])) {
511 110
                            $this->_hints['collection']->hydrateAdd($element);
512
                        }
513
514 589
                        $result[] = $element;
515
                    }
516
517 606
                    $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
518
519
                    // Update result pointer
520 606
                    $this->resultPointers[$dqlAlias] = $element;
521
522
                } else {
523
                    // Update result pointer
524 78
                    $index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
525 78
                    $this->resultPointers[$dqlAlias] = $result[$index];
526 78
                    $resultKey = $index;
527
                }
528
            }
529
530 606 View Code Duplication
            if (isset($this->_hints[Query::HINT_INTERNAL_ITERATION]) && $this->_hints[Query::HINT_INTERNAL_ITERATION]) {
531 606
                $this->_uow->hydrationComplete();
532
            }
533
        }
534
535 640
        if ( ! isset($resultKey) ) {
536 35
            $this->resultCounter++;
537
        }
538
539
        // Append scalar values to mixed result sets
540 640 View Code Duplication
        if (isset($rowData['scalars'])) {
541 54
            if ( ! isset($resultKey) ) {
542 22
                $resultKey = (isset($this->_rsm->indexByMap['scalars']))
543 2
                    ? $row[$this->_rsm->indexByMap['scalars']]
544 22
                    : $this->resultCounter - 1;
545
            }
546
547 54
            foreach ($rowData['scalars'] as $name => $value) {
548 54
                $result[$resultKey][$name] = $value;
549
            }
550
        }
551
552
        // Append new object to mixed result sets
553 640 View Code Duplication
        if (isset($rowData['newObjects'])) {
554 19
            if ( ! isset($resultKey) ) {
555 13
                $resultKey = $this->resultCounter - 1;
556
            }
557
558
559 19
            $scalarCount = (isset($rowData['scalars'])? count($rowData['scalars']): 0);
560
561 19
            foreach ($rowData['newObjects'] as $objIndex => $newObject) {
562 19
                $class  = $newObject['class'];
563 19
                $args   = $newObject['args'];
564 19
                $obj    = $class->newInstanceArgs($args);
565
566 19
                if ($scalarCount == 0 && count($rowData['newObjects']) == 1 ) {
567 10
                    $result[$resultKey] = $obj;
568
569 10
                    continue;
570
                }
571
572 9
                $result[$resultKey][$objIndex] = $obj;
573
            }
574
        }
575 640
    }
576
577
    /**
578
     * When executed in a hydrate() loop we may have to clear internal state to
579
     * decrease memory consumption.
580
     *
581
     * @param mixed $eventArgs
582
     *
583
     * @return void
584
     */
585 4
    public function onClear($eventArgs)
586
    {
587 4
        parent::onClear($eventArgs);
588
589 4
        $aliases             = array_keys($this->identifierMap);
590
591 4
        $this->identifierMap = array_fill_keys($aliases, []);
592 4
    }
593
}
594