Completed
Push — master ( 14b33f...9b5b27 )
by Julián
02:07
created

RelationalBuilder   F

Complexity

Total Complexity 50

Size/Duplication

Total Lines 567
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 37

Importance

Changes 0
Metric Value
wmc 50
lcom 1
cbo 37
dl 0
loc 567
rs 2.8089
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A getDefaultOptions() 0 12 1
A wipe() 0 12 1
B buildManager() 0 32 5
A setUpGeneralConfigurations() 0 19 3
A setUpSpecificConfigurations() 0 18 2
A getAnnotationMappingDriver() 0 4 1
A getXmlMappingDriver() 0 6 2
A getYamlMappingDriver() 0 6 2
A getRepositoryFactory() 0 17 3
A getQueryCacheDriver() 0 11 2
A setQueryCacheDriver() 0 4 1
A getResultCacheDriver() 0 11 2
A setResultCacheDriver() 0 4 1
A getHydratorCacheDriver() 0 11 2
A setHydratorCacheDriver() 0 4 1
A getCacheDriver() 0 13 3
A getNamingStrategy() 0 14 3
A getQuoteStrategy() 0 14 3
A getSQLLogger() 0 12 3
A getCustomStringFunctions() 0 12 1
A getCustomNumericFunctions() 0 12 1
A getCustomDateTimeFunctions() 0 12 1
A getCustomTypes() 0 12 1
A getCustomFilters() 0 12 1
A getConsoleCommands() 0 52 3
A getConsoleHelperSet() 0 10 1

How to fix   Complexity   

Complex Class

Complex classes like RelationalBuilder 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 RelationalBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * doctrine-manager-builder (https://github.com/juliangut/doctrine-manager-builder).
5
 * Doctrine2 managers builder.
6
 *
7
 * @license BSD-3-Clause
8
 * @link https://github.com/juliangut/doctrine-manager-builder
9
 * @author Julián Gutiérrez <[email protected]>
10
 */
11
12
namespace Jgut\Doctrine\ManagerBuilder;
13
14
use Doctrine\Common\Annotations\AnnotationReader;
15
use Doctrine\Common\Cache\CacheProvider;
16
use Doctrine\DBAL\Logging\SQLLogger;
17
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
18
use Doctrine\DBAL\Types\Type;
19
use Doctrine\ORM\Configuration;
20
use Doctrine\ORM\EntityManager;
21
use Doctrine\ORM\EntityRepository;
22
use Doctrine\ORM\Mapping\DefaultQuoteStrategy;
23
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
24
use Doctrine\ORM\Mapping\Driver\XmlDriver;
25
use Doctrine\ORM\Mapping\Driver\YamlDriver;
26
use Doctrine\ORM\Mapping\NamingStrategy;
27
use Doctrine\ORM\Mapping\QuoteStrategy;
28
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
29
use Doctrine\ORM\Repository\RepositoryFactory;
30
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
31
use Doctrine\ORM\Version;
32
use Symfony\Component\Console\Command\Command;
33
use Symfony\Component\Console\Helper\HelperSet;
34
35
/**
36
 * Doctrine RDBMS Entity Manager builder.
37
 *
38
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
39
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
40
 */
41
class RelationalBuilder extends AbstractManagerBuilder
42
{
43
    /**
44
     * Query cache driver.
45
     *
46
     * @var CacheProvider
47
     */
48
    protected $queryCacheDriver;
49
50
    /**
51
     * Result cache driver.
52
     *
53
     * @var CacheProvider
54
     */
55
    protected $resultCacheDriver;
56
57
    /**
58
     * Hydrator cache driver.
59
     *
60
     * @var CacheProvider
61
     */
62
    protected $hydratorCacheDriver;
63
64
    /**
65
     * Naming strategy.
66
     *
67
     * @var NamingStrategy
68
     */
69
    protected $namingStrategy;
70
71
    /**
72
     * Quote strategy.
73
     *
74
     * @var QuoteStrategy
75
     */
76
    protected $quoteStrategy;
77
78
    /**
79
     * SQL logger.
80
     *
81
     * @var SQLLogger
82
     */
83
    protected $SQLLogger;
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    protected function getDefaultOptions()
89
    {
90
        return [
91
            'connection' => [], // Array or \Doctrine\DBAL\Connection
92
            'proxies_namespace' => 'DoctrineRDBMSORMProxy',
93
            'metadata_cache_namespace' => 'DoctrineRDBMSORMMetadataCache',
94
            'query_cache_namespace' => 'DoctrineRDBMSORMQueryCache',
95
            'result_cache_namespace' => 'DoctrineRDBMSORMResultCache',
96
            'hydrator_cache_namespace' => 'DoctrineRDBMSORMHydratorCache',
97
            'default_repository_class' => EntityRepository::class,
98
        ];
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    protected function wipe()
105
    {
106
        $this->manager = null;
107
        $this->mappingDriver = null;
108
        $this->metadataCacheDriver = null;
109
        $this->eventManager = null;
110
        $this->queryCacheDriver = null;
111
        $this->resultCacheDriver = null;
112
        $this->namingStrategy = null;
113
        $this->quoteStrategy = null;
114
        $this->SQLLogger = null;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     *
120
     * @throws \Doctrine\DBAL\DBALException
121
     * @throws \Doctrine\ORM\ORMException
122
     * @throws \InvalidArgumentException
123
     * @throws \RuntimeException
124
     * @throws \UnexpectedValueException
125
     *
126
     * @return EntityManager
127
     */
128
    protected function buildManager()
129
    {
130
        $config = new Configuration();
131
132
        $this->setUpGeneralConfigurations($config);
133
        $this->setUpSpecificConfigurations($config);
134
135
        $eventManager = $this->getEventManager();
136
        if ($this->getEventSubscribers() !== null) {
137
            /* @var array $eventSubscribers */
138
            $eventSubscribers = $this->getEventSubscribers();
139
140
            foreach ($eventSubscribers as $eventSubscriber) {
141
                $eventManager->addEventSubscriber($eventSubscriber);
142
            }
143
        }
144
145
        $entityManager = EntityManager::create($this->getOption('connection'), $config, $eventManager);
146
147
        $platform = $entityManager->getConnection()->getDatabasePlatform();
148
        foreach ($this->getCustomTypes() as $type => $class) {
149
            if (Type::hasType($type)) {
150
                Type::overrideType($type, $class);
151
            } else {
152
                Type::addType($type, $class);
153
            }
154
155
            $platform->registerDoctrineTypeMapping($type, $type);
156
        }
157
158
        return $entityManager;
159
    }
160
161
    /**
162
     * Set up general manager configurations.
163
     *
164
     * @param Configuration $config
165
     */
166
    protected function setUpGeneralConfigurations(Configuration $config)
167
    {
168
        $this->setupAnnotationMetadata();
169
        $config->setMetadataDriverImpl($this->getMetadataMappingDriver());
170
171
        $config->setProxyDir($this->getProxiesPath());
172
        $config->setProxyNamespace($this->getProxiesNamespace());
173
        $config->setAutoGenerateProxyClasses($this->getProxiesAutoGeneration());
174
175
        if ($this->getRepositoryFactory() !== null) {
176
            $config->setRepositoryFactory($this->getRepositoryFactory());
177
        }
178
179
        if ($this->getDefaultRepositoryClass() !== null) {
180
            $config->setDefaultRepositoryClassName($this->getDefaultRepositoryClass());
181
        }
182
183
        $config->setMetadataCacheImpl($this->getMetadataCacheDriver());
184
    }
185
186
    /**
187
     * Set up manager specific configurations.
188
     *
189
     * @param Configuration $config
190
     */
191
    protected function setUpSpecificConfigurations(Configuration $config)
192
    {
193
        $config->setQueryCacheImpl($this->getQueryCacheDriver());
194
        $config->setResultCacheImpl($this->getResultCacheDriver());
195
        $config->setHydrationCacheImpl($this->getHydratorCacheDriver());
196
197
        $config->setNamingStrategy($this->getNamingStrategy());
198
        $config->setQuoteStrategy($this->getQuoteStrategy());
199
200
        $config->setSQLLogger($this->getSQLLogger());
201
        $config->setCustomStringFunctions($this->getCustomStringFunctions());
202
        $config->setCustomNumericFunctions($this->getCustomNumericFunctions());
203
        $config->setCustomDatetimeFunctions($this->getCustomDateTimeFunctions());
204
205
        foreach ($this->getCustomFilters() as $name => $filterClass) {
206
            $config->addFilter($name, $filterClass);
207
        }
208
    }
209
210
    /**
211
     * {@inheritdoc}
212
     */
213
    protected function getAnnotationMappingDriver(array $paths)
214
    {
215
        return new AnnotationDriver(new AnnotationReader, $paths);
216
    }
217
218
    /**
219
     * {@inheritdoc}
220
     */
221
    protected function getXmlMappingDriver(array $paths, $extension = null)
222
    {
223
        $extension = $extension ?: XmlDriver::DEFAULT_FILE_EXTENSION;
224
225
        return new XmlDriver($paths, $extension);
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    protected function getYamlMappingDriver(array $paths, $extension = null)
232
    {
233
        $extension = $extension ?: YamlDriver::DEFAULT_FILE_EXTENSION;
234
235
        return new YamlDriver($paths, $extension);
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     *
241
     * @throws \InvalidArgumentException
242
     *
243
     * @return RepositoryFactory|null
244
     */
245
    protected function getRepositoryFactory()
246
    {
247
        if (!array_key_exists('repository_factory', $this->options)) {
248
            return;
249
        }
250
251
        $repositoryFactory = $this->options['repository_factory'];
252
253
        if (!$repositoryFactory instanceof RepositoryFactory) {
254
            throw new \InvalidArgumentException(sprintf(
255
                'Invalid factory class "%s". It must be a Doctrine\ORM\Repository\RepositoryFactory.',
256
                get_class($repositoryFactory)
257
            ));
258
        }
259
260
        return $repositoryFactory;
261
    }
262
263
    /**
264
     * Retrieve query cache driver.
265
     *
266
     * @throws \InvalidArgumentException
267
     *
268
     * @return CacheProvider
269
     */
270
    public function getQueryCacheDriver()
271
    {
272
        if (!$this->queryCacheDriver instanceof CacheProvider) {
273
            $this->queryCacheDriver = $this->getCacheDriver(
274
                (string) $this->getOption('query_cache_namespace'),
275
                $this->getOption('query_cache_driver')
276
            );
277
        }
278
279
        return $this->queryCacheDriver;
280
    }
281
282
    /**
283
     * Set query cache driver.
284
     *
285
     * @param CacheProvider $queryCacheDriver
286
     */
287
    public function setQueryCacheDriver(CacheProvider $queryCacheDriver)
288
    {
289
        $this->queryCacheDriver = $queryCacheDriver;
290
    }
291
292
    /**
293
     * Retrieve result cache driver.
294
     *
295
     * @throws \InvalidArgumentException
296
     *
297
     * @return CacheProvider
298
     */
299
    public function getResultCacheDriver()
300
    {
301
        if (!$this->resultCacheDriver instanceof CacheProvider) {
302
            $this->resultCacheDriver = $this->getCacheDriver(
303
                (string) $this->getOption('result_cache_namespace'),
304
                $this->getOption('result_cache_driver')
305
            );
306
        }
307
308
        return $this->resultCacheDriver;
309
    }
310
311
    /**
312
     * Set result cache driver.
313
     *
314
     * @param CacheProvider $resultCacheDriver
315
     */
316
    public function setResultCacheDriver(CacheProvider $resultCacheDriver)
317
    {
318
        $this->resultCacheDriver = $resultCacheDriver;
319
    }
320
321
    /**
322
     * Retrieve hydrator cache driver.
323
     *
324
     * @throws \InvalidArgumentException
325
     *
326
     * @return CacheProvider
327
     */
328
    public function getHydratorCacheDriver()
329
    {
330
        if (!$this->hydratorCacheDriver instanceof CacheProvider) {
331
            $this->hydratorCacheDriver = $this->getCacheDriver(
332
                (string) $this->getOption('hydrator_cache_namespace'),
333
                $this->getOption('hydrator_cache_driver')
334
            );
335
        }
336
337
        return $this->hydratorCacheDriver;
338
    }
339
340
    /**
341
     * Set hydrator cache driver.
342
     *
343
     * @param CacheProvider $hydratorCacheDriver
344
     */
345
    public function setHydratorCacheDriver(CacheProvider $hydratorCacheDriver)
346
    {
347
        $this->hydratorCacheDriver = $hydratorCacheDriver;
348
    }
349
350
    /**
351
     * Get cache driver.
352
     *
353
     * @param string $cacheNamespace
354
     * @param CacheProvider $cacheDriver
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cacheDriver not be null|CacheProvider?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
355
     *
356
     * @return CacheProvider
357
     */
358
    protected function getCacheDriver($cacheNamespace, CacheProvider $cacheDriver = null)
359
    {
360
        if (!$cacheDriver instanceof CacheProvider) {
361
            $cacheDriver = clone $this->getMetadataCacheDriver();
362
            $cacheDriver->setNamespace($cacheNamespace);
363
        }
364
365
        if ($cacheDriver->getNamespace() === '') {
366
            $cacheDriver->setNamespace($cacheNamespace);
367
        }
368
369
        return $cacheDriver;
370
    }
371
372
    /**
373
     * Retrieve naming strategy.
374
     *
375
     * @return NamingStrategy
376
     */
377
    protected function getNamingStrategy()
378
    {
379
        if (!$this->namingStrategy instanceof NamingStrategy) {
380
            $namingStrategy = $this->getOption('naming_strategy');
381
382
            if (!$namingStrategy instanceof NamingStrategy) {
383
                $namingStrategy = new UnderscoreNamingStrategy(CASE_LOWER);
384
            }
385
386
            $this->namingStrategy = $namingStrategy;
387
        }
388
389
        return $this->namingStrategy;
390
    }
391
392
    /**
393
     * Retrieve quote strategy.
394
     *
395
     * @throws \InvalidArgumentException
396
     *
397
     * @return QuoteStrategy
398
     */
399
    protected function getQuoteStrategy()
400
    {
401
        if (!$this->quoteStrategy instanceof QuoteStrategy) {
402
            $quoteStrategy = $this->getOption('quote_strategy');
403
404
            if (!$quoteStrategy instanceof QuoteStrategy) {
405
                $quoteStrategy = new DefaultQuoteStrategy;
406
            }
407
408
            $this->quoteStrategy = $quoteStrategy;
409
        }
410
411
        return $this->quoteStrategy;
412
    }
413
414
    /**
415
     * Retrieve SQL logger.
416
     *
417
     * @return SQLLogger|null
418
     */
419
    protected function getSQLLogger()
420
    {
421
        if (!$this->SQLLogger instanceof SQLLogger) {
422
            $sqlLogger = $this->getOption('sql_logger');
423
424
            if ($sqlLogger instanceof SQLLogger) {
425
                $this->SQLLogger = $sqlLogger;
426
            }
427
        }
428
429
        return $this->SQLLogger;
430
    }
431
432
    /**
433
     * Retrieve custom DQL string functions.
434
     *
435
     * @return array
436
     */
437
    protected function getCustomStringFunctions()
438
    {
439
        $functions = (array) $this->getOption('custom_string_functions');
440
441
        return array_filter(
442
            $functions,
443
            function ($name) {
444
                return is_string($name);
445
            },
446
            ARRAY_FILTER_USE_KEY
447
        );
448
    }
449
450
    /**
451
     * Retrieve custom DQL numeric functions.
452
     *
453
     * @return array
454
     */
455
    protected function getCustomNumericFunctions()
456
    {
457
        $functions = (array) $this->getOption('custom_numeric_functions');
458
459
        return array_filter(
460
            $functions,
461
            function ($name) {
462
                return is_string($name);
463
            },
464
            ARRAY_FILTER_USE_KEY
465
        );
466
    }
467
468
    /**
469
     * Retrieve custom DQL date time functions.
470
     *
471
     * @return array
472
     */
473
    protected function getCustomDateTimeFunctions()
474
    {
475
        $functions = (array) $this->getOption('custom_datetime_functions');
476
477
        return array_filter(
478
            $functions,
479
            function ($name) {
480
                return is_string($name);
481
            },
482
            ARRAY_FILTER_USE_KEY
483
        );
484
    }
485
486
    /**
487
     * Retrieve custom DBAL types.
488
     *
489
     * @return array
490
     */
491
    protected function getCustomTypes()
492
    {
493
        $types = (array) $this->getOption('custom_types');
494
495
        return array_filter(
496
            $types,
497
            function ($name) {
498
                return is_string($name);
499
            },
500
            ARRAY_FILTER_USE_KEY
501
        );
502
    }
503
504
    /**
505
     * Get custom registered filters.
506
     *
507
     * @return array
508
     */
509
    protected function getCustomFilters()
510
    {
511
        $filters = (array) $this->getOption('custom_filters');
512
513
        return array_filter(
514
            $filters,
515
            function ($name) {
516
                return is_string($name);
517
            },
518
            ARRAY_FILTER_USE_KEY
519
        );
520
    }
521
522
    /**
523
     * {@inheritdoc}
524
     *
525
     * @throws \Doctrine\DBAL\DBALException
526
     * @throws \Doctrine\ORM\ORMException
527
     * @throws \InvalidArgumentException
528
     * @throws \RuntimeException
529
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
530
     * @throws \Symfony\Component\Console\Exception\LogicException
531
     * @throws \UnexpectedValueException
532
     *
533
     * @return Command[]
534
     */
535
    public function getConsoleCommands()
536
    {
537
        $commands = [
538
            // DBAL
539
            new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
540
            new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(),
541
542
            // ORM
543
            new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
544
            new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
545
            new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
546
            new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
547
            new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
548
            new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
549
            new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
550
            new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
551
            new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
552
            new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
553
            new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
554
            new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
555
            new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
556
            new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),
557
            new \Doctrine\ORM\Tools\Console\Command\InfoCommand(),
558
        ];
559
560
        if (Version::compare('2.5') <= 0) {
561
            $commands[] = new \Doctrine\ORM\Tools\Console\Command\MappingDescribeCommand();
562
        }
563
564
        $commandPrefix = (string) $this->getName();
565
566
        if ($commandPrefix !== '') {
567
            $commands = array_map(
568
                function (Command $command) use ($commandPrefix) {
569
                    $commandNames = array_map(
570
                        function ($commandName) use ($commandPrefix) {
571
                            return preg_replace('/^(dbal|orm):/', $commandPrefix . ':$1:', $commandName);
572
                        },
573
                        array_merge([$command->getName()], $command->getAliases())
574
                    );
575
576
                    $command->setName(array_shift($commandNames));
577
                    $command->setAliases($commandNames);
578
579
                    return $command;
580
                },
581
                $commands
582
            );
583
        }
584
585
        return $commands;
586
    }
587
588
    /**
589
     * {@inheritdoc}
590
     *
591
     * @throws \Doctrine\DBAL\DBALException
592
     * @throws \Doctrine\ORM\ORMException
593
     * @throws \InvalidArgumentException
594
     * @throws \RuntimeException
595
     * @throws \UnexpectedValueException
596
     */
597
    public function getConsoleHelperSet()
598
    {
599
        /* @var EntityManager $entityManager */
600
        $entityManager = $this->getManager();
601
602
        return new HelperSet([
603
            'db' => new ConnectionHelper($entityManager->getConnection()),
604
            'em' => new EntityManagerHelper($entityManager),
605
        ]);
606
    }
607
}
608