Passed
Push — master ( 9faae6...83bfe6 )
by Vincent
03:11
created

PrimeExtension::configureUpgrader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 9
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 17
ccs 10
cts 10
cp 1
crap 1
rs 9.9666
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\Schema\RepositoryUpgraderResolver;
13
use Bdf\Prime\Schema\StructureUpgraderResolverAggregate;
14
use Bdf\Prime\Schema\StructureUpgraderResolverInterface;
15
use Bdf\Prime\ServiceLocator;
16
use Bdf\Prime\Types\TypesRegistryInterface;
17
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
18
use Symfony\Component\Cache\Psr16Cache;
19
use Symfony\Component\Config\FileLocator;
20
use Symfony\Component\DependencyInjection\ChildDefinition;
21
use Symfony\Component\DependencyInjection\ContainerBuilder;
22
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
23
use Symfony\Component\DependencyInjection\Extension\Extension;
24
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
25
use Symfony\Component\DependencyInjection\Reference;
26
27
/**
28
 * PrimeExtension
29
 */
30
class PrimeExtension extends Extension
31
{
32
    /**
33
     * {@inheritDoc}
34
     */
35 6
    public function load(array $configs, ContainerBuilder $container)
36
    {
37 6
        $configuration = $this->getConfiguration($configs, $container);
38 6
        $config = $this->processConfiguration($configuration, $configs);
39
40 6
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
41 6
        $loader->load('prime.yaml');
42 6
        $loader->load('collector.yaml');
43
44 6
        $this->configureConnection($config, $container);
45 6
        $this->configureMapperCache($config, $container);
46 6
        $this->configureSerializer($config, $container);
47
48 6
        if (interface_exists(StructureUpgraderResolverInterface::class)) {
49 6
            $this->configureUpgrader($config, $container);
50
        }
51
52 6
        $container->setParameter('prime.default_connection', $config['default_connection']);
53 6
        $container->setParameter('prime.migration.connection', $config['migration']['connection']);
54 6
        $container->setParameter('prime.migration.table', $config['migration']['table']);
55 6
        $container->setParameter('prime.migration.path', $config['migration']['path']);
56 6
        $container->setParameter('prime.hydrators', $config['hydrators']);
57 6
        $container->setParameter('prime.locatorizable', $config['activerecord']);
58
    }
59
60
    /**
61
     * @param array $config
62
     * @param ContainerBuilder $container
63
     */
64 6
    public function configureConnection(array $config, ContainerBuilder $container)
65
    {
66 6
        foreach ($config['connections'] as $name => &$options) {
67 6
            $options = $this->cleanConnectionOptions($options);
68
69
            // Overwrite global config by the connection config parameters and create the configuration reference.
70 6
            $this->createConfiguration($name, $this->mergeConfiguration($config, $options), $container);
71
72 6
            if (!$container->hasDefinition(MasterSlaveConnectionFactory::class) && $this->hasConnectionOption('read', $options)) {
73 6
                $container->register(MasterSlaveConnectionFactory::class, MasterSlaveConnectionFactory::class)
74 6
                    ->addTag('bdf_prime.connection_factory', ['priority' => -255])
75 6
                    ->addArgument(new Reference(ConnectionFactory::class));
76
            }
77
78 6
            if (!$container->hasDefinition(ShardingConnectionFactory::class) && $this->hasConnectionOption('shards', $options)) {
79 6
                $container->register(ShardingConnectionFactory::class, ShardingConnectionFactory::class)
80 6
                    ->addTag('bdf_prime.connection_factory', ['priority' => -256])
81 6
                    ->addArgument(new Reference(ConnectionFactory::class));
82
            }
83
        }
84
85 6
        $registry = $container->getDefinition(ConnectionRegistry::class);
86 6
        $registry->replaceArgument(0, $config['connections']);
87
    }
88
89
    /**
90
     * @param string $option
91
     * @param array $options
92
     * @return bool
93
     */
94 6
    private function hasConnectionOption(string $option, array $options): bool
95
    {
96 6
        if (isset($options[$option])) {
97 1
            return true;
98
        }
99
100 6
        if (!isset($options['url'])) {
101
            return false;
102
        }
103
104
        // The option could be in the url. Adding the factory by default.
105 6
        return true;
106
    }
107
108
    /**
109
     * @param array $config
110
     * @param ContainerBuilder $container
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
    /**
123
     * @param array $config
124
     * @param ContainerBuilder $container
125
     */
126 6
    public function configureMapperCache(array $config, ContainerBuilder $container)
127
    {
128 6
        $definition = $container->getDefinition(MapperFactory::class);
129
130 6
        if (isset($config['cache']['query'])) {
131 2
            $ref = $this->createResultCacheReference('prime.cache.query', $config['cache']['query'], $container);
132
133 2
            if ($ref !== null) {
134 2
                $definition->replaceArgument(2, $ref);
135
            }
136
        }
137
138 6
        if (isset($config['cache']['metadata'])) {
139
            $ref = $this->createCacheReference('prime.cache.metadata', $config['cache']['metadata'], $container);
140
141
            if ($ref !== null) {
142
                $definition->replaceArgument(1, $ref);
143
            }
144
        }
145
    }
146
147
    /**
148
     * @param array $config
149
     * @param ContainerBuilder $container
150
     */
151 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

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