Passed
Pull Request — master (#7770)
by
unknown
09:22
created

Configuration::newDefaultAnnotationDriver()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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\Cache\Exception\MetadataCacheNotConfigured;
16
use Doctrine\ORM\Cache\Exception\MetadataCacheUsesNonPersistentCache;
17
use Doctrine\ORM\Cache\Exception\QueryCacheNotConfigured;
18
use Doctrine\ORM\Cache\Exception\QueryCacheUsesNonPersistentCache;
19
use Doctrine\ORM\Exception\InvalidEntityRepository;
20
use Doctrine\ORM\Exception\ProxyClassesAlwaysRegenerating;
21
use Doctrine\ORM\Mapping\ClassMetadataFactory;
22
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
23
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
24
use Doctrine\ORM\Mapping\Driver\MappingDriver;
25
use Doctrine\ORM\Mapping\EntityListenerResolver;
26
use Doctrine\ORM\Mapping\Factory\DefaultNamingStrategy;
27
use Doctrine\ORM\Mapping\Factory\NamingStrategy;
28
use Doctrine\ORM\Proxy\Factory\ProxyFactory;
29
use Doctrine\ORM\Query\ResultSetMapping;
30
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
31
use Doctrine\ORM\Repository\RepositoryFactory;
32
use ProxyManager\Configuration as ProxyManagerConfiguration;
33
use ProxyManager\Factory\LazyLoadingGhostFactory;
34
use ProxyManager\FileLocator\FileLocator;
35
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
36
use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy;
37
use ReflectionClass;
38
use function strtolower;
39
40
/**
41
 * Configuration container for all configuration options of Doctrine.
42
 * It combines all configuration options from DBAL & ORM.
43
 *
44
 * {@internal When adding a new configuration option just write a getter/setter pair. }}
45
 */
46
class Configuration extends DBALConfiguration
47
{
48
    /** @var ProxyManagerConfiguration|null */
49
    private $proxyManagerConfiguration;
50
51
    /** @var MappingDriver|null */
52
    private $metadataDriver;
53
54
    /** @var CacheDriver|null */
55
    private $queryCache;
56
57
    /** @var CacheDriver|null */
58
    private $hydrationCache;
59
60
    /** @var CacheDriver|null */
61
    private $metadataCache;
62
63
    /** @var string[][]|ResultSetMapping[][] tuples of [$sqlString, $resultSetMapping] indexed by query name */
64
    private $customStringFunctions = [];
65
66
    /** @var string[][]|ResultSetMapping[][] tuples of [$sqlString, $resultSetMapping] indexed by query name */
67
    private $customNumericFunctions = [];
68
69
    /** @var string[][]|ResultSetMapping[][] tuples of [$sqlString, $resultSetMapping] indexed by query name */
70
    private $customDatetimeFunctions = [];
71
72
    /** @var string[] of hydrator class names, indexed by mode name */
73
    private $customHydrationModes = [];
74
75
    /** @var string */
76
    private $classMetadataFactoryClassName = ClassMetadataFactory::class;
77
78
    /** @var string[] of filter class names, indexed by filter name */
79
    private $filters;
80
81
    /** @var string */
82
    private $defaultRepositoryClassName = EntityRepository::class;
83
84
    /** @var NamingStrategy|null */
85
    private $namingStrategy;
86
87
    /** @var EntityListenerResolver|null */
88
    private $entityListenerResolver;
89
90
    /** @var RepositoryFactory|null */
91
    private $repositoryFactory;
92
93
    /** @var bool */
94
    private $isSecondLevelCacheEnabled = false;
95
96
    /** @var CacheConfiguration|null */
97
    private $secondLevelCacheConfiguration;
98
99
    /** @var mixed[] indexed by hint name */
100
    private $defaultQueryHints = [];
101
102
    /**
103
     * Sets the directory where Doctrine generates any necessary proxy class files.
104
     */
105 92
    public function setProxyDir(string $directory) : void
106
    {
107 92
        $this->getProxyManagerConfiguration()->setProxiesTargetDir($directory);
108 92
        $this->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS);
109 92
    }
110
111
    /**
112
     * Gets the directory where Doctrine generates any necessary proxy class files.
113
     *
114
     * @return string
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Configuration::getProxyDir() has useless @return annotation.
Loading history...
115
     */
116 1
    public function getProxyDir(): string
0 ignored issues
show
introduced by
There must be exactly 1 whitespace between closing parenthesis and return type colon.
Loading history...
117
    {
118 1
        return $this->getProxyManagerConfiguration()->getProxiesTargetDir();
119
    }
120
121
    /**
122
     * Sets the strategy for automatically generating proxy classes.
123
     *
124
     * @param bool|int $autoGenerate Possible values are constants of Doctrine\ORM\Proxy\Factory\ProxyFactory.
125
     *                               True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
126
     */
127 2298
    public function setAutoGenerateProxyClasses($autoGenerate) : void
128
    {
129 2298
        $proxyManagerConfig = $this->getProxyManagerConfiguration();
130
131 2298
        switch ((int) $autoGenerate) {
132
            case ProxyFactory::AUTOGENERATE_ALWAYS:
133
            case ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS:
134 101
                $proxyManagerConfig->setGeneratorStrategy(new FileWriterGeneratorStrategy(
135 101
                    new FileLocator($proxyManagerConfig->getProxiesTargetDir())
136
                ));
137
138 101
                return;
139
            case ProxyFactory::AUTOGENERATE_NEVER:
140
            case ProxyFactory::AUTOGENERATE_EVAL:
141
            default:
142 2212
                $proxyManagerConfig->setGeneratorStrategy(new EvaluatingGeneratorStrategy());
143
144 2212
                return;
145
        }
146
    }
147
148
    /**
149
     * Sets the namespace where proxy classes reside.
150
     */
151 2284
    public function setProxyNamespace(string $namespace) : void
152
    {
153 2284
        $this->getProxyManagerConfiguration()->setProxiesNamespace($namespace);
154 2284
    }
155
156
    /**
157
     * Sets the cache driver implementation that is used for metadata caching.
158
     *
159
     * @todo Force parameter to be a Closure to ensure lazy evaluation
160
     *       (as soon as a metadata cache is in effect, the driver never needs to initialize).
161
     */
162 2280
    public function setMetadataDriverImpl(MappingDriver $metadataDriver) : void
163
    {
164 2280
        $this->metadataDriver = $metadataDriver;
165 2280
    }
166
167
    /**
168
     * Adds a new default annotation driver with a correctly configured annotation reader.
169
     *
170
     * @param string[] $paths
171
     */
172 2268
    public function newDefaultAnnotationDriver(array $paths = []) : AnnotationDriver
173
    {
174 2268
        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

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