Failed Conditions
Pull Request — master (#7130)
by Michael
13:25 queued 18s
created

Configuration   F

Complexity

Total Complexity 63

Size/Duplication

Total Lines 549
Duplicated Lines 0 %

Test Coverage

Coverage 94.77%

Importance

Changes 0
Metric Value
dl 0
loc 549
ccs 145
cts 153
cp 0.9477
rs 3.6585
c 0
b 0
f 0
wmc 63

47 Methods

Rating   Name   Duplication   Size   Complexity  
A getFilterClassName() 0 3 1
A setMetadataDriverImpl() 0 3 1
A setCustomStringFunctions() 0 4 2
A setDefaultQueryHints() 0 3 1
A addCustomDatetimeFunction() 0 3 1
A getHydrationCacheImpl() 0 3 1
A getCustomHydrationMode() 0 3 1
A getSecondLevelCacheConfiguration() 0 7 3
A buildGhostObjectFactory() 0 3 1
A getCustomStringFunction() 0 3 1
A getMetadataCacheImpl() 0 3 1
A setSecondLevelCacheConfiguration() 0 3 1
A addCustomHydrationMode() 0 3 1
A setMetadataCacheImpl() 0 3 1
A setCustomHydrationModes() 0 6 2
A getProxyManagerConfiguration() 0 4 1
B setAutoGenerateProxyClasses() 0 18 5
A setHydrationCacheImpl() 0 3 1
A setQueryCacheImpl() 0 3 1
A getDefaultQueryHint() 0 3 1
A setNamingStrategy() 0 3 1
A setProxyDir() 0 4 1
A getClassMetadataFactoryName() 0 3 1
A setSecondLevelCacheEnabled() 0 3 1
A isSecondLevelCacheEnabled() 0 3 1
A setCustomNumericFunctions() 0 4 2
A getCustomNumericFunction() 0 3 1
A getMetadataDriverImpl() 0 3 1
A addCustomStringFunction() 0 3 1
A setCustomDatetimeFunctions() 0 4 2
A setProxyNamespace() 0 3 1
A getNamingStrategy() 0 4 1
A getDefaultQueryHints() 0 3 1
A getEntityListenerResolver() 0 4 1
A newDefaultAnnotationDriver() 0 7 1
A setClassMetadataFactoryName() 0 3 1
A setEntityListenerResolver() 0 3 1
A getQueryCacheImpl() 0 3 1
A getRepositoryFactory() 0 4 1
A addFilter() 0 3 1
A setDefaultQueryHint() 0 3 1
A getCustomDatetimeFunction() 0 3 1
A addCustomNumericFunction() 0 3 1
B ensureProductionSettings() 0 24 6
A getDefaultRepositoryClassName() 0 3 1
A setRepositoryFactory() 0 3 1
A setDefaultRepositoryClassName() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like Configuration often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Configuration, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM;
6
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use Doctrine\Common\Annotations\AnnotationRegistry;
9
use Doctrine\Common\Annotations\CachedReader;
10
use Doctrine\Common\Cache\ArrayCache;
11
use Doctrine\Common\Cache\Cache as CacheDriver;
12
use Doctrine\Common\Persistence\ObjectRepository;
13
use Doctrine\DBAL\Configuration as DBALConfiguration;
14
use Doctrine\ORM\Cache\CacheConfiguration;
15
use Doctrine\ORM\Mapping\ClassMetadataFactory;
16
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
17
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
18
use Doctrine\ORM\Mapping\Driver\MappingDriver;
19
use Doctrine\ORM\Mapping\EntityListenerResolver;
20
use Doctrine\ORM\Mapping\Factory\DefaultNamingStrategy;
21
use Doctrine\ORM\Mapping\Factory\NamingStrategy;
22
use Doctrine\ORM\Proxy\Factory\ProxyFactory;
23
use Doctrine\ORM\Query\ResultSetMapping;
24
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
25
use Doctrine\ORM\Repository\RepositoryFactory;
26
use ProxyManager\Configuration as ProxyManagerConfiguration;
27
use ProxyManager\Factory\LazyLoadingGhostFactory;
28
use ProxyManager\FileLocator\FileLocator;
29
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
30
use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy;
31
use function strtolower;
32
33
/**
34
 * Configuration container for all configuration options of Doctrine.
35
 * It combines all configuration options from DBAL & ORM.
36
 *
37
 * {@internal When adding a new configuration option just write a getter/setter pair. }}
38
 */
39
class Configuration extends DBALConfiguration
40
{
41
    /** @var ProxyManagerConfiguration|null */
42
    private $proxyManagerConfiguration;
43
44
    /** @var MappingDriver|null */
45
    private $metadataDriver;
46
47
    /** @var CacheDriver|null */
48
    private $queryCache;
49
50
    /** @var CacheDriver|null */
51
    private $hydrationCache;
52
53
    /** @var CacheDriver|null */
54
    private $metadataCache;
55
56
    /** @var string[][]|ResultSetMapping[][] tuples of [$sqlString, $resultSetMapping] indexed by query name */
57
    private $customStringFunctions = [];
58
59
    /** @var string[][]|ResultSetMapping[][] tuples of [$sqlString, $resultSetMapping] indexed by query name */
60
    private $customNumericFunctions = [];
61
62
    /** @var string[][]|ResultSetMapping[][] tuples of [$sqlString, $resultSetMapping] indexed by query name */
63
    private $customDatetimeFunctions = [];
64
65
    /** @var string[] of hydrator class names, indexed by mode name */
66
    private $customHydrationModes = [];
67
68
    /** @var string */
69
    private $classMetadataFactoryClassName = ClassMetadataFactory::class;
70
71
    /** @var string[] of filter class names, indexed by filter name */
72
    private $filters;
73
74
    /** @var string */
75
    private $defaultRepositoryClassName = EntityRepository::class;
76
77
    /** @var NamingStrategy|null */
78
    private $namingStrategy;
79
80
    /** @var EntityListenerResolver|null */
81
    private $entityListenerResolver;
82
83
    /** @var RepositoryFactory|null */
84
    private $repositoryFactory;
85
86
    /** @var bool */
87
    private $isSecondLevelCacheEnabled = false;
88
89
    /** @var CacheConfiguration|null */
90
    private $secondLevelCacheConfiguration;
91
92
    /** @var mixed[] indexed by hint name */
93
    private $defaultQueryHints = [];
94
95
    /**
96
     * Sets the directory where Doctrine generates any necessary proxy class files.
97
     */
98 88
    public function setProxyDir(string $directory) : void
99
    {
100 88
        $this->getProxyManagerConfiguration()->setProxiesTargetDir($directory);
101 88
        $this->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS);
102 88
    }
103
104
    /**
105
     * Sets the strategy for automatically generating proxy classes.
106
     *
107
     * @param bool|int $autoGenerate Possible values are constants of Doctrine\ORM\Proxy\Factory\ProxyFactory.
108
     *                               True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
109
     */
110 2264
    public function setAutoGenerateProxyClasses($autoGenerate) : void
111
    {
112 2264
        $proxyManagerConfig = $this->getProxyManagerConfiguration();
113
114 2264
        switch ((int) $autoGenerate) {
115
            case ProxyFactory::AUTOGENERATE_ALWAYS:
116
            case ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS:
117 97
                $proxyManagerConfig->setGeneratorStrategy(new FileWriterGeneratorStrategy(
118 97
                    new FileLocator($proxyManagerConfig->getProxiesTargetDir())
119
                ));
120
121 97
                return;
122
            case ProxyFactory::AUTOGENERATE_NEVER:
123
            case ProxyFactory::AUTOGENERATE_EVAL:
124
            default:
125 2182
                $proxyManagerConfig->setGeneratorStrategy(new EvaluatingGeneratorStrategy());
126
127 2182
                return;
128
        }
129
    }
130
131
    /**
132
     * Sets the namespace where proxy classes reside.
133
     */
134 2251
    public function setProxyNamespace(string $namespace) : void
135
    {
136 2251
        $this->getProxyManagerConfiguration()->setProxiesNamespace($namespace);
137 2251
    }
138
139
    /**
140
     * Sets the cache driver implementation that is used for metadata caching.
141
     *
142
     * @todo Force parameter to be a Closure to ensure lazy evaluation
143
     *       (as soon as a metadata cache is in effect, the driver never needs to initialize).
144
     */
145 2247
    public function setMetadataDriverImpl(MappingDriver $metadataDriver) : void
146
    {
147 2247
        $this->metadataDriver = $metadataDriver;
148 2247
    }
149
150
    /**
151
     * Adds a new default annotation driver with a correctly configured annotation reader.
152
     *
153
     * @param string[] $paths
154
     */
155 2237
    public function newDefaultAnnotationDriver(array $paths = []) : AnnotationDriver
156
    {
157 2237
        AnnotationRegistry::registerFile(__DIR__ . '/Annotation/DoctrineAnnotations.php');
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\Common\Annotati...egistry::registerFile() has been deprecated: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists') ( Ignorable by Annotation )

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

157
        /** @scrutinizer ignore-deprecated */ AnnotationRegistry::registerFile(__DIR__ . '/Annotation/DoctrineAnnotations.php');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
158
159 2237
        $reader = new CachedReader(new AnnotationReader(), new ArrayCache());
160
161 2237
        return new AnnotationDriver($reader, $paths);
162
    }
163
164
    /**
165
     * Gets the cache driver implementation that is used for the mapping metadata.
166
     */
167 2245
    public function getMetadataDriverImpl() : ?MappingDriver
168
    {
169 2245
        return $this->metadataDriver;
170
    }
171
172
    /**
173
     * Gets the cache driver implementation that is used for the query cache (SQL cache).
174
     */
175 771
    public function getQueryCacheImpl() : ?CacheDriver
176
    {
177 771
        return $this->queryCache;
178
    }
179
180
    /**
181
     * Sets the cache driver implementation that is used for the query cache (SQL cache).
182
     */
183 2189
    public function setQueryCacheImpl(CacheDriver $queryCache) : void
184
    {
185 2189
        $this->queryCache = $queryCache;
186 2189
    }
187
188
    /**
189
     * Gets the cache driver implementation that is used for the hydration cache (SQL cache).
190
     */
191 1
    public function getHydrationCacheImpl() : ?CacheDriver
192
    {
193 1
        return $this->hydrationCache;
194
    }
195
196
    /**
197
     * Sets the cache driver implementation that is used for the hydration cache (SQL cache).
198
     */
199 1
    public function setHydrationCacheImpl(CacheDriver $hydrationCache) : void
200
    {
201 1
        $this->hydrationCache = $hydrationCache;
202 1
    }
203
204
    /**
205
     * Gets the cache driver implementation that is used for metadata caching.
206
     */
207 2252
    public function getMetadataCacheImpl() : ?CacheDriver
208
    {
209 2252
        return $this->metadataCache;
210
    }
211
212
    /**
213
     * Sets the cache driver implementation that is used for metadata caching.
214
     */
215 2189
    public function setMetadataCacheImpl(CacheDriver $metadataCache) : void
216
    {
217 2189
        $this->metadataCache = $metadataCache;
218 2189
    }
219
220
    /**
221
     * Ensures that this Configuration instance contains settings that are
222
     * suitable for a production environment.
223
     *
224
     * @throws ORMException If a configuration setting has a value that is not
225
     *                      suitable for a production environment.
226
     */
227 6
    public function ensureProductionSettings() : void
228
    {
229 6
        $queryCacheImpl = $this->getQueryCacheImpl();
230
231 6
        if (! $queryCacheImpl) {
232 1
            throw ORMException::queryCacheNotConfigured();
233
        }
234
235 5
        if ($queryCacheImpl instanceof ArrayCache) {
236 1
            throw ORMException::queryCacheUsesNonPersistentCache($queryCacheImpl);
237
        }
238
239 4
        $metadataCacheImpl = $this->getMetadataCacheImpl();
240
241 4
        if (! $metadataCacheImpl) {
242 1
            throw ORMException::metadataCacheNotConfigured();
243
        }
244
245 3
        if ($metadataCacheImpl instanceof ArrayCache) {
246 1
            throw ORMException::metadataCacheUsesNonPersistentCache($metadataCacheImpl);
247
        }
248
249 2
        if ($this->getProxyManagerConfiguration()->getGeneratorStrategy() instanceof EvaluatingGeneratorStrategy) {
250 1
            throw ORMException::proxyClassesAlwaysRegenerating();
251
        }
252 1
    }
253
254
    /**
255
     * Registers a custom DQL function that produces a string value.
256
     * Such a function can then be used in any DQL statement in any place where string
257
     * functions are allowed.
258
     *
259
     * DQL function names are case-insensitive.
260
     *
261
     * @param string|callable $classNameOrFactory Class name or a callable that returns the function.
262
     */
263 4
    public function addCustomStringFunction(string $functionName, $classNameOrFactory) : void
264
    {
265 4
        $this->customStringFunctions[strtolower($functionName)] = $classNameOrFactory;
266 4
    }
267
268
    /**
269
     * Gets the implementation class name of a registered custom string DQL function.
270
     *
271
     * @return string|callable|null
272
     */
273 159
    public function getCustomStringFunction(string $functionName)
274
    {
275 159
        return $this->customStringFunctions[strtolower($functionName)] ?? null;
276
    }
277
278
    /**
279
     * Sets a map of custom DQL string functions.
280
     *
281
     * Keys must be function names and values the FQCN of the implementing class.
282
     * The function names will be case-insensitive in DQL.
283
     *
284
     * Any previously added string functions are discarded.
285
     *
286
     * @param string[]|callable[] $functions The map of custom DQL string functions.
287
     */
288 1
    public function setCustomStringFunctions(array $functions) : void
289
    {
290 1
        foreach ($functions as $name => $className) {
291 1
            $this->addCustomStringFunction($name, $className);
292
        }
293 1
    }
294
295
    /**
296
     * Registers a custom DQL function that produces a numeric value.
297
     * Such a function can then be used in any DQL statement in any place where numeric
298
     * functions are allowed.
299
     *
300
     * DQL function names are case-insensitive.
301
     *
302
     * @param string|callable $classNameOrFactory Class name or a callable that returns the function.
303
     */
304 3
    public function addCustomNumericFunction(string $functionName, $classNameOrFactory) : void
305
    {
306 3
        $this->customNumericFunctions[strtolower($functionName)] = $classNameOrFactory;
307 3
    }
308
309
    /**
310
     * Gets the implementation class name of a registered custom numeric DQL function.
311
     *
312
     * @return string|callable|null
313
     */
314 157
    public function getCustomNumericFunction(string $functionName)
315
    {
316 157
        return $this->customNumericFunctions[strtolower($functionName)] ?? null;
317
    }
318
319
    /**
320
     * Sets a map of custom DQL numeric functions.
321
     *
322
     * Keys must be function names and values the FQCN of the implementing class.
323
     * The function names will be case-insensitive in DQL.
324
     *
325
     * Any previously added numeric functions are discarded.
326
     *
327
     * @param string[]|callable[] $functions The map of custom DQL numeric functions.
328
     */
329 2
    public function setCustomNumericFunctions(array $functions) : void
330
    {
331 2
        foreach ($functions as $name => $className) {
332 1
            $this->addCustomNumericFunction($name, $className);
333
        }
334 2
    }
335
336
    /**
337
     * Registers a custom DQL function that produces a date/time value.
338
     * Such a function can then be used in any DQL statement in any place where date/time
339
     * functions are allowed.
340
     *
341
     * DQL function names are case-insensitive.
342
     *
343
     * @param string|callable $classNameOrFactory Class name or a callable that returns the function.
344
     */
345 1
    public function addCustomDatetimeFunction(string $functionName, $classNameOrFactory) : void
346
    {
347 1
        $this->customDatetimeFunctions[strtolower($functionName)] = $classNameOrFactory;
348 1
    }
349
350
    /**
351
     * Gets the implementation class name of a registered custom date/time DQL function.
352
     *
353
     * @return string|callable|null
354
     */
355 155
    public function getCustomDatetimeFunction(string $functionName)
356
    {
357 155
        return $this->customDatetimeFunctions[strtolower($functionName)] ?? null;
358
    }
359
360
    /**
361
     * Sets a map of custom DQL date/time functions.
362
     *
363
     * Keys must be function names and values the FQCN of the implementing class.
364
     * The function names will be case-insensitive in DQL.
365
     *
366
     * Any previously added date/time functions are discarded.
367
     *
368
     * @param iterable|string[] $functions The map of custom DQL date/time functions.
369
     */
370 1
    public function setCustomDatetimeFunctions(array $functions) : void
371
    {
372 1
        foreach ($functions as $name => $className) {
373 1
            $this->addCustomDatetimeFunction($name, $className);
374
        }
375 1
    }
376
377
    /**
378
     * Sets the custom hydrator modes in one pass.
379
     *
380
     * @param iterable|string[] $modes An iterable of string $modeName => string $hydratorClassName
381
     */
382 1
    public function setCustomHydrationModes(iterable $modes) : void
383
    {
384 1
        $this->customHydrationModes = [];
385
386 1
        foreach ($modes as $modeName => $hydrator) {
387 1
            $this->addCustomHydrationMode($modeName, $hydrator);
388
        }
389 1
    }
390
391
    /**
392
     * Gets the hydrator class for the given hydration mode name.
393
     *
394
     * @return string|null The hydrator class name.
395
     */
396 3
    public function getCustomHydrationMode(string $modeName) : ?string
397
    {
398 3
        return $this->customHydrationModes[$modeName] ?? null;
399
    }
400
401
    /**
402
     * Adds a custom hydration mode.
403
     */
404 3
    public function addCustomHydrationMode(string $modeName, string $hydratorClassName) : void
405
    {
406 3
        $this->customHydrationModes[$modeName] = $hydratorClassName;
407 3
    }
408
409
    /**
410
     * Sets a class metadata factory.
411
     */
412 1
    public function setClassMetadataFactoryName(string $classMetadataFactoryClassName) : void
413
    {
414 1
        $this->classMetadataFactoryClassName = $classMetadataFactoryClassName;
415 1
    }
416
417 2243
    public function getClassMetadataFactoryName() : string
418
    {
419 2243
        return $this->classMetadataFactoryClassName;
420
    }
421
422
    /**
423
     * Adds a filter to the list of possible filters.
424
     */
425 46
    public function addFilter(string $filterName, string $filterClassName) : void
426
    {
427 46
        $this->filters[$filterName] = $filterClassName;
428 46
    }
429
430
    /**
431
     * Gets the class name for a given filter name.
432
     *
433
     * @return string|null The class name of the filter
434
     */
435 45
    public function getFilterClassName(string $filterName) : ?string
436
    {
437 45
        return $this->filters[$filterName] ?? null;
438
    }
439
440
    /**
441
     * Sets default repository class.
442
     *
443
     * @throws ORMException If not is a \Doctrine\Common\Persistence\ObjectRepository implementation.
444
     */
445 1
    public function setDefaultRepositoryClassName(string $repositoryClassName) : void
446
    {
447 1
        $reflectionClass = new \ReflectionClass($repositoryClassName);
448
449 1
        if (! $reflectionClass->implementsInterface(ObjectRepository::class)) {
450 1
            throw ORMException::invalidEntityRepository($repositoryClassName);
451
        }
452
453
        $this->defaultRepositoryClassName = $repositoryClassName;
454
    }
455
456
    /**
457
     * Get default repository class.
458
     */
459 135
    public function getDefaultRepositoryClassName() : string
460
    {
461 135
        return $this->defaultRepositoryClassName;
462
    }
463
464
    /**
465
     * Sets naming strategy.
466
     */
467 3
    public function setNamingStrategy(NamingStrategy $namingStrategy) : void
468
    {
469 3
        $this->namingStrategy = $namingStrategy;
470 3
    }
471
472
    /**
473
     * Gets naming strategy..
474
     */
475 1951
    public function getNamingStrategy() : ?NamingStrategy
476
    {
477 1951
        return $this->namingStrategy
478 1951
            ?? $this->namingStrategy = new DefaultNamingStrategy();
479
    }
480
481
    /**
482
     * Set the entity listener resolver.
483
     */
484 1
    public function setEntityListenerResolver(EntityListenerResolver $resolver) : void
485
    {
486 1
        $this->entityListenerResolver = $resolver;
487 1
    }
488
489
    /**
490
     * Get the entity listener resolver.
491
     */
492 2243
    public function getEntityListenerResolver() : EntityListenerResolver
493
    {
494 2243
        return $this->entityListenerResolver
495 2243
            ?? $this->entityListenerResolver = new DefaultEntityListenerResolver();
496
    }
497
498
    /**
499
     * Set the entity repository factory.
500
     */
501
    public function setRepositoryFactory(RepositoryFactory $repositoryFactory) : void
502
    {
503
        $this->repositoryFactory = $repositoryFactory;
504
    }
505
506
    /**
507
     * Get the entity repository factory.
508
     */
509 2242
    public function getRepositoryFactory() : RepositoryFactory
510
    {
511 2242
        return $this->repositoryFactory
512 2242
            ?? $this->repositoryFactory = new DefaultRepositoryFactory();
513
    }
514
515 2242
    public function isSecondLevelCacheEnabled() : bool
516
    {
517 2242
        return $this->isSecondLevelCacheEnabled;
518
    }
519
520 280
    public function setSecondLevelCacheEnabled(bool $flag = true) : void
521
    {
522 280
        $this->isSecondLevelCacheEnabled = $flag;
523 280
    }
524
525 281
    public function setSecondLevelCacheConfiguration(CacheConfiguration $cacheConfig) : void
526
    {
527 281
        $this->secondLevelCacheConfiguration = $cacheConfig;
528 281
    }
529
530 281
    public function getSecondLevelCacheConfiguration() : ?CacheConfiguration
531
    {
532 281
        if ($this->isSecondLevelCacheEnabled && ! $this->secondLevelCacheConfiguration) {
533
            $this->secondLevelCacheConfiguration = new CacheConfiguration();
534
        }
535
536 281
        return $this->secondLevelCacheConfiguration;
537
    }
538
539
    /**
540
     * Returns query hints, which will be applied to every query in application
541
     *
542
     * @return mixed[]
543
     */
544 967
    public function getDefaultQueryHints() : array
545
    {
546 967
        return $this->defaultQueryHints;
547
    }
548
549
    /**
550
     * Sets array of query hints, which will be applied to every query in application
551
     *
552
     * @param mixed[] $defaultQueryHints
553
     */
554 1
    public function setDefaultQueryHints(array $defaultQueryHints) : void
555
    {
556 1
        $this->defaultQueryHints = $defaultQueryHints;
557 1
    }
558
559
    /**
560
     * Gets the value of a default query hint. If the hint name is not recognized, FALSE is returned.
561
     *
562
     * @return mixed The value of the hint or FALSE, if the hint name is not recognized.
563
     */
564
    public function getDefaultQueryHint(string $hintName)
565
    {
566
        return $this->defaultQueryHints[$hintName] ?? false;
567
    }
568
569
    /**
570
     * Sets a default query hint. If the hint name is not recognized, it is silently ignored.
571
     *
572
     * @param mixed $value The value of the hint.
573
     */
574 1
    public function setDefaultQueryHint(string $hintName, $value) : void
575
    {
576 1
        $this->defaultQueryHints[$hintName] = $value;
577 1
    }
578
579 2243
    public function buildGhostObjectFactory() : LazyLoadingGhostFactory
580
    {
581 2243
        return new LazyLoadingGhostFactory(clone $this->getProxyManagerConfiguration());
582
    }
583
584 2266
    public function getProxyManagerConfiguration() : ProxyManagerConfiguration
585
    {
586 2266
        return $this->proxyManagerConfiguration
587 2266
            ?? $this->proxyManagerConfiguration = new ProxyManagerConfiguration();
588
    }
589
}
590