ObjectHydrator::hydrateRowData()   F
last analyzed

Complexity

Conditions 50
Paths > 20000

Size

Total Lines 262
Code Lines 148

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 133
CRAP Score 50

Importance

Changes 0
Metric Value
cc 50
eloc 148
c 0
b 0
f 0
nc 31096
nop 2
dl 0
loc 262
ccs 133
cts 133
cp 1
crap 50
rs 0

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
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Internal\Hydration;
6
7
use Doctrine\Common\Collections\Collection;
8
use Doctrine\DBAL\FetchMode;
9
use Doctrine\ORM\Mapping\ClassMetadata;
10
use Doctrine\ORM\Mapping\ManyToManyAssociationMetadata;
11
use Doctrine\ORM\Mapping\ToManyAssociationMetadata;
12
use Doctrine\ORM\Mapping\ToOneAssociationMetadata;
13
use Doctrine\ORM\PersistentCollection;
14
use Doctrine\ORM\Query;
15
use Doctrine\ORM\UnitOfWork;
16
use ProxyManager\Proxy\GhostObjectInterface;
17
use function array_fill_keys;
18
use function array_keys;
19
use function count;
20
use function key;
21
use function spl_object_id;
22
23
/**
24
 * The ObjectHydrator constructs an object graph out of an SQL result set.
25
 *
26
 * {@internal Highly performance-sensitive code. }}
27
 */
28
class ObjectHydrator extends AbstractHydrator
29
{
30
    /** @var mixed[][] */
31
    private $identifierMap = [];
32
33
    /** @var mixed[] */
34
    private $resultPointers = [];
35
36
    /** @var string[] */
37
    private $idTemplate = [];
38
39
    /** @var int */
40
    private $resultCounter = 0;
41
42
    /** @var bool */
43
    private $rootAliases = [];
44
45
    /** @var Collection[]|object[][] */
46
    private $initializedCollections = [];
47
48
    /** @var Collection[]|object[][] */
49
    private $existingCollections = [];
50
51
    /**
52
     * {@inheritdoc}
53
     */
54 661
    protected function prepare()
55
    {
56 661
        if (! isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
57 565
            $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true;
58
        }
59
60 661
        foreach ($this->rsm->aliasMap as $dqlAlias => $className) {
61 628
            $this->identifierMap[$dqlAlias] = [];
62 628
            $this->idTemplate[$dqlAlias]    = '';
63
64
            // Remember which associations are "fetch joined", so that we know where to inject
65
            // collection stubs or proxies and where not.
66 628
            if (! isset($this->rsm->relationMap[$dqlAlias])) {
67 628
                continue;
68
            }
69
70 310
            $parent = $this->rsm->parentAliasMap[$dqlAlias];
71
72 310
            if (! isset($this->rsm->aliasMap[$parent])) {
73 1
                throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent);
74
            }
75
76 309
            $sourceClassName = $this->rsm->aliasMap[$parent];
77 309
            $sourceClass     = $this->getClassMetadata($sourceClassName);
78 309
            $association     = $sourceClass->getProperty($this->rsm->relationMap[$dqlAlias]);
79
80 309
            $this->hints['fetched'][$parent][$association->getName()] = true;
81
82 309
            if ($association instanceof ManyToManyAssociationMetadata) {
83 35
                continue;
84
            }
85
86
            // Mark any non-collection opposite sides as fetched, too.
87 288
            if ($association->getMappedBy()) {
0 ignored issues
show
Bug introduced by
The method getMappedBy() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

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

87
            if ($association->/** @scrutinizer ignore-call */ getMappedBy()) {
Loading history...
88 240
                $this->hints['fetched'][$dqlAlias][$association->getMappedBy()] = true;
89
90 240
                continue;
91
            }
92
93
            // handle fetch-joined owning side bi-directional one-to-one associations
94 66
            if ($association->getInversedBy()) {
0 ignored issues
show
Bug introduced by
The method getInversedBy() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

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

94
            if ($association->/** @scrutinizer ignore-call */ getInversedBy()) {
Loading history...
95 45
                $class        = $this->getClassMetadata($className);
96 45
                $inverseAssoc = $class->getProperty($association->getInversedBy());
97
98 45
                if (! ($inverseAssoc instanceof ToOneAssociationMetadata)) {
99 27
                    continue;
100
                }
101
102 18
                $this->hints['fetched'][$dqlAlias][$inverseAssoc->getName()] = true;
103
            }
104
        }
105 660
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 655
    protected function cleanup()
111
    {
112 655
        $eagerLoad = isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD]) && $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] === true;
113
114 655
        parent::cleanup();
115
116 655
        $this->identifierMap          =
117 655
        $this->initializedCollections =
118 655
        $this->existingCollections    =
119 655
        $this->resultPointers         = [];
120
121 655
        if ($eagerLoad) {
122 655
            $this->uow->triggerEagerLoads();
123
        }
124
125 655
        $this->uow->hydrationComplete();
126 655
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 654
    protected function hydrateAllData()
132
    {
133 654
        $result = [];
134
135 654
        while ($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) {
136 612
            $this->hydrateRowData($row, $result);
137
        }
138
139
        // Take snapshots from all newly initialized collections
140 651
        foreach ($this->initializedCollections as $coll) {
141 69
            $coll->takeSnapshot();
142
        }
143
144 651
        return $result;
145
    }
146
147
    /**
148
     * Initializes a related collection.
149
     *
150
     * @param object        $entity         The entity to which the collection belongs.
151
     * @param ClassMetadata $class
152
     * @param string        $fieldName      The name of the field on the entity that holds the collection.
153
     * @param string        $parentDqlAlias Alias of the parent fetch joining this collection.
154
     *
155
     * @return PersistentCollection
156
     */
157 101
    private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
158
    {
159
        /** @var ToManyAssociationMetadata $association */
160 101
        $association = $class->getProperty($fieldName);
161 101
        $value       = $association->getValue($entity);
162 101
        $oid         = spl_object_id($entity);
163
164 101
        if (! $value instanceof PersistentCollection) {
165 65
            $value = $association->wrap($entity, $value, $this->em);
166
167 65
            $association->setValue($entity, $value);
168
169 65
            $this->uow->setOriginalEntityProperty($oid, $fieldName, $value);
170
171 65
            $this->initializedCollections[$oid . $fieldName] = $value;
172 39
        } elseif (isset($this->hints[Query::HINT_REFRESH]) ||
173 39
            (isset($this->hints['fetched'][$parentDqlAlias][$fieldName]) && ! $value->isInitialized())
174
        ) {
175
            // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
176 6
            $value->setDirty(false);
177 6
            $value->setInitialized(true);
178 6
            $value->unwrap()->clear();
179
180 6
            $this->initializedCollections[$oid . $fieldName] = $value;
181
        } else {
182
            // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
183 34
            $this->existingCollections[$oid . $fieldName] = $value;
184
        }
185
186 101
        return $value;
187
    }
188
189
    /**
190
     * Gets an entity instance.
191
     *
192
     * @param mixed[] $data     The instance data.
193
     * @param string  $dqlAlias The DQL alias of the entity's class.
194
     *
195
     * @return object The entity.
196
     *
197
     * @throws HydrationException
198
     */
199 583
    private function getEntity(array $data, $dqlAlias)
200
    {
201 583
        $className = $this->rsm->aliasMap[$dqlAlias];
202
203 583
        if (isset($this->rsm->discriminatorColumns[$dqlAlias])) {
204 69
            $fieldName = $this->rsm->discriminatorColumns[$dqlAlias];
205
206 69
            if (! isset($this->rsm->metaMappings[$fieldName])) {
207 1
                throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $fieldName, $dqlAlias);
208
            }
209
210 68
            $discrColumn = $this->rsm->metaMappings[$fieldName];
211
212 68
            if (! isset($data[$discrColumn])) {
213 1
                throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias);
214
            }
215
216 68
            if ($data[$discrColumn] === '') {
217
                throw HydrationException::emptyDiscriminatorValue($dqlAlias);
218
            }
219
220 68
            $discrMap           = $this->metadataCache[$className]->discriminatorMap;
221 68
            $discriminatorValue = (string) $data[$discrColumn];
222
223 68
            if (! isset($discrMap[$discriminatorValue])) {
224 1
                throw HydrationException::invalidDiscriminatorValue($discriminatorValue, array_keys($discrMap));
225
            }
226
227 67
            $className = $discrMap[$discriminatorValue];
228
229 67
            unset($data[$discrColumn]);
230
        }
231
232 581
        if (isset($this->hints[Query::HINT_REFRESH_ENTITY], $this->rootAliases[$dqlAlias])) {
233 22
            $id = $this->em->getIdentifierFlattener()->flattenIdentifier($this->metadataCache[$className], $data);
234
235 22
            $this->em->getUnitOfWork()->registerManaged($this->hints[Query::HINT_REFRESH_ENTITY], $id, $data);
236
        }
237
238 581
        $this->hints['fetchAlias'] = $dqlAlias;
239
240 581
        return $this->uow->createEntity($className, $data, $this->hints);
241
    }
242
243
    /**
244
     * @param string  $className
245
     * @param mixed[] $data
246
     *
247
     * @return mixed
248
     */
249 34
    private function getEntityFromIdentityMap($className, array $data)
250
    {
251
        /** @var ClassMetadata $class */
252 34
        $class = $this->metadataCache[$className];
253 34
        $id    = $this->em->getIdentifierFlattener()->flattenIdentifier($class, $data);
254
255 34
        return $this->uow->tryGetById($id, $class->getRootClassName());
256
    }
257
258
    /**
259
     * Hydrates a single row in an SQL result set.
260
     *
261
     * @internal
262
     * First, the data of the row is split into chunks where each chunk contains data
263
     * that belongs to a particular component/class. Afterwards, all these chunks
264
     * are processed, one after the other. For each chunk of class data only one of the
265
     * following code paths is executed:
266
     *
267
     * Path A: The data chunk belongs to a joined/associated object and the association
268
     *         is collection-valued.
269
     * Path B: The data chunk belongs to a joined/associated object and the association
270
     *         is single-valued.
271
     * Path C: The data chunk belongs to a root result element/object that appears in the topmost
272
     *         level of the hydrated result. A typical example are the objects of the type
273
     *         specified by the FROM clause in a DQL query.
274
     *
275
     * @param mixed[] $row    The data of the row to process.
276
     * @param mixed[] $result The result array to fill.
277
     */
278 617
    protected function hydrateRowData(array $row, array &$result)
279
    {
280
        // Initialize
281 617
        $id                 = $this->idTemplate; // initialize the id-memory
282 617
        $nonemptyComponents = [];
283
        // Split the row data into chunks of class data.
284 617
        $rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
285
286
        // reset result pointers for each data row
287 617
        $this->resultPointers = [];
288
289
        // Hydrate the data chunks
290 617
        foreach ($rowData['data'] as $dqlAlias => $data) {
291 583
            $entityName = $this->rsm->aliasMap[$dqlAlias];
292
293 583
            if (isset($this->rsm->parentAliasMap[$dqlAlias])) {
294
                // It's a joined result
295
296 303
                $parentAlias = $this->rsm->parentAliasMap[$dqlAlias];
297
                // we need the $path to save into the identifier map which entities were already
298
                // seen for this parent-child relationship
299 303
                $path = $parentAlias . '.' . $dqlAlias;
300
301
                // We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
302 303
                if (! isset($nonemptyComponents[$parentAlias])) {
303
                    // TODO: Add special case code where we hydrate the right join objects into identity map at least
304 2
                    continue;
305
                }
306
307 303
                $parentClass   = $this->metadataCache[$this->rsm->aliasMap[$parentAlias]];
308 303
                $relationField = $this->rsm->relationMap[$dqlAlias];
309 303
                $association   = $parentClass->getProperty($relationField);
310
311
                // Get a reference to the parent object to which the joined element belongs.
312 303
                if ($this->rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
313 17
                    $objectClass  = $this->resultPointers[$parentAlias];
314 17
                    $parentObject = $objectClass[key($objectClass)];
315 288
                } elseif (isset($this->resultPointers[$parentAlias])) {
316 288
                    $parentObject = $this->resultPointers[$parentAlias];
317
                } else {
318
                    // Parent object of relation not found, mark as not-fetched again
319 2
                    $element = $this->getEntity($data, $dqlAlias);
320
321
                    // Update result pointer and provide initial fetch data for parent
322 2
                    $this->resultPointers[$dqlAlias]               = $element;
323 2
                    $rowData['data'][$parentAlias][$relationField] = $element;
324
325
                    // Mark as not-fetched again
326 2
                    unset($this->hints['fetched'][$parentAlias][$relationField]);
327 2
                    continue;
328
                }
329
330 303
                $oid = spl_object_id($parentObject);
331
332
                // Check the type of the relation (many or single-valued)
333 303
                if (! ($association instanceof ToOneAssociationMetadata)) {
334
                    // PATH A: Collection-valued association
335 102
                    $reflFieldValue = $association->getValue($parentObject);
336
337 102
                    if (isset($nonemptyComponents[$dqlAlias])) {
338 98
                        $collKey = $oid . $relationField;
339 98
                        if (isset($this->initializedCollections[$collKey])) {
340 46
                            $reflFieldValue = $this->initializedCollections[$collKey];
341 98
                        } elseif (! isset($this->existingCollections[$collKey])) {
342 98
                            $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
343
                        }
344
345 98
                        $indexExists  = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
346 98
                        $index        = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
347 98
                        $indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false;
348
349 98
                        if (! $indexExists || ! $indexIsValid) {
350 98
                            if (isset($this->existingCollections[$collKey])) {
351 34
                                $element = $this->getEntityFromIdentityMap($entityName, $data);
352
353
                                // Collection exists, only look for the element in the identity map.
354 34
                                if ($element) {
355 34
                                    $this->resultPointers[$dqlAlias] = $element;
356
                                } else {
357 34
                                    unset($this->resultPointers[$dqlAlias]);
358
                                }
359
                            } else {
360 66
                                $element = $this->getEntity($data, $dqlAlias);
361
362 66
                                if (isset($this->rsm->indexByMap[$dqlAlias])) {
363 10
                                    $indexValue = $row[$this->rsm->indexByMap[$dqlAlias]];
364 10
                                    $reflFieldValue->hydrateSet($indexValue, $element);
365 10
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
366
                                } else {
367 56
                                    $reflFieldValue->hydrateAdd($element);
368 56
                                    $reflFieldValue->last();
369 56
                                    $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
370
                                }
371
                                // Update result pointer
372 98
                                $this->resultPointers[$dqlAlias] = $element;
373
                            }
374
                        } else {
375
                            // Update result pointer
376 98
                            $this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
377
                        }
378 9
                    } elseif (! $reflFieldValue) {
379 5
                        $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
380 6
                    } elseif ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
381 102
                        $reflFieldValue->setInitialized(true);
382
                    }
383
                } else {
384
                    // PATH B: Single-valued association
385 222
                    $reflFieldValue = $association->getValue($parentObject);
386
387 222
                    if (! $reflFieldValue || isset($this->hints[Query::HINT_REFRESH]) ||
388 222
                        ($reflFieldValue instanceof GhostObjectInterface && ! $reflFieldValue->isProxyInitialized())) {
389
                        // we only need to take action if this value is null,
390
                        // we refresh the entity or its an uninitialized proxy.
391 209
                        if (isset($nonemptyComponents[$dqlAlias])) {
392 115
                            $element = $this->getEntity($data, $dqlAlias);
393
394 114
                            $association->setValue($parentObject, $element);
395 114
                            $this->uow->setOriginalEntityProperty($oid, $relationField, $element);
396
397 114
                            $mappedBy    = $association->getMappedBy();
398 114
                            $targetClass = $this->metadataCache[$association->getTargetEntity()];
399
400 114
                            if ($association->isOwningSide()) {
401
                                // TODO: Just check hints['fetched'] here?
402
                                // If there is an inverse mapping on the target class its bidirectional
403 51
                                if ($association->getInversedBy()) {
404 34
                                    $inverseAssociation = $targetClass->getProperty($association->getInversedBy());
405
406 34
                                    if ($inverseAssociation instanceof ToOneAssociationMetadata) {
407 12
                                        $inverseAssociation->setValue($element, $parentObject);
408
409 12
                                        $this->uow->setOriginalEntityProperty(
410 51
                                            spl_object_id($element),
411 12
                                            $inverseAssociation->getName(),
412
                                            $parentObject
413
                                        );
414
                                    }
415
                                }
416
                            } else {
417
                                // For sure bidirectional, as there is no inverse side in unidirectional mappings
418 68
                                $inverseAssociation = $targetClass->getProperty($mappedBy);
0 ignored issues
show
Bug introduced by
It seems like $mappedBy can also be of type null; however, parameter $propertyName of Doctrine\ORM\Mapping\Com...Metadata::getProperty() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

418
                                $inverseAssociation = $targetClass->getProperty(/** @scrutinizer ignore-type */ $mappedBy);
Loading history...
419
420 68
                                $inverseAssociation->setValue($element, $parentObject);
421
422 68
                                $this->uow->setOriginalEntityProperty(
423 68
                                    spl_object_id($element),
424
                                    $mappedBy,
425
                                    $parentObject
426
                                );
427
                            }
428
429
                            // Update result pointer
430 114
                            $this->resultPointers[$dqlAlias] = $element;
431
                        } else {
432 113
                            $association->setValue($parentObject, null);
433
434 208
                            $this->uow->setOriginalEntityProperty($oid, $relationField, null);
435
                        }
436
                    // else leave $reflFieldValue null for single-valued associations
437
                    } else {
438
                        // Update result pointer
439 302
                        $this->resultPointers[$dqlAlias] = $reflFieldValue;
440
                    }
441
                }
442
            } else {
443
                // PATH C: Its a root result element
444 583
                $this->rootAliases[$dqlAlias] = true; // Mark as root alias
445 583
                $entityKey                    = $this->rsm->entityMappings[$dqlAlias] ?: 0;
446
447
                // if this row has a NULL value for the root result id then make it a null result.
448 583
                if (! isset($nonemptyComponents[$dqlAlias])) {
449 3
                    if ($this->rsm->isMixed) {
450 2
                        $result[] = [$entityKey => null];
451
                    } else {
452 1
                        $result[] = null;
453
                    }
454 3
                    $resultKey = $this->resultCounter;
455 3
                    ++$this->resultCounter;
456 3
                    continue;
457
                }
458
459
                // check for existing result from the iterations before
460 583
                if (! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
461 583
                    $element = $this->getEntity($data, $dqlAlias);
462
463 581
                    if ($this->rsm->isMixed) {
464 39
                        $element = [$entityKey => $element];
465
                    }
466
467 581
                    if (isset($this->rsm->indexByMap[$dqlAlias])) {
468 26
                        $resultKey = $row[$this->rsm->indexByMap[$dqlAlias]];
469
470 26
                        if (isset($this->hints['collection'])) {
471 10
                            $this->hints['collection']->hydrateSet($resultKey, $element);
472
                        }
473
474 26
                        $result[$resultKey] = $element;
475
                    } else {
476 564
                        $resultKey = $this->resultCounter;
477 564
                        ++$this->resultCounter;
478
479 564
                        if (isset($this->hints['collection'])) {
480 104
                            $this->hints['collection']->hydrateAdd($element);
481
                        }
482
483 564
                        $result[] = $element;
484
                    }
485
486 581
                    $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
487
488
                    // Update result pointer
489 581
                    $this->resultPointers[$dqlAlias] = $element;
490
                } else {
491
                    // Update result pointer
492 77
                    $index                           = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
493 77
                    $this->resultPointers[$dqlAlias] = $result[$index];
494 77
                    $resultKey                       = $index;
495
                }
496
            }
497
498 581
            if (isset($this->hints[Query::HINT_INTERNAL_ITERATION]) && $this->hints[Query::HINT_INTERNAL_ITERATION]) {
499 4
                $this->uow->hydrationComplete();
500
            }
501
        }
502
503 614
        if (! isset($resultKey)) {
504 34
            $this->resultCounter++;
505
        }
506
507
        // Append scalar values to mixed result sets
508 614
        if (isset($rowData['scalars'])) {
509 53
            if (! isset($resultKey)) {
510 23
                $resultKey = isset($this->rsm->indexByMap['scalars'])
511 2
                    ? $row[$this->rsm->indexByMap['scalars']]
512 23
                    : $this->resultCounter - 1;
513
            }
514
515 53
            foreach ($rowData['scalars'] as $name => $value) {
516 53
                $result[$resultKey][$name] = $value;
517
            }
518
        }
519
520
        // Append new object to mixed result sets
521 614
        if (isset($rowData['newObjects'])) {
522 17
            if (! isset($resultKey)) {
523 11
                $resultKey = $this->resultCounter - 1;
524
            }
525
526 17
            $hasNoScalars = ! (isset($rowData['scalars']) && $rowData['scalars']);
527
528 17
            foreach ($rowData['newObjects'] as $objIndex => $newObject) {
529 17
                $class = $newObject['class'];
530 17
                $args  = $newObject['args'];
531 17
                $obj   = $class->newInstanceArgs($args);
532
533 17
                if ($hasNoScalars && count($rowData['newObjects']) === 1) {
534 8
                    $result[$resultKey] = $obj;
535
536 8
                    continue;
537
                }
538
539 9
                $result[$resultKey][$objIndex] = $obj;
540
            }
541
        }
542 614
    }
543
544
    /**
545
     * When executed in a hydrate() loop we may have to clear internal state to
546
     * decrease memory consumption.
547
     *
548
     * @param mixed $eventArgs
549
     */
550 4
    public function onClear($eventArgs)
551
    {
552 4
        parent::onClear($eventArgs);
553
554 4
        $aliases = array_keys($this->identifierMap);
555
556 4
        $this->identifierMap = array_fill_keys($aliases, []);
557 4
    }
558
}
559