Failed Conditions
Pull Request — 2.6 (#7882)
by
unknown
06:45
created

ObjectHydrator::prepare()   B

Complexity

Conditions 9
Paths 16

Size

Total Lines 49
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 9.0046

Importance

Changes 0
Metric Value
eloc 25
c 0
b 0
f 0
dl 0
loc 49
ccs 25
cts 26
cp 0.9615
rs 8.0555
cc 9
nc 16
nop 0
crap 9.0046
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 281
    protected function prepare()
81
    {
82 281
        if ( ! isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
83 234
            $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true;
84
        }
85
86 281
        foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
87 269
            $this->identifierMap[$dqlAlias] = [];
88 269
            $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 269
            if ( ! isset($this->_rsm->relationMap[$dqlAlias])) {
93 269
                continue;
94
            }
95
96 95
            $parent = $this->_rsm->parentAliasMap[$dqlAlias];
97
98 95
            if ( ! isset($this->_rsm->aliasMap[$parent])) {
99 1
                throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent);
100
            }
101
102 94
            $sourceClassName = $this->_rsm->aliasMap[$parent];
103 94
            $sourceClass     = $this->getClassMetadata($sourceClassName);
104 94
            $assoc           = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
105
106 94
            $this->_hints['fetched'][$parent][$assoc['fieldName']] = true;
107
108 94
            if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) {
109 12
                continue;
110
            }
111
112
            // Mark any non-collection opposite sides as fetched, too.
113 85
            if ($assoc['mappedBy']) {
114 82
                $this->_hints['fetched'][$dqlAlias][$assoc['mappedBy']] = true;
115
116 82
                continue;
117
            }
118
119
            // handle fetch-joined owning side bi-directional one-to-one associations
120 4
            if ($assoc['inversedBy']) {
121 4
                $class        = $this->getClassMetadata($className);
122 4
                $inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
123
124 4
                if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
125 4
                    continue;
126
                }
127
128
                $this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true;
129
            }
130
        }
131 280
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 275
    protected function cleanup()
137
    {
138 275
        $eagerLoad = (isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) && $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] == true;
139
140 275
        parent::cleanup();
141
142 275
        $this->identifierMap =
143 275
        $this->initializedCollections =
144 275
        $this->existingCollections =
145 275
        $this->resultPointers = [];
146
147 275
        if ($eagerLoad) {
148 275
            $this->_uow->triggerEagerLoads();
149
        }
150
151 275
        $this->_uow->hydrationComplete();
152 275
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157 274
    protected function hydrateAllData()
158
    {
159 274
        $result = [];
160
161 274
        while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
162 230
            $this->hydrateRowData($row, $result);
163
        }
164
165
        // Take snapshots from all newly initialized collections
166 271
        foreach ($this->initializedCollections as $coll) {
167 25
            $coll->takeSnapshot();
168
        }
169
170 271
        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 26
    private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
184
    {
185 26
        $oid      = spl_object_hash($entity);
186 26
        $relation = $class->associationMappings[$fieldName];
187 26
        $value    = $class->reflFields[$fieldName]->getValue($entity);
188
189 26
        if ($value === null || is_array($value)) {
190 25
            $value = new ArrayCollection((array) $value);
191
        }
192
193 26
        if ( ! $value instanceof PersistentCollection) {
194 25
            $value = new PersistentCollection(
195 25
                $this->_em, $this->_metadataCache[$relation['targetEntity']], $value
196
            );
197 25
            $value->setOwner($entity, $relation);
198
199 25
            $class->reflFields[$fieldName]->setValue($entity, $value);
200 25
            $this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
201
202 25
            $this->initializedCollections[$oid . $fieldName] = $value;
203
        } else if (
204 2
            isset($this->_hints[Query::HINT_REFRESH]) ||
205 2
            isset($this->_hints['fetched'][$parentDqlAlias][$fieldName]) &&
206 2
             ! $value->isInitialized()
207
        ) {
208
            // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
209 1
            $value->setDirty(false);
210 1
            $value->setInitialized(true);
211 1
            $value->unwrap()->clear();
212
213 1
            $this->initializedCollections[$oid . $fieldName] = $value;
214
        } else {
215
            // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
216 1
            $this->existingCollections[$oid . $fieldName] = $value;
217
        }
218
219 26
        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 222
    private function getEntity(array $data, $dqlAlias)
233
    {
234 222
        $className = $this->_rsm->aliasMap[$dqlAlias];
235
236 222
        if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
237 31
            $fieldName = $this->_rsm->discriminatorColumns[$dqlAlias];
238
239 31
            if ( ! isset($this->_rsm->metaMappings[$fieldName])) {
240 1
                throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $fieldName, $dqlAlias);
241
            }
242
243 30
            $discrColumn = $this->_rsm->metaMappings[$fieldName];
244
245 30
            if ( ! isset($data[$discrColumn])) {
246 1
                throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias);
247
            }
248
249 30
            if ($data[$discrColumn] === "") {
250
                throw HydrationException::emptyDiscriminatorValue($dqlAlias);
251
            }
252
253 30
            $discrMap = $this->_metadataCache[$className]->discriminatorMap;
254 30
            $discriminatorValue = (string) $data[$discrColumn];
255
256 30
            if ( ! isset($discrMap[$discriminatorValue])) {
257 1
                throw HydrationException::invalidDiscriminatorValue($discriminatorValue, array_keys($discrMap));
258
            }
259
260 29
            $className = $discrMap[$discriminatorValue];
261
262 29
            unset($data[$discrColumn]);
263
        }
264
265 220
        if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->rootAliases[$dqlAlias])) {
266 4
            $this->registerManaged($this->_metadataCache[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
267
        }
268
269 220
        $this->_hints['fetchAlias'] = $dqlAlias;
270
271 220
        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 1
    private function getEntityFromIdentityMap($className, array $data)
281
    {
282
        // TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
283 1
        $class = $this->_metadataCache[$className];
284
285
        /* @var $class ClassMetadata */
286 1
        if ($class->isIdentifierComposite) {
287
            $idHash = '';
288
289
            foreach ($class->identifier as $fieldName) {
290
                $idHash .= ' ' . (isset($class->associationMappings[$fieldName])
291
                    ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
292
                    : $data[$fieldName]);
293
            }
294
295
            return $this->_uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName);
296 1
        } 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 1
        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 235
    protected function hydrateRowData(array $row, array &$result)
326
    {
327
        // Initialize
328 235
        $id = $this->idTemplate; // initialize the id-memory
329 235
        $nonemptyComponents = [];
330
        // Split the row data into chunks of class data.
331 235
        $rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
332
333
        // reset result pointers for each data row
334 235
        $this->resultPointers = [];
335
336
        // Hydrate the data chunks
337 235
        foreach ($rowData['data'] as $dqlAlias => $data) {
338 222
            $entityName = $this->_rsm->aliasMap[$dqlAlias];
339
340 222
            if (isset($this->_rsm->parentAliasMap[$dqlAlias])) {
341
                // It's a joined result
342
343 85
                $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 85
                $path = $parentAlias . '.' . $dqlAlias;
347
348
                // We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
349 85
                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 85
                $parentClass    = $this->_metadataCache[$this->_rsm->aliasMap[$parentAlias]];
355 85
                $relationField  = $this->_rsm->relationMap[$dqlAlias];
356 85
                $relation       = $parentClass->associationMappings[$relationField];
357 85
                $reflField      = $parentClass->reflFields[$relationField];
358
359
                // Get a reference to the parent object to which the joined element belongs.
360 85
                if ($this->_rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
361 15
                    $objectClass = $this->resultPointers[$parentAlias];
362 15
                    $parentObject = $objectClass[key($objectClass)];
363 72
                } else if (isset($this->resultPointers[$parentAlias])) {
364 72
                    $parentObject = $this->resultPointers[$parentAlias];
365
                } else {
366
                    // Parent object of relation not found, mark as not-fetched again
367
                    $element = $this->getEntity($data, $dqlAlias);
368
369
                    // Update result pointer and provide initial fetch data for parent
370
                    $this->resultPointers[$dqlAlias] = $element;
371
                    $rowData['data'][$parentAlias][$relationField] = $element;
372
373
                    // Mark as not-fetched again
374
                    unset($this->_hints['fetched'][$parentAlias][$relationField]);
375
                    continue;
376
                }
377
378 85
                $oid = spl_object_hash($parentObject);
379
380
                // Check the type of the relation (many or single-valued)
381 85
                if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
382
                    // PATH A: Collection-valued association
383 27
                    $reflFieldValue = $reflField->getValue($parentObject);
384
385 27
                    if (isset($nonemptyComponents[$dqlAlias])) {
386 23
                        $collKey = $oid . $relationField;
387 23
                        if (isset($this->initializedCollections[$collKey])) {
388 16
                            $reflFieldValue = $this->initializedCollections[$collKey];
389 23
                        } else if ( ! isset($this->existingCollections[$collKey])) {
390 23
                            $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
391
                        }
392
393 23
                        $indexExists    = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
394 23
                        $index          = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
395 23
                        $indexIsValid   = $index !== false ? isset($reflFieldValue[$index]) : false;
396
397 23
                        if ( ! $indexExists || ! $indexIsValid) {
398 23
                            if (isset($this->existingCollections[$collKey])) {
399
                                // Collection exists, only look for the element in the identity map.
400 1
                                if ($element = $this->getEntityFromIdentityMap($entityName, $data)) {
401 1
                                    $this->resultPointers[$dqlAlias] = $element;
402
                                } else {
403 1
                                    unset($this->resultPointers[$dqlAlias]);
404
                                }
405
                            } else {
406 22
                                $element = $this->getEntity($data, $dqlAlias);
407
408 22
                                if (isset($this->_rsm->indexByMap[$dqlAlias])) {
409 2
                                    $indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
410 2
                                    $reflFieldValue->hydrateSet($indexValue, $element);
411 2
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
412
                                } else {
413 20
                                    $reflFieldValue->hydrateAdd($element);
414 20
                                    $reflFieldValue->last();
415 20
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
416
                                }
417
                                // Update result pointer
418 23
                                $this->resultPointers[$dqlAlias] = $element;
419
                            }
420
                        } else {
421
                            // Update result pointer
422 23
                            $this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
423
                        }
424 8
                    } else if ( ! $reflFieldValue) {
425 5
                        $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
426 5
                    } else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
427 27
                        $reflFieldValue->setInitialized(true);
428
                    }
429
430
                } else {
431
                    // PATH B: Single-valued association
432 60
                    $reflFieldValue = $reflField->getValue($parentObject);
433
434 60
                    if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && !$reflFieldValue->__isInitialized__)) {
0 ignored issues
show
Bug introduced by
Accessing __isInitialized__ on the interface Doctrine\ORM\Proxy\Proxy suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
435
                        // we only need to take action if this value is null,
436
                        // we refresh the entity or its an uninitialized proxy.
437 60
                        if (isset($nonemptyComponents[$dqlAlias])) {
438 4
                            $element = $this->getEntity($data, $dqlAlias);
439 3
                            $reflField->setValue($parentObject, $element);
440 3
                            $this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
441 3
                            $targetClass = $this->_metadataCache[$relation['targetEntity']];
442
443 3
                            if ($relation['isOwningSide']) {
444
                                // TODO: Just check hints['fetched'] here?
445
                                // If there is an inverse mapping on the target class its bidirectional
446 1
                                if ($relation['inversedBy']) {
447 1
                                    $inverseAssoc = $targetClass->associationMappings[$relation['inversedBy']];
448 1
                                    if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
449
                                        $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject);
450 1
                                        $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc['fieldName'], $parentObject);
451
                                    }
452
                                } else if ($parentClass === $targetClass && $relation['mappedBy']) {
453
                                    // Special case: bi-directional self-referencing one-one on the same class
454 1
                                    $targetClass->reflFields[$relationField]->setValue($element, $parentObject);
455
                                }
456
                            } else {
457
                                // For sure bidirectional, as there is no inverse side in unidirectional mappings
458 2
                                $targetClass->reflFields[$relation['mappedBy']]->setValue($element, $parentObject);
459 2
                                $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation['mappedBy'], $parentObject);
460
                            }
461
                            // Update result pointer
462 3
                            $this->resultPointers[$dqlAlias] = $element;
463
                        } else {
464 58
                            $this->_uow->setOriginalEntityProperty($oid, $relationField, null);
465 59
                            $reflField->setValue($parentObject, null);
466
                        }
467
                        // else leave $reflFieldValue null for single-valued associations
468
                    } else {
469
                        // Update result pointer
470 84
                        $this->resultPointers[$dqlAlias] = $reflFieldValue;
471
                    }
472
                }
473
            } else {
474
                // PATH C: Its a root result element
475 222
                $this->rootAliases[$dqlAlias] = true; // Mark as root alias
476 222
                $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 222
                if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
480 2
                    if ($this->_rsm->isMixed) {
481 2
                        $result[] = [$entityKey => null];
482
                    } else {
483
                        $result[] = null;
484
                    }
485 2
                    $resultKey = $this->resultCounter;
486 2
                    ++$this->resultCounter;
487 2
                    continue;
488
                }
489
490
                // check for existing result from the iterations before
491 222
                if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
492 222
                    $element = $this->getEntity($data, $dqlAlias);
493
494 220
                    if ($this->_rsm->isMixed) {
495 33
                        $element = [$entityKey => $element];
496
                    }
497
498 220
                    if (isset($this->_rsm->indexByMap[$dqlAlias])) {
499 6
                        $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
500
501 6
                        if (isset($this->_hints['collection'])) {
502
                            $this->_hints['collection']->hydrateSet($resultKey, $element);
503
                        }
504
505 6
                        $result[$resultKey] = $element;
506
                    } else {
507 214
                        $resultKey = $this->resultCounter;
508 214
                        ++$this->resultCounter;
509
510 214
                        if (isset($this->_hints['collection'])) {
511 39
                            $this->_hints['collection']->hydrateAdd($element);
512
                        }
513
514 214
                        $result[] = $element;
515
                    }
516
517 220
                    $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
518
519
                    // Update result pointer
520 220
                    $this->resultPointers[$dqlAlias] = $element;
521
522
                } else {
523
                    // Update result pointer
524 19
                    $index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
525 19
                    $this->resultPointers[$dqlAlias] = $result[$index];
526 19
                    $resultKey = $index;
527
                }
528
            }
529
530 220
            if (isset($this->_hints[Query::HINT_INTERNAL_ITERATION]) && $this->_hints[Query::HINT_INTERNAL_ITERATION]) {
531 220
                $this->_uow->hydrationComplete();
532
            }
533
        }
534
535 232
        if ( ! isset($resultKey) ) {
536 13
            $this->resultCounter++;
537
        }
538
539
        // Append scalar values to mixed result sets
540 232
        if (isset($rowData['scalars'])) {
541 37
            if ( ! isset($resultKey) ) {
542 13
                $resultKey = (isset($this->_rsm->indexByMap['scalars']))
543 2
                    ? $row[$this->_rsm->indexByMap['scalars']]
544 13
                    : $this->resultCounter - 1;
545
            }
546
547 37
            foreach ($rowData['scalars'] as $name => $value) {
548 37
                $result[$resultKey][$name] = $value;
549
            }
550
        }
551
552
        // Append new object to mixed result sets
553 232
        if (isset($rowData['newObjects'])) {
554
            if ( ! isset($resultKey) ) {
555
                $resultKey = $this->resultCounter - 1;
556
            }
557
558
559
            $scalarCount = (isset($rowData['scalars'])? count($rowData['scalars']): 0);
560
561
            foreach ($rowData['newObjects'] as $objIndex => $newObject) {
562
                $class  = $newObject['class'];
563
                $args   = $newObject['args'];
564
                $obj    = $class->newInstanceArgs($args);
565
566
                if ($scalarCount == 0 && count($rowData['newObjects']) == 1 ) {
567
                    $result[$resultKey] = $obj;
568
569
                    continue;
570
                }
571
572
                $result[$resultKey][$objIndex] = $obj;
573
            }
574
        }
575 232
    }
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 3
    public function onClear($eventArgs)
586
    {
587 3
        parent::onClear($eventArgs);
588
589 3
        $aliases             = array_keys($this->identifierMap);
590
591 3
        $this->identifierMap = array_fill_keys($aliases, []);
592 3
    }
593
}
594