Passed
Push — master ( de4fd9...38d8bf )
by Dominik
03:06
created

getOrmEmConfigByNameAndOptionsDefinition()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 48
ccs 27
cts 27
cp 1
rs 9.1344
c 0
b 0
f 0
cc 4
nc 1
nop 3
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * (c) Beau Simensen <[email protected]> (https://github.com/dflydev/dflydev-doctrine-orm-service-provider)
7
 */
8
9
namespace Chubbyphp\ServiceProvider;
10
11
use Chubbyphp\ServiceProvider\Registry\DoctrineOrmManagerRegistry;
12
use Doctrine\Common\Cache\ApcuCache;
13
use Doctrine\Common\Cache\ArrayCache;
14
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
15
use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver;
16
use Doctrine\DBAL\Types\Type;
17
use Doctrine\ORM\Cache\CacheConfiguration;
18
use Doctrine\ORM\Cache\DefaultCacheFactory;
19
use Doctrine\ORM\Cache\RegionsConfiguration;
20
use Doctrine\ORM\Configuration;
21
use Doctrine\ORM\EntityManager;
22
use Doctrine\ORM\EntityRepository;
23
use Doctrine\ORM\Mapping\ClassMetadataFactory;
24
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
25
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
26
use Doctrine\ORM\Mapping\DefaultQuoteStrategy;
27
use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver;
28
use Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver;
29
use Doctrine\ORM\Mapping\Driver\XmlDriver;
30
use Doctrine\ORM\Mapping\Driver\YamlDriver;
31
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
32
use Pimple\Container;
33
use Pimple\ServiceProviderInterface;
34
35
final class DoctrineOrmServiceProvider implements ServiceProviderInterface
36
{
37
    /**
38
     * Register ORM service.
39
     *
40
     * @param Container $container
41
     */
42 5
    public function register(Container $container)
43
    {
44 5
        $container['doctrine.orm.em.default_options'] = $this->getOrmEmDefaultOptions();
45 5
        $container['doctrine.orm.ems.options.initializer'] = $this->getOrmEmsOptionsInitializerDefinition($container);
46 5
        $container['doctrine.orm.ems'] = $this->getOrmEmsDefinition($container);
47 5
        $container['doctrine.orm.ems.config'] = $this->getOrmEmsConfigServiceProvider($container);
48 5
        $container['doctrine.orm.proxies_dir'] = sys_get_temp_dir();
49 5
        $container['doctrine.orm.auto_generate_proxies'] = true;
50 5
        $container['doctrine.orm.proxies_namespace'] = 'DoctrineProxy';
51 5
        $container['doctrine.orm.mapping_driver_chain'] = $this->getOrmMappingDriverChainDefinition($container);
52 5
        $container['doctrine.orm.mapping_driver_chain.factory'] = $this->getOrmMappingDriverChainFactoryDefinition($container);
53 5
        $container['doctrine.orm.mapping_driver.factory.annotation'] = $this->getOrmMappingDriverFactoryAnnotation($container);
54 5
        $container['doctrine.orm.mapping_driver.factory.yml'] = $this->getOrmMappingDriverFactoryYaml($container);
55 5
        $container['doctrine.orm.mapping_driver.factory.simple_yml'] = $this->getOrmMappingDriverFactorySimpleYaml($container);
56 5
        $container['doctrine.orm.mapping_driver.factory.xml'] = $this->getOrmMappingDriverFactoryXml($container);
57 5
        $container['doctrine.orm.mapping_driver.factory.simple_xml'] = $this->getOrmMappingDriverFactorySimpleXml($container);
58 5
        $container['doctrine.orm.mapping_driver.factory.php'] = $this->getOrmMappingDriverFactoryPhp($container);
59 5
        $container['doctrine.orm.custom.functions.string'] = [];
60 5
        $container['doctrine.orm.custom.functions.numeric'] = [];
61 5
        $container['doctrine.orm.custom.functions.datetime'] = [];
62 5
        $container['doctrine.orm.custom.hydration_modes'] = [];
63 5
        $container['doctrine.orm.class_metadata_factory_name'] = ClassMetadataFactory::class;
64 5
        $container['doctrine.orm.default_repository_class'] = EntityRepository::class;
65 5
        $container['doctrine.orm.strategy.naming'] = $this->getOrmNamingStrategyDefinition($container);
66 5
        $container['doctrine.orm.strategy.quote'] = $this->getOrmQuoteStrategyDefinition($container);
67 5
        $container['doctrine.orm.entity_listener_resolver'] = $this->getOrmEntityListenerResolverDefinition($container);
68 5
        $container['doctrine.orm.repository_factory'] = $this->getOrmRepositoryFactoryDefinition($container);
69 5
        $container['doctrine.orm.default.query_hints'] = [];
70 5
        $container['doctrine.orm.em'] = $this->getOrmEmDefinition($container);
71 5
        $container['doctrine.orm.em.config'] = $this->getOrmEmConfigDefinition($container);
72 5
        $container['doctrine.orm.manager_registry'] = $this->getOrmManagerRegistryDefintion($container);
73 5
        $container['doctrine.orm.em.cache_factory.array'] = $this->getOrmArrayCacheFactoryDefinition($container);
74 5
        $container['doctrine.orm.em.cache_factory.apcu'] = $this->getOrmApcuCacheFactoryDefinition($container);
75 5
    }
76
77
    /**
78
     * @return array
79
     */
80 5
    private function getOrmEmDefaultOptions(): array
81
    {
82
        return [
83 5
            'connection' => 'default',
84
            'query_cache' => null,
85
            'metadata_cache' => null,
86
            'result_cache' => null,
87
            'hydration_cache' => null,
88
            'second_level_cache' => null,
89
            'mappings' => [],
90
            'types' => [],
91
        ];
92
    }
93
94
    /**
95
     * @param Container $container
96
     *
97
     * @return callable
98
     */
99 View Code Duplication
    private function getOrmEmsOptionsInitializerDefinition(Container $container): callable
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
100
    {
101 5
        return $container->protect(function () use ($container) {
102 5
            static $initialized = false;
103
104 5
            if ($initialized) {
105 5
                return;
106
            }
107
108 5
            $initialized = true;
109
110 5
            if (!isset($container['doctrine.orm.ems.options'])) {
111 4
                $container['doctrine.orm.ems.options'] = [
112 4
                    'default' => isset($container['doctrine.orm.em.options']) ? $container['doctrine.orm.em.options'] : [],
113
                ];
114
            }
115
116 5
            $tmp = $container['doctrine.orm.ems.options'];
117 5
            foreach ($tmp as $name => &$options) {
118 5
                $options = array_replace($container['doctrine.orm.em.default_options'], $options);
119
120 5
                if (!isset($container['doctrine.orm.ems.default'])) {
121 5
                    $container['doctrine.orm.ems.default'] = $name;
122
                }
123
            }
124
125 5
            $container['doctrine.orm.ems.options'] = $tmp;
126 5
        });
127
    }
128
129
    /**
130
     * @param Container $container
131
     *
132
     * @return callable
133
     */
134
    private function getOrmEmsDefinition(Container $container): callable
135
    {
136 5
        return function () use ($container) {
137 5
            $container['doctrine.orm.ems.options.initializer']();
138
139 5
            $ems = new Container();
140 5
            foreach ($container['doctrine.orm.ems.options'] as $name => $options) {
141 5
                if ($container['doctrine.orm.ems.default'] === $name) {
142
                    // we use shortcuts here in case the default has been overridden
143 5
                    $config = $container['doctrine.orm.em.config'];
144
                } else {
145 1
                    $config = $container['doctrine.orm.ems.config'][$name];
146
                }
147
148 3
                $ems[$name] = function () use ($container, $options, $config) {
149 3
                    return EntityManager::create(
150 3
                        $container['doctrine.dbal.dbs'][$options['connection']],
151 3
                        $config,
152 3
                        $container['doctrine.dbal.dbs.event_manager'][$options['connection']]
153
                    );
154 3
                };
155
            }
156
157 3
            return $ems;
158 5
        };
159
    }
160
161
    /**
162
     * @param Container $container
163
     *
164
     * @return callable
165
     */
166
    private function getOrmEmsConfigServiceProvider(Container $container): callable
167
    {
168 5
        return function () use ($container) {
169 5
            $container['doctrine.orm.ems.options.initializer']();
170
171 5
            $configs = new Container();
172 5
            foreach ($container['doctrine.orm.ems.options'] as $name => $options) {
173 5
                $configs[$name] = $this->getOrmEmConfigByNameAndOptionsDefinition($container, $name, $options);
174
            }
175
176 5
            return $configs;
177 5
        };
178
    }
179
180
    /**
181
     * @param Container $container
182
     * @param string    $name
183
     * @param array     $options
184
     *
185
     * @return callable
186
     */
187
    private function getOrmEmConfigByNameAndOptionsDefinition(
188
        Container $container,
189
        string $name,
190
        array $options
191
    ): callable {
192 5
        return function () use ($container, $name, $options) {
193 5
            $config = new Configuration();
194
195 5
            $config->setProxyDir($container['doctrine.orm.proxies_dir']);
196 5
            $config->setAutoGenerateProxyClasses($container['doctrine.orm.auto_generate_proxies']);
197 5
            $config->setProxyNamespace($container['doctrine.orm.proxies_namespace']);
198 5
            $config->setMetadataDriverImpl(
199 5
                $container['doctrine.orm.mapping_driver_chain']($name, $config, (array) $options['mappings'])
200
            );
201
202 3
            foreach (['query', 'hydration', 'metadata', 'result'] as $cacheType) {
203 3
                $this->assignCache($container, $config, $options, $cacheType);
204
            }
205
206 3
            foreach ((array) $options['types'] as $typeName => $typeClass) {
207 1
                if (Type::hasType($typeName)) {
208 1
                    Type::overrideType($typeName, $typeClass);
209
                } else {
210 1
                    Type::addType($typeName, $typeClass);
211
                }
212
            }
213
214 3
            $config->setCustomStringFunctions($container['doctrine.orm.custom.functions.string']);
215 3
            $config->setCustomNumericFunctions($container['doctrine.orm.custom.functions.numeric']);
216 3
            $config->setCustomDatetimeFunctions($container['doctrine.orm.custom.functions.datetime']);
217 3
            $config->setCustomHydrationModes($container['doctrine.orm.custom.hydration_modes']);
218
219 3
            $config->setClassMetadataFactoryName($container['doctrine.orm.class_metadata_factory_name']);
220 3
            $config->setDefaultRepositoryClassName($container['doctrine.orm.default_repository_class']);
221
222 3
            $config->setNamingStrategy($container['doctrine.orm.strategy.naming']);
223 3
            $config->setQuoteStrategy($container['doctrine.orm.strategy.quote']);
224
225 3
            $config->setEntityListenerResolver($container['doctrine.orm.entity_listener_resolver']);
226 3
            $config->setRepositoryFactory($container['doctrine.orm.repository_factory']);
227
228 3
            $this->assignSecondLevelCache($container, $config, $options);
229
230 3
            $config->setDefaultQueryHints($container['doctrine.orm.default.query_hints']);
231
232 3
            return $config;
233 5
        };
234
    }
235
236
    /**
237
     * @param Container $container
238
     * @param Configuration $config
239
     * @param array $options
240
     * @param string $cacheType
241
     */
242 3
    private function assignCache(Container $container, Configuration $config, array $options, string $cacheType)
243
    {
244 3
        $optionsKey = sprintf('%s_cache', $cacheType);
245
246 3
        if (null === $options[$optionsKey]) {
247 2
            return;
248
        }
249
250 1
        $cacheFactoryKey = sprintf('doctrine.orm.em.cache_factory.%s', $options[$optionsKey]);
251 1
        $setMethod = sprintf('set%sCacheImpl', ucfirst($cacheType));
252
253 1
        $config->$setMethod($container[$cacheFactoryKey]);
254 1
    }
255
256
    /**
257
     * @param Container $container
258
     * @param Configuration $config
259
     * @param array $options
260
     */
261 3
    private function assignSecondLevelCache(Container $container, Configuration $config, array $options)
262
    {
263 3
        if (null === $options['second_level_cache']) {
264 2
            return;
265
        }
266
267 1
        $cacheFactoryKey = sprintf('doctrine.orm.em.cache_factory.%s', $options['second_level_cache']);
268 1
        $secondLevelCacheAdapter = $container[$cacheFactoryKey];
269
270 1
        $regionsCacheConfiguration = new RegionsConfiguration();
271 1
        $factory = new DefaultCacheFactory($regionsCacheConfiguration, $secondLevelCacheAdapter);
272
273 1
        $cacheConfiguration = new CacheConfiguration();
274 1
        $cacheConfiguration->setCacheFactory($factory);
275 1
        $cacheConfiguration->setRegionsConfiguration($regionsCacheConfiguration);
276
277 1
        $config->setSecondLevelCacheEnabled(true);
278 1
        $config->setSecondLevelCacheConfiguration($cacheConfiguration);
279 1
    }
280
281
    /**
282
     * @param Container $container
283
     *
284
     * @return callable
285
     */
286
    private function getOrmMappingDriverChainDefinition(Container $container): callable
287
    {
288 5
        return $container->protect(function (string $name, Configuration $config, array $mappings) use ($container) {
289 5
            $container['doctrine.orm.ems.options.initializer']();
290
291
            /** @var MappingDriverChain $chain */
292 5
            $chain = $container['doctrine.orm.mapping_driver_chain.factory']();
293 5
            foreach ($mappings as $mapping) {
294 4
                if (!is_array($mapping)) {
295 1
                    throw new \InvalidArgumentException(
296 1
                        'The "doctrine.orm.em.options" option "mappings" should be an array of arrays.'
297
                    );
298
                }
299
300 3
                if (isset($mapping['alias'])) {
301 2
                    $config->addEntityNamespace($mapping['alias'], $mapping['namespace']);
302
                }
303
304 3
                $factoryKey = sprintf('doctrine.orm.mapping_driver.factory.%s', $mapping['type']);
305 3
                if (!isset($container[$factoryKey])) {
306 1
                    throw new \InvalidArgumentException(
307 1
                        sprintf('There is no driver factory for type "%s"', $mapping['type'])
308
                    );
309
                }
310
311 2
                $chain->addDriver($container[$factoryKey]($mapping, $config), $mapping['namespace']);
312
            }
313
314 3
            return $container['doctrine.orm.mapping_driver_chain.instances.'.$name] = $chain;
315 5
        });
316
    }
317
318
    /**
319
     * @param Container $container
320
     *
321
     * @return callable
322
     */
323
    private function getOrmMappingDriverChainFactoryDefinition(Container $container): callable
324
    {
325 5
        return $container->protect(function () use ($container) {
326 5
            return new MappingDriverChain();
327 5
        });
328
    }
329
330
    /**
331
     * @param Container $container
332
     *
333
     * @return callable
334
     */
335
    private function getOrmMappingDriverFactoryAnnotation(Container $container): callable
336
    {
337 5
        return $container->protect(function (array $mapping, Configuration $config) {
338 2
            $useSimpleAnnotationReader = $mapping['use_simple_annotation_reader'] ?? true;
339
340 2
            return $config->newDefaultAnnotationDriver(
341 2
                (array) $mapping['path'],
342 2
                $useSimpleAnnotationReader
343
            );
344 5
        });
345
    }
346
347
    /**
348
     * @param Container $container
349
     *
350
     * @return callable
351
     */
352
    private function getOrmMappingDriverFactoryYaml(Container $container): callable
353
    {
354 5
        return $container->protect(function (array $mapping, Configuration $config) {
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
355 2
            return new YamlDriver($mapping['path'], $mapping['extension'] ?? YamlDriver::DEFAULT_FILE_EXTENSION);
356 5
        });
357
    }
358
359
    /**
360
     * @param Container $container
361
     *
362
     * @return callable
363
     */
364 View Code Duplication
    private function getOrmMappingDriverFactorySimpleYaml(Container $container): callable
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
365
    {
366 5
        return $container->protect(function (array $mapping, Configuration $config) {
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
367 2
            return new SimplifiedYamlDriver(
368 2
                [$mapping['path'] => $mapping['namespace']],
369 2
                $mapping['extension'] ?? SimplifiedYamlDriver::DEFAULT_FILE_EXTENSION
370
            );
371 5
        });
372
    }
373
374
    /**
375
     * @param Container $container
376
     *
377
     * @return callable
378
     */
379
    private function getOrmMappingDriverFactoryXml(Container $container): callable
380
    {
381 5
        return $container->protect(function (array $mapping, Configuration $config) {
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
382 2
            return new XmlDriver($mapping['path'], $mapping['extension'] ?? XmlDriver::DEFAULT_FILE_EXTENSION);
383 5
        });
384
    }
385
386
    /**
387
     * @param Container $container
388
     *
389
     * @return callable
390
     */
391 View Code Duplication
    private function getOrmMappingDriverFactorySimpleXml(Container $container): callable
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
392
    {
393 5
        return $container->protect(function (array $mapping, Configuration $config) {
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
394 2
            return new SimplifiedXmlDriver(
395 2
                [$mapping['path'] => $mapping['namespace']],
396 2
                $mapping['extension'] ?? SimplifiedXmlDriver::DEFAULT_FILE_EXTENSION
397
            );
398 5
        });
399
    }
400
401
    /**
402
     * @param Container $container
403
     *
404
     * @return callable
405
     */
406
    private function getOrmMappingDriverFactoryPhp(Container $container): callable
407
    {
408 5
        return $container->protect(function (array $mapping, Configuration $config) {
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
409 2
            return new StaticPHPDriver($mapping['path']);
410 5
        });
411
    }
412
413
    /**
414
     * @param Container $container
415
     *
416
     * @return callable
417
     */
418
    private function getOrmNamingStrategyDefinition(Container $container): callable
419
    {
420 5
        return function () use ($container) {
421 2
            return new DefaultNamingStrategy();
422 5
        };
423
    }
424
425
    /**
426
     * @param Container $container
427
     *
428
     * @return callable
429
     */
430
    private function getOrmQuoteStrategyDefinition(Container $container): callable
431
    {
432 5
        return function () use ($container) {
433 2
            return new DefaultQuoteStrategy();
434 5
        };
435
    }
436
437
    /**
438
     * @param Container $container
439
     *
440
     * @return callable
441
     */
442
    private function getOrmEntityListenerResolverDefinition(Container $container): callable
443
    {
444 5
        return function () use ($container) {
445 2
            return new DefaultEntityListenerResolver();
446 5
        };
447
    }
448
449
    /**
450
     * @param Container $container
451
     *
452
     * @return callable
453
     */
454
    private function getOrmRepositoryFactoryDefinition(Container $container): callable
455
    {
456 5
        return function () use ($container) {
457 2
            return new DefaultRepositoryFactory();
458 5
        };
459
    }
460
461
    /**
462
     * @param Container $container
463
     *
464
     * @return callable
465
     */
466
    private function getOrmEmDefinition(Container $container): callable
467
    {
468 5
        return function () use ($container) {
469 4
            $ems = $container['doctrine.orm.ems'];
470
471 2
            return $ems[$container['doctrine.orm.ems.default']];
472 5
        };
473
    }
474
475
    /**
476
     * @param Container $container
477
     *
478
     * @return callable
479
     */
480
    private function getOrmEmConfigDefinition(Container $container): callable
481
    {
482 5
        return function () use ($container) {
483 5
            $configs = $container['doctrine.orm.ems.config'];
484
485 5
            return $configs[$container['doctrine.orm.ems.default']];
486 5
        };
487
    }
488
489
    /**
490
     * @param Container $container
491
     *
492
     * @return callable
493
     */
494
    private function getOrmManagerRegistryDefintion(Container $container): callable
0 ignored issues
show
Unused Code introduced by
The parameter $container is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
495
    {
496 5
        return function ($container) {
497 1
            return new DoctrineOrmManagerRegistry($container);
498 5
        };
499
    }
500
501
    /**
502
     * @param Container $container
503
     *
504
     * @return callable
505
     */
506
    private function getOrmArrayCacheFactoryDefinition(Container $container): callable
507
    {
508 5
        return $container->factory(function () use ($container) {
509 1
            return new ArrayCache();
510 5
        });
511
    }
512
513
    /**
514
     * @param Container $container
515
     *
516
     * @return callable
517
     */
518
    private function getOrmApcuCacheFactoryDefinition(Container $container): callable
519
    {
520 5
        return $container->factory(function () use ($container) {
521 1
            return new ApcuCache();
522 5
        });
523
    }
524
}
525