Test Failed
Pull Request — master (#8)
by Vincent
03:04
created

PrimeExtension::createConfiguration()   B

Complexity

Conditions 10
Paths 96

Size

Total Lines 41
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 10.0107

Importance

Changes 0
Metric Value
cc 10
eloc 24
c 0
b 0
f 0
nc 96
nop 3
dl 0
loc 41
ccs 20
cts 21
cp 0.9524
crap 10.0107
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Bdf\PrimeBundle\DependencyInjection;
4
5
use Bdf\Prime\Cache\DoctrineCacheAdapter;
6
use Bdf\Prime\Configuration as PrimeConfiguration;
7
use Bdf\Prime\Connection\ConnectionRegistry;
8
use Bdf\Prime\Connection\Factory\ConnectionFactory;
9
use Bdf\Prime\Connection\Factory\MasterSlaveConnectionFactory;
10
use Bdf\Prime\Connection\Factory\ShardingConnectionFactory;
11
use Bdf\Prime\Mapper\MapperFactory;
12
use Bdf\Prime\MongoDB\Collection\MongoCollectionLocator;
0 ignored issues
show
Bug introduced by
The type Bdf\Prime\MongoDB\Collec...\MongoCollectionLocator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use Bdf\Prime\MongoDB\Document\DocumentMapperInterface;
0 ignored issues
show
Bug introduced by
The type Bdf\Prime\MongoDB\Document\DocumentMapperInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use Bdf\Prime\MongoDB\Schema\CollectionStructureUpgraderResolver;
0 ignored issues
show
Bug introduced by
The type Bdf\Prime\MongoDB\Schema...ructureUpgraderResolver was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Bdf\Prime\Schema\RepositoryUpgraderResolver;
16
use Bdf\Prime\Schema\StructureUpgraderResolverAggregate;
17
use Bdf\Prime\Schema\StructureUpgraderResolverInterface;
18
use Bdf\Prime\ServiceLocator;
19
use Bdf\Prime\Shell\PrimeShellCommand;
0 ignored issues
show
Bug introduced by
The type Bdf\Prime\Shell\PrimeShellCommand was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use Bdf\Prime\Types\TypesRegistryInterface;
21
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
22
use Symfony\Component\Cache\Psr16Cache;
23
use Symfony\Component\Config\FileLocator;
24
use Symfony\Component\Config\Loader\FileLoader;
25
use Symfony\Component\DependencyInjection\ChildDefinition;
26
use Symfony\Component\DependencyInjection\ContainerBuilder;
27
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
28
use Symfony\Component\DependencyInjection\Extension\Extension;
29
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
30
use Symfony\Component\DependencyInjection\Reference;
31
32
/**
33
 * PrimeExtension.
34
 */
35
class PrimeExtension extends Extension
36
{
37
    /**
38
     * {@inheritDoc}
39
     */
40 6
    public function load(array $configs, ContainerBuilder $container)
41
    {
42 6
        $configuration = $this->getConfiguration($configs, $container);
43 6
        $config = $this->processConfiguration($configuration, $configs);
44
45 6
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
46 6
        $loader->load('prime.yaml');
47 6
        $loader->load('collector.yaml');
48
49 6
        $this->configureConnection($config, $container);
50 6
        $this->configureMapperCache($config, $container);
51 6
        $this->configureSerializer($config, $container);
52
53 6
        if (interface_exists(StructureUpgraderResolverInterface::class)) {
54 6
            $this->configureUpgrader($config, $container);
55
        }
56
57 6
        if (class_exists(MongoCollectionLocator::class)) {
58
            $this->configureMongo($loader, $container, $config);
59
        }
60
61 6
        if (class_exists(PrimeShellCommand::class)) {
62
            $loader->load('prime_shell.yaml');
63
        }
64
65 6
        $container->setParameter('prime.default_connection', $config['default_connection']);
66 6
        $container->setParameter('prime.migration.connection', $config['migration']['connection']);
67 6
        $container->setParameter('prime.migration.table', $config['migration']['table']);
68 6
        $container->setParameter('prime.migration.path', $config['migration']['path']);
69 6
        $container->setParameter('prime.hydrators', $config['hydrators']);
70 6
        $container->setParameter('prime.locatorizable', $config['activerecord']);
71
    }
72
73 6
    public function configureConnection(array $config, ContainerBuilder $container)
74
    {
75 6
        foreach ($config['connections'] as $name => &$options) {
76 6
            $options = $this->cleanConnectionOptions($options);
77
78
            // Overwrite global config by the connection config parameters and create the configuration reference.
79 6
            $this->createConfiguration($name, $this->mergeConfiguration($config, $options), $container);
80
81 6
            if (!$container->hasDefinition(MasterSlaveConnectionFactory::class) && $this->hasConnectionOption('read', $options)) {
82 6
                $container->register(MasterSlaveConnectionFactory::class, MasterSlaveConnectionFactory::class)
83 6
                    ->addTag('bdf_prime.connection_factory', ['priority' => -255])
84 6
                    ->addArgument(new Reference(ConnectionFactory::class));
85
            }
86
87 6
            if (!$container->hasDefinition(ShardingConnectionFactory::class) && $this->hasConnectionOption('shards', $options)) {
88 6
                $container->register(ShardingConnectionFactory::class, ShardingConnectionFactory::class)
89 6
                    ->addTag('bdf_prime.connection_factory', ['priority' => -256])
90 6
                    ->addArgument(new Reference(ConnectionFactory::class));
91
            }
92
        }
93
94 6
        $registry = $container->getDefinition(ConnectionRegistry::class);
95 6
        $registry->replaceArgument(0, $config['connections']);
96
    }
97
98 6
    private function hasConnectionOption(string $option, array $options): bool
99
    {
100 6
        if (isset($options[$option])) {
101 1
            return true;
102
        }
103
104 6
        if (!isset($options['url'])) {
105
            return false;
106
        }
107
108
        // The option could be in the url. Adding the factory by default.
109 6
        return true;
110
    }
111
112 6
    public function configureSerializer(array $config, ContainerBuilder $container)
113
    {
114 6
        if (!isset($config['serializer'])) {
115 6
            return;
116
        }
117
118
        $prime = $container->findDefinition('prime');
119
        $prime->addMethodCall('setSerializer', [new Reference($config['serializer'])]);
120
    }
121
122 6
    public function configureMapperCache(array $config, ContainerBuilder $container)
123
    {
124 6
        $definition = $container->getDefinition(MapperFactory::class);
125
126 6
        if (isset($config['cache']['query'])) {
127 2
            $ref = $this->createResultCacheReference('prime.cache.query', $config['cache']['query'], $container);
128
129 2
            if (null !== $ref) {
130 2
                $definition->replaceArgument(2, $ref);
131
            }
132
        }
133
134 6
        if (isset($config['cache']['metadata'])) {
135
            $ref = $this->createCacheReference('prime.cache.metadata', $config['cache']['metadata'], $container);
136
137
            if (null !== $ref) {
138
                $definition->replaceArgument(1, $ref);
139
            }
140
        }
141
    }
142
143
    /**
144
     * @throws \Exception
145
     */
146
    public function configureMongo(FileLoader $loader, ContainerBuilder $container, array $config): void
147
    {
148
        $loader->load('prime_mongo.yaml');
149
150
        $container->registerForAutoconfiguration(DocumentMapperInterface::class)
151
            ->setPublic(true)
152
            ->setShared(false)
153
            ->setAutowired(true);
154
155
        if (isset($config['cache']['metadata'])) {
156
            $definition = $container->findDefinition('prime_mongodb_serializer');
157
            $ref = $this->createCacheReference('prime.cache.metadata', $config['cache']['metadata'], $container);
158
159
            if (null !== $ref) {
160
                $definition->replaceArgument(0, $ref);
161
            }
162
        }
163
164
        $container->findDefinition(StructureUpgraderResolverAggregate::class)
165
            ->addMethodCall('register', [new Reference(CollectionStructureUpgraderResolver::class)])
166
        ;
167
    }
168
169 6
    private function configureUpgrader(array $config, ContainerBuilder $container)
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed. ( Ignorable by Annotation )

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

169
    private function configureUpgrader(/** @scrutinizer ignore-unused */ array $config, ContainerBuilder $container)

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

Loading history...
170
    {
171 6
        $container->register(RepositoryUpgraderResolver::class)
172 6
            ->addArgument(new Reference(ServiceLocator::class))
173
        ;
174
175 6
        $container->register(StructureUpgraderResolverAggregate::class)
176 6
            ->setPublic(true)
177 6
            ->addMethodCall('register', [new Reference(RepositoryUpgraderResolver::class)])
178
        ;
179
180 6
        $container->setAlias(StructureUpgraderResolverInterface::class, StructureUpgraderResolverAggregate::class)
181 6
            ->setPublic(true)
182
        ;
183
184 6
        $container->findDefinition('prime.upgrade_command')
185 6
            ->replaceArgument(0, new Reference(StructureUpgraderResolverInterface::class))
186
        ;
187
    }
188
189 6
    public function mergeConfiguration(array $globalConfig, array $config): array
190
    {
191
        return [
192 6
            'types' => array_merge($globalConfig['types'], $config['types']),
193 6
            'auto_commit' => $config['auto_commit'] ?? $globalConfig['auto_commit'],
194 6
            'logging' => $config['logging'] ?? $globalConfig['logging'],
195 6
            'profiling' => $config['profiling'] ?? $globalConfig['profiling'],
196
            'platformTypes' => $config['platformTypes'] ?? [],
197
        ];
198
    }
199
200
    /**
201
     * Create and declare the configuration definition of the connection.
202 6
     */
203
    public function createConfiguration(string $name, array $config, ContainerBuilder $container): void
204 6
    {
205
        $namespace = "prime.{$name}_connection";
206 6
207 6
        $configuration = $container->setDefinition("$namespace.configuration", new ChildDefinition(PrimeConfiguration::class));
208 6
        $configuration->setPublic(true);
209
        $configuration->addMethodCall('setTypes', [new Reference("$namespace.types")]);
210 6
211 6
        $typeRegistry = $container->setDefinition("$namespace.types", new ChildDefinition(TypesRegistryInterface::class));
212 2
        foreach ($config['types'] as $type => $info) {
213
            $typeRegistry->addMethodCall('register', [$info['class'], is_int($type) ? null : $type]);
214
        }
215 6
216 2
        if (isset($config['auto_commit'])) {
217
            $configuration->addMethodCall('setAutoCommit', [$config['auto_commit']]);
218
        }
219 6
220 6
        $logger = null;
221 6
        if ($config['logging']) {
222
            $logger = new Reference('prime.logger');
223
        }
224 6
225 6
        if ($config['profiling']) {
226
            $profilingLogger = new Reference('prime.logger.profiling');
227 6
228 6
            if (null !== $logger) {
229 6
                $chainLogger = $container->findDefinition('prime.logger.chain');
230
                $chainLogger->replaceArgument(0, [$logger, $profilingLogger]);
231 6
232
                $logger = new Reference('prime.logger.chain');
233
            } else {
234
                $logger = $profilingLogger;
235
            }
236
        }
237 6
238 6
        if ($logger) {
239
            $configuration->addMethodCall('setSQLLogger', [$logger]);
240
        }
241
242
        foreach ($config['platformTypes'] as $type => $info) {
243
            $configuration->addMethodCall('addPlatformType', [$info['class'], is_int($type) ? null : $type]);
244
        }
245
    }
246
247
    /**
248
     * @return Reference|null
249
     */
250
    private function createCacheReference(string $namespace, array $config, ContainerBuilder $container)
251
    {
252
        if (isset($config['service'])) {
253
            return new Reference($config['service']);
254
        }
255
256
        if (isset($config['pool'])) {
257
            if (!$container->has($namespace)) {
258
                $definition = $container->register($namespace, Psr16Cache::class);
259
                $definition->addArgument(new Reference($config['pool']));
260
            }
261
262
            return new Reference($namespace);
263
        }
264
265
        return null;
266
    }
267
268 2
    /**
269
     * Create the cache result service.
270 2
     *
271 1
     * @return Reference|null
272
     */
273
    private function createResultCacheReference(string $namespace, array $config, ContainerBuilder $container)
274 1
    {
275 1
        if (isset($config['service'])) {
276 1
            return new Reference($config['service']);
277 1
        }
278 1
279
        if (isset($config['pool'])) {
280 1
            if (!$container->has($namespace)) {
281 1
                $definition = $container->register($namespace.'.doctrine-provider', DoctrineProvider::class);
282
                $definition->setFactory([DoctrineProvider::class, 'wrap']);
283
                $definition->addArgument(new Reference($config['pool']));
284 1
285
                $definition = $container->register($namespace, DoctrineCacheAdapter::class);
286
                $definition->addArgument(new Reference($namespace.'.doctrine-provider'));
287
            }
288
289
            return new Reference($namespace);
290
        }
291
292
        return null;
293 6
    }
294
295 6
    /**
296
     * Rearrange the key name of the configuration.
297
     */
298
    private function cleanConnectionOptions(array $options): array
299
    {
300
        if (isset($options['platform_service'])) {
301
            $options['platform'] = new Reference($options['platform_service']);
302 6
            unset($options['platform_service']);
303
        }
304
305
//        unset($options['mapping_types']);
306
307
        if (isset($options['shard_choser'])) {
308
            $options['shard_choser'] = new Reference($options['shard_choser']);
309
        }
310
311
        $parameters = [
312
            'options' => 'driverOptions',
313
            'driver_class' => 'driverClass',
314
            'wrapper_class' => 'wrapperClass',
315
            'shard_choser' => 'shardChoser',
316 6
            'distribution_key' => 'distributionKey',
317 6
            'server_version' => 'serverVersion',
318 6
            'default_table_options' => 'defaultTableOptions',
319 6
        ];
320
321
        foreach ($parameters as $old => $new) {
322
            if (isset($options[$old])) {
323 6
                $options[$new] = $options[$old];
324
                unset($options[$old]);
325
            }
326
        }
327 6
328
        if (!empty($options['read']) && !empty($options['shards'])) {
329 6
            throw new InvalidArgumentException('Sharding and master-slave connection cannot be used together');
330 6
        }
331 6
332
        $parameters = ['read', 'shards', 'driverOptions', 'defaultTableOptions'];
333
334
        foreach ($parameters as $key) {
335 6
            if (empty($options[$key])) {
336
                unset($options[$key]);
337
            }
338
        }
339
340
        return $options;
341 6
    }
342
343 6
    /**
344
     * {@inheritDoc}
345
     */
346
    public function getConfiguration(array $config, ContainerBuilder $container)
347
    {
348
        return new Configuration($container->getParameter('kernel.debug'));
349
    }
350
}
351