Completed
Push — master ( 4b5952...b8f7dd )
by Andreas
11s
created

HydratorFactory::hydrate()   B

Complexity

Conditions 10
Paths 64

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 41
ccs 21
cts 21
cp 1
rs 7.6666
c 0
b 0
f 0
cc 10
nc 64
nop 3
crap 10

How to fix   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\ODM\MongoDB\Hydrator;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\ODM\MongoDB\Configuration;
9
use Doctrine\ODM\MongoDB\DocumentManager;
10
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
11
use Doctrine\ODM\MongoDB\Event\PreLoadEventArgs;
12
use Doctrine\ODM\MongoDB\Events;
13
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
14
use Doctrine\ODM\MongoDB\Types\Type;
15
use Doctrine\ODM\MongoDB\UnitOfWork;
16
use ProxyManager\Proxy\GhostObjectInterface;
17
use const DIRECTORY_SEPARATOR;
18
use function array_key_exists;
19
use function chmod;
20
use function class_exists;
21
use function dirname;
22
use function file_exists;
23
use function file_put_contents;
24
use function get_class;
25
use function is_dir;
26
use function is_writable;
27
use function mkdir;
28
use function rename;
29
use function rtrim;
30
use function sprintf;
31
use function str_replace;
32
use function substr;
33
use function uniqid;
34
35
/**
36
 * The HydratorFactory class is responsible for instantiating a correct hydrator
37
 * type based on document's ClassMetadata
38
 */
39
class HydratorFactory
40
{
41
    /**
42
     * The DocumentManager this factory is bound to.
43
     *
44
     * @var DocumentManager
45
     */
46
    private $dm;
47
48
    /**
49
     * The UnitOfWork used to coordinate object-level transactions.
50
     *
51
     * @var UnitOfWork
52
     */
53
    private $unitOfWork;
54
55
    /**
56
     * The EventManager associated with this Hydrator
57
     *
58
     * @var EventManager
59
     */
60
    private $evm;
61
62
    /**
63
     * Which algorithm to use to automatically (re)generate hydrator classes.
64
     *
65
     * @var int
66
     */
67
    private $autoGenerate;
68
69
    /**
70
     * The namespace that contains all hydrator classes.
71
     *
72
     * @var string|null
73
     */
74
    private $hydratorNamespace;
75
76
    /**
77
     * The directory that contains all hydrator classes.
78
     *
79
     * @var string|null
80
     */
81
    private $hydratorDir;
82
83
    /**
84
     * Array of instantiated document hydrators.
85
     *
86
     * @var array
87
     */
88
    private $hydrators = [];
89
90
    /**
91
     * @throws HydratorException
92
     */
93 1634
    public function __construct(DocumentManager $dm, EventManager $evm, ?string $hydratorDir, ?string $hydratorNs, int $autoGenerate)
94
    {
95 1634
        if (! $hydratorDir) {
96
            throw HydratorException::hydratorDirectoryRequired();
97
        }
98 1634
        if (! $hydratorNs) {
99
            throw HydratorException::hydratorNamespaceRequired();
100
        }
101 1634
        $this->dm                = $dm;
102 1634
        $this->evm               = $evm;
103 1634
        $this->hydratorDir       = $hydratorDir;
104 1634
        $this->hydratorNamespace = $hydratorNs;
105 1634
        $this->autoGenerate      = $autoGenerate;
106 1634
    }
107
108
    /**
109
     * Sets the UnitOfWork instance.
110
     */
111 1634
    public function setUnitOfWork(UnitOfWork $uow) : void
112
    {
113 1634
        $this->unitOfWork = $uow;
114 1634
    }
115
116
    /**
117
     * Gets the hydrator object for the given document class.
118
     */
119 397
    public function getHydratorFor(string $className) : HydratorInterface
120
    {
121 397
        if (isset($this->hydrators[$className])) {
122 213
            return $this->hydrators[$className];
123
        }
124 397
        $hydratorClassName = str_replace('\\', '', $className) . 'Hydrator';
125 397
        $fqn               = $this->hydratorNamespace . '\\' . $hydratorClassName;
126 397
        $class             = $this->dm->getClassMetadata($className);
127
128 397
        if (! class_exists($fqn, false)) {
129 181
            $fileName = $this->hydratorDir . DIRECTORY_SEPARATOR . $hydratorClassName . '.php';
130 181
            switch ($this->autoGenerate) {
131
                case Configuration::AUTOGENERATE_NEVER:
132
                    require $fileName;
133
                    break;
134
135
                case Configuration::AUTOGENERATE_ALWAYS:
136 181
                    $this->generateHydratorClass($class, $hydratorClassName, $fileName);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
137 181
                    require $fileName;
138 181
                    break;
139
140
                case Configuration::AUTOGENERATE_FILE_NOT_EXISTS:
141
                    if (! file_exists($fileName)) {
142
                        $this->generateHydratorClass($class, $hydratorClassName, $fileName);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
143
                    }
144
                    require $fileName;
145
                    break;
146
147
                case Configuration::AUTOGENERATE_EVAL:
148
                    $this->generateHydratorClass($class, $hydratorClassName, false);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
149
                    break;
150
            }
151
        }
152 397
        $this->hydrators[$className] = new $fqn($this->dm, $this->unitOfWork, $class);
153 397
        return $this->hydrators[$className];
154
    }
155
156
    /**
157
     * Generates hydrator classes for all given classes.
158
     *
159
     * @param array  $classes The classes (ClassMetadata instances) for which to generate hydrators.
160
     * @param string $toDir   The target directory of the hydrator classes. If not specified, the
161
     *                        directory configured on the Configuration of the DocumentManager used
162
     *                        by this factory is used.
163
     */
164
    public function generateHydratorClasses(array $classes, ?string $toDir = null) : void
165
    {
166
        $hydratorDir = $toDir ?: $this->hydratorDir;
167
        $hydratorDir = rtrim($hydratorDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
168
        foreach ($classes as $class) {
169
            $hydratorClassName = str_replace('\\', '', $class->name) . 'Hydrator';
170
            $hydratorFileName  = $hydratorDir . $hydratorClassName . '.php';
171
            $this->generateHydratorClass($class, $hydratorClassName, $hydratorFileName);
172
        }
173
    }
174
175
    /**
176
     * @param string|false $fileName Filename where class code to be written or false to eval code.
177
     */
178 181
    private function generateHydratorClass(ClassMetadata $class, string $hydratorClassName, $fileName) : void
179
    {
180 181
        $code = '';
181
182 181
        foreach ($class->fieldMappings as $fieldName => $mapping) {
183 181
            if (isset($mapping['alsoLoadFields'])) {
184 5
                foreach ($mapping['alsoLoadFields'] as $name) {
185 5
                    $code .= sprintf(
186
                        <<<EOF
187
188 5
        /** @AlsoLoad("$name") */
189 5
        if (!array_key_exists('%1\$s', \$data) && array_key_exists('$name', \$data)) {
190 5
            \$data['%1\$s'] = \$data['$name'];
191
        }
192
193
EOF
194
                        ,
195 5
                        $mapping['name']
196
                    );
197
                }
198
            }
199
200 181
            if ($mapping['type'] === 'date') {
201 9
                $code .= sprintf(
202
                    <<<EOF
203
204
        /** @Field(type="date") */
205
        if (isset(\$data['%1\$s'])) {
206
            \$value = \$data['%1\$s'];
207
            %3\$s
208
            \$this->class->reflFields['%2\$s']->setValue(\$document, clone \$return);
209
            \$hydratedData['%2\$s'] = \$return;
210
        }
211
212
EOF
213
                    ,
214 9
                    $mapping['name'],
215 9
                    $mapping['fieldName'],
216 9
                    Type::getType($mapping['type'])->closureToPHP()
217
                );
218 181
            } elseif (! isset($mapping['association'])) {
219 180
                $code .= sprintf(
220
                    <<<EOF
221
222 180
        /** @Field(type="{$mapping['type']}") */
223
        if (isset(\$data['%1\$s']) || (! empty(\$this->class->fieldMappings['%2\$s']['nullable']) && array_key_exists('%1\$s', \$data))) {
224
            \$value = \$data['%1\$s'];
225
            if (\$value !== null) {
226
                \$typeIdentifier = \$this->class->fieldMappings['%2\$s']['type'];
227
                %3\$s
228
            } else {
229
                \$return = null;
230
            }
231
            \$this->class->reflFields['%2\$s']->setValue(\$document, \$return);
232
            \$hydratedData['%2\$s'] = \$return;
233
        }
234
235
EOF
236
                    ,
237 180
                    $mapping['name'],
238 180
                    $mapping['fieldName'],
239 180
                    Type::getType($mapping['type'])->closureToPHP()
240
                );
241 119
            } elseif ($mapping['association'] === ClassMetadata::REFERENCE_ONE && $mapping['isOwningSide']) {
242 51
                $code .= sprintf(
243
                    <<<EOF
244
245
        /** @ReferenceOne */
246
        if (isset(\$data['%1\$s'])) {
247
            \$reference = \$data['%1\$s'];
248
            \$className = \$this->unitOfWork->getClassNameForAssociation(\$this->class->fieldMappings['%2\$s'], \$reference);
249
            \$identifier = ClassMetadata::getReferenceId(\$reference, \$this->class->fieldMappings['%2\$s']['storeAs']);
250
            \$targetMetadata = \$this->dm->getClassMetadata(\$className);
251
            \$id = \$targetMetadata->getPHPIdentifierValue(\$identifier);
252
            \$return = \$this->dm->getReference(\$className, \$id);
253
            \$this->class->reflFields['%2\$s']->setValue(\$document, \$return);
254
            \$hydratedData['%2\$s'] = \$return;
255
        }
256
257
EOF
258
                    ,
259 51
                    $mapping['name'],
260 51
                    $mapping['fieldName']
261
                );
262 101
            } elseif ($mapping['association'] === ClassMetadata::REFERENCE_ONE && $mapping['isInverseSide']) {
263 6
                if (isset($mapping['repositoryMethod']) && $mapping['repositoryMethod']) {
264 1
                    $code .= sprintf(
265
                        <<<EOF
266
267
        \$className = \$this->class->fieldMappings['%2\$s']['targetDocument'];
268
        \$return = \$this->dm->getRepository(\$className)->%3\$s(\$document);
269
        \$this->class->reflFields['%2\$s']->setValue(\$document, \$return);
270
        \$hydratedData['%2\$s'] = \$return;
271
272
EOF
273
                        ,
274 1
                        $mapping['name'],
275 1
                        $mapping['fieldName'],
276 1
                        $mapping['repositoryMethod']
277
                    );
278
                } else {
279 6
                    $code .= sprintf(
280
                        <<<EOF
281
282
        \$mapping = \$this->class->fieldMappings['%2\$s'];
283
        \$className = \$mapping['targetDocument'];
284
        \$targetClass = \$this->dm->getClassMetadata(\$mapping['targetDocument']);
285
        \$mappedByMapping = \$targetClass->fieldMappings[\$mapping['mappedBy']];
286
        \$mappedByFieldName = ClassMetadata::getReferenceFieldName(\$mappedByMapping['storeAs'], \$mapping['mappedBy']);
287
        \$criteria = array_merge(
288
            array(\$mappedByFieldName => \$data['_id']),
289
            isset(\$this->class->fieldMappings['%2\$s']['criteria']) ? \$this->class->fieldMappings['%2\$s']['criteria'] : array()
290
        );
291
        \$sort = isset(\$this->class->fieldMappings['%2\$s']['sort']) ? \$this->class->fieldMappings['%2\$s']['sort'] : array();
292
        \$return = \$this->unitOfWork->getDocumentPersister(\$className)->load(\$criteria, null, array(), 0, \$sort);
293
        \$this->class->reflFields['%2\$s']->setValue(\$document, \$return);
294
        \$hydratedData['%2\$s'] = \$return;
295
296
EOF
297
                        ,
298 6
                        $mapping['name'],
299 6
                        $mapping['fieldName']
300
                    );
301
                }
302 100
            } elseif ($mapping['association'] === ClassMetadata::REFERENCE_MANY || $mapping['association'] === ClassMetadata::EMBED_MANY) {
303 80
                $code .= sprintf(
304
                    <<<EOF
305
306
        /** @Many */
307
        \$mongoData = isset(\$data['%1\$s']) ? \$data['%1\$s'] : null;
308
        \$return = \$this->dm->getConfiguration()->getPersistentCollectionFactory()->create(\$this->dm, \$this->class->fieldMappings['%2\$s']);
309
        \$return->setHints(\$hints);
310
        \$return->setOwner(\$document, \$this->class->fieldMappings['%2\$s']);
311
        \$return->setInitialized(false);
312
        if (\$mongoData) {
313
            \$return->setMongoData(\$mongoData);
314
        }
315
        \$this->class->reflFields['%2\$s']->setValue(\$document, \$return);
316
        \$hydratedData['%2\$s'] = \$return;
317
318
EOF
319
                    ,
320 80
                    $mapping['name'],
321 80
                    $mapping['fieldName']
322
                );
323 45
            } elseif ($mapping['association'] === ClassMetadata::EMBED_ONE) {
324 45
                $code .= sprintf(
325
                    <<<EOF
326
327
        /** @EmbedOne */
328
        if (isset(\$data['%1\$s'])) {
329
            \$embeddedDocument = \$data['%1\$s'];
330
            \$className = \$this->unitOfWork->getClassNameForAssociation(\$this->class->fieldMappings['%2\$s'], \$embeddedDocument);
331
            \$embeddedMetadata = \$this->dm->getClassMetadata(\$className);
332
            \$return = \$embeddedMetadata->newInstance();
333
334
            \$this->unitOfWork->setParentAssociation(\$return, \$this->class->fieldMappings['%2\$s'], \$document, '%1\$s');
335
336
            \$embeddedData = \$this->dm->getHydratorFactory()->hydrate(\$return, \$embeddedDocument, \$hints);
337
            \$embeddedId = \$embeddedMetadata->identifier && isset(\$embeddedData[\$embeddedMetadata->identifier]) ? \$embeddedData[\$embeddedMetadata->identifier] : null;
338
339
            if (empty(\$hints[Query::HINT_READ_ONLY])) {
340
                \$this->unitOfWork->registerManaged(\$return, \$embeddedId, \$embeddedData);
341
            }
342
343
            \$this->class->reflFields['%2\$s']->setValue(\$document, \$return);
344
            \$hydratedData['%2\$s'] = \$return;
345
        }
346
347
EOF
348
                    ,
349 45
                    $mapping['name'],
350 181
                    $mapping['fieldName']
351
                );
352
            }
353
        }
354
355 181
        $namespace = $this->hydratorNamespace;
356 181
        $code      = sprintf(
357
            <<<EOF
358
<?php
359
360 181
namespace $namespace;
361
362
use Doctrine\ODM\MongoDB\DocumentManager;
363
use Doctrine\ODM\MongoDB\Hydrator\HydratorInterface;
364
use Doctrine\ODM\MongoDB\Query\Query;
365
use Doctrine\ODM\MongoDB\UnitOfWork;
366
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
367
368
/**
369
 * THIS CLASS WAS GENERATED BY THE DOCTRINE ODM. DO NOT EDIT THIS FILE.
370
 */
371 181
class $hydratorClassName implements HydratorInterface
372
{
373
    private \$dm;
374
    private \$unitOfWork;
375
    private \$class;
376
377
    public function __construct(DocumentManager \$dm, UnitOfWork \$uow, ClassMetadata \$class)
378
    {
379
        \$this->dm = \$dm;
380
        \$this->unitOfWork = \$uow;
381
        \$this->class = \$class;
382
    }
383
384
    public function hydrate(object \$document, array \$data, array \$hints = array()): array
385
    {
386
        \$hydratedData = array();
387
%s        return \$hydratedData;
388
    }
389
}
390
EOF
391
            ,
392 181
            $code
393
        );
394
395 181
        if ($fileName === false) {
396
            if (! class_exists($namespace . '\\' . $hydratorClassName)) {
397
                eval(substr($code, 5));
398
            }
399
        } else {
400 181
            $parentDirectory = dirname($fileName);
401
402 181
            if (! is_dir($parentDirectory) && (@mkdir($parentDirectory, 0775, true) === false)) {
403
                throw HydratorException::hydratorDirectoryNotWritable();
404
            }
405
406 181
            if (! is_writable($parentDirectory)) {
407
                throw HydratorException::hydratorDirectoryNotWritable();
408
            }
409
410 181
            $tmpFileName = $fileName . '.' . uniqid('', true);
411 181
            file_put_contents($tmpFileName, $code);
412 181
            rename($tmpFileName, $fileName);
413 181
            chmod($fileName, 0664);
414
        }
415 181
    }
416
417
    /**
418
     * Hydrate array of MongoDB document data into the given document object.
419
     *
420
     * @param array $hints Any hints to account for during reconstitution/lookup of the document.
421
     */
422 397
    public function hydrate(object $document, array $data, array $hints = []) : array
423
    {
424 397
        $metadata = $this->dm->getClassMetadata(get_class($document));
425
        // Invoke preLoad lifecycle events and listeners
426 397
        if (! empty($metadata->lifecycleCallbacks[Events::preLoad])) {
0 ignored issues
show
Bug introduced by
Accessing lifecycleCallbacks on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
427 14
            $args = [new PreLoadEventArgs($document, $this->dm, $data)];
428 14
            $metadata->invokeLifecycleCallbacks(Events::preLoad, $document, $args);
429
        }
430 397
        if ($this->evm->hasListeners(Events::preLoad)) {
431 3
            $this->evm->dispatchEvent(Events::preLoad, new PreLoadEventArgs($document, $this->dm, $data));
432
        }
433
434
        // alsoLoadMethods may transform the document before hydration
435 397
        if (! empty($metadata->alsoLoadMethods)) {
0 ignored issues
show
Bug introduced by
Accessing alsoLoadMethods on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
436 12
            foreach ($metadata->alsoLoadMethods as $method => $fieldNames) {
0 ignored issues
show
Bug introduced by
Accessing alsoLoadMethods on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
437 12
                foreach ($fieldNames as $fieldName) {
438
                    // Invoke the method only once for the first field we find
439 12
                    if (array_key_exists($fieldName, $data)) {
440 8
                        $document->$method($data[$fieldName]);
441 12
                        continue 2;
442
                    }
443
                }
444
            }
445
        }
446
447 397
        if ($document instanceof GhostObjectInterface) {
448 79
            $document->setProxyInitializer(null);
449
        }
450
451 397
        $data = $this->getHydratorFor($metadata->name)->hydrate($document, $data, $hints);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
452
453
        // Invoke the postLoad lifecycle callbacks and listeners
454 397
        if (! empty($metadata->lifecycleCallbacks[Events::postLoad])) {
0 ignored issues
show
Bug introduced by
Accessing lifecycleCallbacks on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
455 13
            $metadata->invokeLifecycleCallbacks(Events::postLoad, $document, [new LifecycleEventArgs($document, $this->dm)]);
456
        }
457 397
        if ($this->evm->hasListeners(Events::postLoad)) {
458 4
            $this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($document, $this->dm));
459
        }
460
461 397
        return $data;
462
    }
463
}
464