Passed
Push — master ( e83fc5...bed458 )
by Dominik
02:20
created

getOrmEmNameFromParamKeyDefinition()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
ccs 0
cts 10
cp 0
rs 9.4285
cc 2
eloc 6
nc 1
nop 1
crap 6
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 Doctrine\Common\Cache\ApcuCache;
12
use Doctrine\Common\Cache\ArrayCache;
13
use Doctrine\Common\Cache\CacheProvider;
14
use Doctrine\Common\Cache\FilesystemCache;
15
use Doctrine\Common\Cache\MemcacheCache;
16
use Doctrine\Common\Cache\MemcachedCache;
17
use Doctrine\Common\Cache\XcacheCache;
18
use Doctrine\Common\Cache\RedisCache;
19
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
20
use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver;
21
use Doctrine\DBAL\Types\Type;
22
use Doctrine\ORM\Configuration;
23
use Doctrine\ORM\EntityManager;
24
use Doctrine\ORM\EntityRepository;
25
use Doctrine\ORM\Mapping\ClassMetadataFactory;
26
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
27
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
28
use Doctrine\ORM\Mapping\DefaultQuoteStrategy;
29
use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver;
30
use Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver;
31
use Doctrine\ORM\Mapping\Driver\XmlDriver;
32
use Doctrine\ORM\Mapping\Driver\YamlDriver;
33
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
34
use Pimple\Container;
35
use Pimple\ServiceProviderInterface;
36
37
final class DoctrineOrmServiceProvider implements ServiceProviderInterface
38
{
39
    /**
40
     * Register ORM service.
41
     *
42
     * @param Container $container
43
     */
44
    public function register(Container $container)
45
    {
46
        $container['orm.em.default_options'] = $this->getOrmEmDefaultOptions();
47
        $container['orm.ems.options.initializer'] = $this->getOrmEmsOptionsInitializerDefinition($container);
48
        $container['orm.ems'] = $this->getOrmEmsDefinition($container);
49
        $container['orm.ems.config'] = $this->getOrmEmsConfigServiceProvider($container);
50
        $container['orm.cache.configurer'] = $this->getOrmCacheConfigurerDefinition($container);
51
        $container['orm.cache.locator'] = $this->getOrmCacheLocatorDefinition($container);
52
        $container['orm.cache.factory'] = $this->getOrmCacheFactoryDefinition($container);
53
        $container['orm.cache.factory.apcu'] = $this->getOrmCacheFactoryApcuDefinition($container);
54
        $container['orm.cache.factory.array'] = $this->getOrmCacheFactoryArrayDefinition($container);
55
        $container['orm.cache.factory.filesystem'] = $this->getOrmCacheFactoryFilesystemDefinition($container);
56
        $container['orm.cache.factory.memcache'] = $this->getOrmCacheFactoryMemcacheDefinition($container);
57
        $container['orm.cache.factory.memcached'] = $this->getOrmCacheFactoryMemcachedDefinition($container);
58
        $container['orm.cache.factory.redis'] = $this->getOrmCacheFactoryRedisDefinition($container);
59
        $container['orm.cache.factory.xcache'] = $this->getOrmCacheFactoryXCacheDefinition($container);
60
        $container['orm.default_cache'] = ['driver' => 'array'];
61
        $container['orm.proxies_dir'] = sys_get_temp_dir();
62
        $container['orm.proxies_namespace'] = 'DoctrineProxy';
63
        $container['orm.auto_generate_proxies'] = true;
64
        $container['orm.custom.functions.string'] = [];
65
        $container['orm.custom.functions.numeric'] = [];
66
        $container['orm.custom.functions.datetime'] = [];
67
        $container['orm.custom.hydration_modes'] = [];
68
        $container['orm.class_metadata_factory_name'] = ClassMetadataFactory::class;
69
        $container['orm.default_repository_class'] = EntityRepository::class;
70
        $container['orm.entity_listener_resolver'] = $this->getOrmEntityListenerResolverDefinition($container);
71
        $container['orm.repository_factory'] = $this->getOrmRepositoryFactoryDefinition($container);
72
        $container['orm.strategy.naming'] = $this->getOrmNamingStrategyDefinition($container);
73
        $container['orm.strategy.quote'] = $this->getOrmQuoteStrategyDefinition($container);
74
        $container['orm.mapping_driver_chain.locator'] = $this->getOrmMappingDriverChainLocatorDefinition($container);
75
        $container['orm.mapping_driver_chain.factory'] = $this->getOrmMappingDriverChainFactoryDefinition($container);
76
        $container['orm.em'] = $this->getOrmEmDefinition($container);
77
        $container['orm.em.config'] = $this->getOrmEmConfigDefinition($container);
78
    }
79
80
    /**
81
     * @return array
82
     */
83
    private function getOrmEmDefaultOptions(): array
84
    {
85
        return [
86
            'connection' => 'default',
87
            'mappings' => [],
88
            'types' => [],
89
        ];
90
    }
91
92
    /**
93
     * @param Container $container
94
     *
95
     * @return \Closure
96
     */
97
    private function getOrmEmsOptionsInitializerDefinition(Container $container): \Closure
98
    {
99
        return $container->protect(function () use ($container) {
100
            static $initialized = false;
101
102
            if ($initialized) {
103
                return;
104
            }
105
106
            $initialized = true;
107
108
            if (!isset($container['orm.ems.options'])) {
109
                $container['orm.ems.options'] = [
110
                    'default' => isset($container['orm.em.options']) ? $container['orm.em.options'] : [],
111
                ];
112
            }
113
114
            $tmp = $container['orm.ems.options'];
115
            foreach ($tmp as $name => &$options) {
116
                $options = array_replace($container['orm.em.default_options'], $options);
117
118
                if (!isset($container['orm.ems.default'])) {
119
                    $container['orm.ems.default'] = $name;
120
                }
121
            }
122
123
            $container['orm.ems.options'] = $tmp;
124
        });
125
    }
126
127
    /**
128
     * @param Container $container
129
     *
130
     * @return \Closure
131
     */
132
    private function getOrmEmsDefinition(Container $container): \Closure
133
    {
134
        return function () use ($container) {
135
            $container['orm.ems.options.initializer']();
136
137
            $ems = new Container();
138
            foreach ($container['orm.ems.options'] as $name => $options) {
139
                if ($container['orm.ems.default'] === $name) {
140
                    // we use shortcuts here in case the default has been overridden
141
                    $config = $container['orm.em.config'];
142
                } else {
143
                    $config = $container['orm.ems.config'][$name];
144
                }
145
146
                $ems[$name] = function () use ($container, $options, $config) {
147
                    return EntityManager::create(
148
                        $container['dbs'][$options['connection']],
149
                        $config,
150
                        $container['dbs.event_manager'][$options['connection']]
151
                    );
152
                };
153
            }
154
155
            return $ems;
156
        };
157
    }
158
159
    /**
160
     * @param Container $container
161
     *
162
     * @return \Closure
163
     */
164
    private function getOrmEmsConfigServiceProvider(Container $container): \Closure
165
    {
166
        return function () use ($container) {
167
            $container['orm.ems.options.initializer']();
168
169
            $configs = new Container();
170
            foreach ($container['orm.ems.options'] as $name => $options) {
171
                $configs[$name] = $this->getOrmEmConfigByNameAndOptionsDefinition($container, $name, $options);
172
            }
173
174
            return $configs;
175
        };
176
    }
177
178
    /**
179
     * @param Container $container
180
     * @param string    $name
181
     * @param array     $options
182
     *
183
     * @return \Closure
184
     */
185
    private function getOrmEmConfigByNameAndOptionsDefinition(
186
        Container $container,
187
        string $name,
188
        array $options
189
    ): \Closure {
190
        return function () use ($container, $name, $options) {
191
            $config = new Configuration();
192
193
            $container['orm.cache.configurer']($name, $config, $options);
194
195
            $config->setProxyDir($container['orm.proxies_dir']);
196
            $config->setProxyNamespace($container['orm.proxies_namespace']);
197
            $config->setAutoGenerateProxyClasses($container['orm.auto_generate_proxies']);
198
199
            $config->setCustomStringFunctions($container['orm.custom.functions.string']);
200
            $config->setCustomNumericFunctions($container['orm.custom.functions.numeric']);
201
            $config->setCustomDatetimeFunctions($container['orm.custom.functions.datetime']);
202
            $config->setCustomHydrationModes($container['orm.custom.hydration_modes']);
203
204
            $config->setClassMetadataFactoryName($container['orm.class_metadata_factory_name']);
205
            $config->setDefaultRepositoryClassName($container['orm.default_repository_class']);
206
207
            $config->setEntityListenerResolver($container['orm.entity_listener_resolver']);
208
            $config->setRepositoryFactory($container['orm.repository_factory']);
209
210
            $config->setNamingStrategy($container['orm.strategy.naming']);
211
            $config->setQuoteStrategy($container['orm.strategy.quote']);
212
213
            /** @var MappingDriverChain $chain */
214
            $chain = $container['orm.mapping_driver_chain.locator']($name);
215
216
            foreach ((array) $options['mappings'] as $entity) {
217
                if (!is_array($entity)) {
218
                    throw new \InvalidArgumentException(
219
                        "The 'orm.em.options' option 'mappings' should be an array of arrays."
220
                    );
221
                }
222
223
                if (isset($entity['alias'])) {
224
                    $config->addEntityNamespace($entity['alias'], $entity['namespace']);
225
                }
226
227
                switch ($entity['type']) {
228
                    case 'annotation':
229
                        $useSimpleAnnotationReader = $entity['use_simple_annotation_reader'] ?? true;
230
                        $driver = $config->newDefaultAnnotationDriver(
231
                            (array) $entity['path'],
232
                            $useSimpleAnnotationReader
233
                        );
234
                        $chain->addDriver($driver, $entity['namespace']);
235
236
                        break;
237 View Code Duplication
                    case 'yml':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
238
                        $driver = new YamlDriver($entity['path']);
239
                        $chain->addDriver($driver, $entity['namespace']);
240
241
                        break;
242 View Code Duplication
                    case 'simple_yml':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
243
                        $driver = new SimplifiedYamlDriver([$entity['path'] => $entity['namespace']]);
244
                        $chain->addDriver($driver, $entity['namespace']);
245
246
                        break;
247 View Code Duplication
                    case 'xml':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
248
                        $driver = new XmlDriver($entity['path']);
249
                        $chain->addDriver($driver, $entity['namespace']);
250
251
                        break;
252 View Code Duplication
                    case 'simple_xml':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
253
                        $driver = new SimplifiedXmlDriver([$entity['path'] => $entity['namespace']]);
254
                        $chain->addDriver($driver, $entity['namespace']);
255
256
                        break;
257 View Code Duplication
                    case 'php':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
258
                        $driver = new StaticPHPDriver($entity['path']);
259
                        $chain->addDriver($driver, $entity['namespace']);
260
261
                        break;
262
                    default:
263
                        throw new \InvalidArgumentException(
264
                            sprintf('"%s" is not a recognized driver', $entity['type'])
265
                        );
266
                }
267
            }
268
269
            $config->setMetadataDriverImpl($chain);
270
271
            foreach ((array) $options['types'] as $typeName => $typeClass) {
272
                if (Type::hasType($typeName)) {
273
                    Type::overrideType($typeName, $typeClass);
274
                } else {
275
                    Type::addType($typeName, $typeClass);
276
                }
277
            }
278
279
            return $config;
280
        };
281
    }
282
283
    /**
284
     * @param Container $container
285
     *
286
     * @return \Closure
287
     */
288
    private function getOrmCacheConfigurerDefinition(Container $container): \Closure
289
    {
290
        return $container->protect(function ($name, Configuration $config, $options) use ($container) {
291
            $config->setMetadataCacheImpl($container['orm.cache.locator']($name, 'metadata', $options));
292
            $config->setQueryCacheImpl($container['orm.cache.locator']($name, 'query', $options));
293
            $config->setResultCacheImpl($container['orm.cache.locator']($name, 'result', $options));
294
            $config->setHydrationCacheImpl($container['orm.cache.locator']($name, 'hydration', $options));
295
        });
296
    }
297
298
    /**
299
     * @param Container $container
300
     *
301
     * @return \Closure
302
     */
303
    private function getOrmCacheLocatorDefinition(Container $container): \Closure
304
    {
305
        return $container->protect(function ($name, $cacheName, $options) use ($container) {
306
            $cacheNameKey = $cacheName.'_cache';
307
308
            if (!isset($options[$cacheNameKey])) {
309
                $options[$cacheNameKey] = $container['orm.default_cache'];
310
            }
311
312
            if (isset($options[$cacheNameKey]) && !is_array($options[$cacheNameKey])) {
313
                $options[$cacheNameKey] = [
314
                    'driver' => $options[$cacheNameKey],
315
                ];
316
            }
317
318
            if (!isset($options[$cacheNameKey]['driver'])) {
319
                throw new \RuntimeException("No driver specified for '$cacheName'");
320
            }
321
322
            $driver = $options[$cacheNameKey]['driver'];
323
324
            $cacheInstanceKey = 'orm.cache.instances.'.$name.'.'.$cacheName;
325
            if (isset($container[$cacheInstanceKey])) {
326
                return $container[$cacheInstanceKey];
327
            }
328
329
            $cache = $container['orm.cache.factory']($driver, $options[$cacheNameKey]);
330
331
            if (isset($options['cache_namespace']) && $cache instanceof CacheProvider) {
332
                $cache->setNamespace($options['cache_namespace']);
333
            }
334
335
            return $container[$cacheInstanceKey] = $cache;
336
        });
337
    }
338
339
    /**
340
     * @param Container $container
341
     *
342
     * @return \Closure
343
     */
344
    private function getOrmCacheFactoryApcuDefinition(Container $container): \Closure
345
    {
346
        return $container->protect(function () use ($container) {
347
            return new ApcuCache();
348
        });
349
    }
350
351
    /**
352
     * @param Container $container
353
     *
354
     * @return \Closure
355
     */
356
    private function getOrmCacheFactoryArrayDefinition(Container $container): \Closure
357
    {
358
        return $container->protect(function () use ($container) {
359
            return new ArrayCache();
360
        });
361
    }
362
363
    /**
364
     * @param Container $container
365
     *
366
     * @return \Closure
367
     */
368
    private function getOrmCacheFactoryFilesystemDefinition(Container $container): \Closure
369
    {
370
        return $container->protect(function ($cacheOptions) {
371
            if (empty($cacheOptions['path'])) {
372
                throw new \RuntimeException('FilesystemCache path not defined');
373
            }
374
375
            $cacheOptions += [
376
                'extension' => FilesystemCache::EXTENSION,
377
                'umask' => 0002,
378
            ];
379
380
            return new FilesystemCache($cacheOptions['path'], $cacheOptions['extension'], $cacheOptions['umask']);
381
        });
382
    }
383
384
    /**
385
     * @param Container $container
386
     *
387
     * @return \Closure
388
     */
389
    private function getOrmCacheFactoryMemcacheDefinition(Container $container): \Closure
390
    {
391
        return $container->protect(function ($cacheOptions) use ($container) {
392
            if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
393
                throw new \RuntimeException('Host and port options need to be specified for memcache cache');
394
            }
395
396
            $memcache = new \Memcache();
397
            $memcache->connect($cacheOptions['host'], $cacheOptions['port']);
398
399
            $cache = new MemcacheCache();
400
            $cache->setMemcache($memcache);
401
402
            return $cache;
403
        });
404
    }
405
406
    /**
407
     * @param Container $container
408
     *
409
     * @return \Closure
410
     */
411
    private function getOrmCacheFactoryMemcachedDefinition(Container $container): \Closure
412
    {
413
        return $container->protect(function ($cacheOptions) use ($container) {
414
            if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
415
                throw new \RuntimeException('Host and port options need to be specified for memcached cache');
416
            }
417
418
            $memcached = new \Memcached();
419
            $memcached->addServer($cacheOptions['host'], $cacheOptions['port']);
420
421
            $cache = new MemcachedCache();
422
            $cache->setMemcached($memcached);
423
424
            return $cache;
425
        });
426
    }
427
428
    /**
429
     * @param Container $container
430
     *
431
     * @return \Closure
432
     */
433
    private function getOrmCacheFactoryRedisDefinition(Container $container): \Closure
434
    {
435
        return $container->protect(function ($cacheOptions) use ($container) {
436
            if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
437
                throw new \RuntimeException('Host and port options need to be specified for redis cache');
438
            }
439
440
            $redis = new \Redis();
441
            $redis->connect($cacheOptions['host'], $cacheOptions['port']);
442
443
            if (isset($cacheOptions['password'])) {
444
                $redis->auth($cacheOptions['password']);
445
            }
446
447
            $cache = new RedisCache();
448
            $cache->setRedis($redis);
449
450
            return $cache;
451
        });
452
    }
453
454
    /**
455
     * @param Container $container
456
     *
457
     * @return \Closure
458
     */
459
    private function getOrmCacheFactoryXCacheDefinition(Container $container): \Closure
460
    {
461
        return $container->protect(function () use ($container) {
462
            return new XcacheCache();
463
        });
464
    }
465
466
    /**
467
     * @param Container $container
468
     *
469
     * @return \Closure
470
     */
471
    private function getOrmCacheFactoryDefinition(Container $container): \Closure
472
    {
473
        return $container->protect(function ($driver, $cacheOptions) use ($container) {
474
            $cacheFactoryKey = 'orm.cache.factory.'.$driver;
475
            if (!isset($container[$cacheFactoryKey])) {
476
                throw new \RuntimeException(
477
                    sprintf('Factory "%s" for cache type "%s" not defined', $cacheFactoryKey, $driver)
478
                );
479
            }
480
481
            return $container[$cacheFactoryKey]($cacheOptions);
482
        });
483
    }
484
485
    /**
486
     * @param Container $container
487
     *
488
     * @return \Closure
489
     */
490
    private function getOrmMappingDriverChainLocatorDefinition(Container $container): \Closure
491
    {
492
        return $container->protect(function ($name = null) use ($container) {
493
            $container['orm.ems.options.initializer']();
494
495
            if (null === $name) {
496
                $name = $container['orm.ems.default'];
497
            }
498
499
            $cacheInstanceKey = 'orm.mapping_driver_chain.instances.'.$name;
500
            if (isset($container[$cacheInstanceKey])) {
501
                return $container[$cacheInstanceKey];
502
            }
503
504
            return $container[$cacheInstanceKey] = $container['orm.mapping_driver_chain.factory']($name);
505
        });
506
    }
507
508
    /**
509
     * @param Container $container
510
     *
511
     * @return \Closure
512
     */
513
    private function getOrmMappingDriverChainFactoryDefinition(Container $container): \Closure
514
    {
515
        return $container->protect(function () use ($container) {
516
            return new MappingDriverChain();
517
        });
518
    }
519
520
    /**
521
     * @param Container $container
522
     *
523
     * @return \Closure
524
     */
525
    private function getOrmNamingStrategyDefinition(Container $container): \Closure
526
    {
527
        return function () use ($container) {
528
            return new DefaultNamingStrategy();
529
        };
530
    }
531
532
    /**
533
     * @param Container $container
534
     *
535
     * @return \Closure
536
     */
537
    private function getOrmQuoteStrategyDefinition(Container $container): \Closure
538
    {
539
        return function () use ($container) {
540
            return new DefaultQuoteStrategy();
541
        };
542
    }
543
544
    /**
545
     * @param Container $container
546
     *
547
     * @return \Closure
548
     */
549
    private function getOrmEntityListenerResolverDefinition(Container $container): \Closure
550
    {
551
        return function () use ($container) {
552
            return new DefaultEntityListenerResolver();
553
        };
554
    }
555
556
    /**
557
     * @param Container $container
558
     *
559
     * @return \Closure
560
     */
561
    private function getOrmRepositoryFactoryDefinition(Container $container): \Closure
562
    {
563
        return function () use ($container) {
564
            return new DefaultRepositoryFactory();
565
        };
566
    }
567
568
    /**
569
     * @param Container $container
570
     *
571
     * @return \Closure
572
     */
573
    private function getOrmEmDefinition(Container $container): \Closure
574
    {
575
        return function () use ($container) {
576
            $ems = $container['orm.ems'];
577
578
            return $ems[$container['orm.ems.default']];
579
        };
580
    }
581
582
    /**
583
     * @param Container $container
584
     *
585
     * @return \Closure
586
     */
587
    private function getOrmEmConfigDefinition(Container $container): \Closure
588
    {
589
        return function () use ($container) {
590
            $configs = $container['orm.ems.config'];
591
592
            return $configs[$container['orm.ems.default']];
593
        };
594
    }
595
}
596