Test Failed
Push — master ( 15382f...02157a )
by Sébastien
03:01
created

PrimeExtension::load()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 18
c 2
b 0
f 0
nc 4
nop 2
dl 0
loc 27
cc 3
rs 9.6666
ccs 16
cts 16
cp 1
crap 3
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\CollectionStructureUpgrader;
0 ignored issues
show
Bug introduced by
The type Bdf\Prime\MongoDB\Schema...ectionStructureUpgrader 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\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...
16
use Bdf\Prime\Schema\RepositoryUpgraderResolver;
17
use Bdf\Prime\Schema\StructureUpgraderResolverAggregate;
18
use Bdf\Prime\Schema\StructureUpgraderResolverInterface;
19
use Bdf\Prime\ServiceLocator;
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 6
class PrimeExtension extends Extension
36
{
37 6
    /**
38 6
     * {@inheritDoc}
39
     */
40 6
    public function load(array $configs, ContainerBuilder $container)
41 6
    {
42 6
        $configuration = $this->getConfiguration($configs, $container);
43
        $config = $this->processConfiguration($configuration, $configs);
44 6
45 6
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
46 6
        $loader->load('prime.yaml');
47
        $loader->load('collector.yaml');
48 6
49 6
        $this->configureConnection($config, $container);
50
        $this->configureMapperCache($config, $container);
51
        $this->configureSerializer($config, $container);
52 6
53 6
        if (interface_exists(StructureUpgraderResolverInterface::class)) {
54 6
            $this->configureUpgrader($config, $container);
55 6
        }
56 6
57 6
        if (class_exists(MongoCollectionLocator::class)) {
58
            $this->configureMongo($loader, $container, $config);
59
        }
60
61
        $container->setParameter('prime.default_connection', $config['default_connection']);
62
        $container->setParameter('prime.migration.connection', $config['migration']['connection']);
63
        $container->setParameter('prime.migration.table', $config['migration']['table']);
64 6
        $container->setParameter('prime.migration.path', $config['migration']['path']);
65
        $container->setParameter('prime.hydrators', $config['hydrators']);
66 6
        $container->setParameter('prime.locatorizable', $config['activerecord']);
67 6
    }
68
69
    /**
70 6
     * @param array $config
71
     * @param ContainerBuilder $container
72 6
     */
73 6
    public function configureConnection(array $config, ContainerBuilder $container)
74 6
    {
75 6
        foreach ($config['connections'] as $name => &$options) {
76
            $options = $this->cleanConnectionOptions($options);
77
78 6
            // Overwrite global config by the connection config parameters and create the configuration reference.
79 6
            $this->createConfiguration($name, $this->mergeConfiguration($config, $options), $container);
80 6
81 6
            if (!$container->hasDefinition(MasterSlaveConnectionFactory::class) && $this->hasConnectionOption('read', $options)) {
82
                $container->register(MasterSlaveConnectionFactory::class, MasterSlaveConnectionFactory::class)
83
                    ->addTag('bdf_prime.connection_factory', ['priority' => -255])
84
                    ->addArgument(new Reference(ConnectionFactory::class));
85 6
            }
86 6
87
            if (!$container->hasDefinition(ShardingConnectionFactory::class) && $this->hasConnectionOption('shards', $options)) {
88
                $container->register(ShardingConnectionFactory::class, ShardingConnectionFactory::class)
89
                    ->addTag('bdf_prime.connection_factory', ['priority' => -256])
90
                    ->addArgument(new Reference(ConnectionFactory::class));
91
            }
92
        }
93
94 6
        $registry = $container->getDefinition(ConnectionRegistry::class);
95
        $registry->replaceArgument(0, $config['connections']);
96 6
    }
97 1
98
    /**
99
     * @param string $option
100 6
     * @param array $options
101
     * @return bool
102
     */
103
    private function hasConnectionOption(string $option, array $options): bool
104
    {
105 6
        if (isset($options[$option])) {
106
            return true;
107
        }
108
109
        if (!isset($options['url'])) {
110
            return false;
111
        }
112 6
113
        // The option could be in the url. Adding the factory by default.
114 6
        return true;
115 6
    }
116
117
    /**
118
     * @param array $config
119
     * @param ContainerBuilder $container
120
     */
121
    public function configureSerializer(array $config, ContainerBuilder $container)
122
    {
123
        if (!isset($config['serializer'])) {
124
            return;
125
        }
126 6
127
        $prime = $container->findDefinition('prime');
128 6
        $prime->addMethodCall('setSerializer', [new Reference($config['serializer'])]);
129
    }
130 6
131 2
    /**
132
     * @param array $config
133 2
     * @param ContainerBuilder $container
134 2
     */
135
    public function configureMapperCache(array $config, ContainerBuilder $container)
136
    {
137
        $definition = $container->getDefinition(MapperFactory::class);
138 6
139
        if (isset($config['cache']['query'])) {
140
            $ref = $this->createResultCacheReference('prime.cache.query', $config['cache']['query'], $container);
141
142
            if ($ref !== null) {
143
                $definition->replaceArgument(2, $ref);
144
            }
145
        }
146
147
        if (isset($config['cache']['metadata'])) {
148
            $ref = $this->createCacheReference('prime.cache.metadata', $config['cache']['metadata'], $container);
149
150
            if ($ref !== null) {
151 6
                $definition->replaceArgument(1, $ref);
152
            }
153 6
        }
154 6
    }
155
156
    /**
157 6
     * @param FileLoader $loader
158 6
     * @param ContainerBuilder $container
159 6
     * @param array $config
160
     * @return void
161
     * @throws \Exception
162 6
     */
163 6
    public function configureMongo(FileLoader $loader, ContainerBuilder $container, array $config): void
164
    {
165
        $loader->load('prime_mongo.yaml');
166 6
167 6
        $container->registerForAutoconfiguration(DocumentMapperInterface::class)
168
            ->setPublic(true)
169
            ->setShared(false)
170
            ->setAutowired(true);
171
172
        if (isset($config['cache']['metadata'])) {
173
            $definition = $container->findDefinition('prime_mongodb_serializer');
174
            $ref = $this->createCacheReference('prime.cache.metadata', $config['cache']['metadata'], $container);
175
176
            if ($ref !== null) {
177 6
                $definition->replaceArgument(0, $ref);
178
            }
179
        }
180 6
181 6
        $container->findDefinition(StructureUpgraderResolverAggregate::class)
182 6
            ->addMethodCall('register', [new Reference(CollectionStructureUpgraderResolver::class)])
183 6
        ;
184
    }
185
186
    /**
187
     * @param array $config
188
     * @param ContainerBuilder $container
189
     */
190
    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

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