Issues (63)

DependencyInjection/PrimeExtension.php (1 issue)

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;
13
use Bdf\Prime\MongoDB\Document\DocumentMapperInterface;
14
use Bdf\Prime\MongoDB\Schema\CollectionStructureUpgraderResolver;
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;
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 7
    public function load(array $configs, ContainerBuilder $container)
41
    {
42 7
        $configuration = $this->getConfiguration($configs, $container);
43 7
        $config = $this->processConfiguration($configuration, $configs);
44
45 7
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
46 7
        $loader->load('prime.yaml');
47 7
        $loader->load('collector.yaml');
48
49 7
        $this->configureConnection($config, $container);
50 7
        $this->configureMapperCache($config, $container);
51 7
        $this->configureSerializer($config, $container);
52
53 7
        if (interface_exists(StructureUpgraderResolverInterface::class)) {
54 7
            $this->configureUpgrader($config, $container);
55
        }
56
57 7
        if (class_exists(MongoCollectionLocator::class)) {
58
            $this->configureMongo($loader, $container, $config);
59
        }
60
61 7
        if (class_exists(PrimeShellCommand::class)) {
62
            $loader->load('prime_shell.yaml');
63
        }
64
65 7
        $container->setParameter('prime.default_connection', $config['default_connection']);
66 7
        $container->setParameter('prime.migration.connection', $config['migration']['connection']);
67 7
        $container->setParameter('prime.migration.table', $config['migration']['table']);
68 7
        $container->setParameter('prime.migration.path', $config['migration']['path']);
69 7
        $container->setParameter('prime.hydrators', $config['hydrators']);
70 7
        $container->setParameter('prime.locatorizable', $config['activerecord']);
71
    }
72
73 7
    public function configureConnection(array $config, ContainerBuilder $container)
74
    {
75 7
        foreach ($config['connections'] as $name => &$options) {
76 7
            $options = $this->cleanConnectionOptions($options);
77
78
            // Overwrite global config by the connection config parameters and create the configuration reference.
79 7
            $this->createConfiguration($name, $this->mergeConfiguration($config, $options), $container);
80
81 7
            if (!$container->hasDefinition(MasterSlaveConnectionFactory::class) && $this->hasConnectionOption('read', $options)) {
82 7
                $container->register(MasterSlaveConnectionFactory::class, MasterSlaveConnectionFactory::class)
83 7
                    ->addTag('bdf_prime.connection_factory', ['priority' => -255])
84 7
                    ->addArgument(new Reference(ConnectionFactory::class));
85
            }
86
87 7
            if (!$container->hasDefinition(ShardingConnectionFactory::class) && $this->hasConnectionOption('shards', $options)) {
88 7
                $container->register(ShardingConnectionFactory::class, ShardingConnectionFactory::class)
89 7
                    ->addTag('bdf_prime.connection_factory', ['priority' => -256])
90 7
                    ->addArgument(new Reference(ConnectionFactory::class));
91
            }
92
        }
93
94 7
        $registry = $container->getDefinition(ConnectionRegistry::class);
95 7
        $registry->replaceArgument(0, $config['connections']);
96
    }
97
98 7
    private function hasConnectionOption(string $option, array $options): bool
99
    {
100 7
        if (isset($options[$option])) {
101 1
            return true;
102
        }
103
104 7
        if (!isset($options['url'])) {
105
            return false;
106
        }
107
108
        // The option could be in the url. Adding the factory by default.
109 7
        return true;
110
    }
111
112 7
    public function configureSerializer(array $config, ContainerBuilder $container)
113
    {
114 7
        if (!isset($config['serializer'])) {
115 7
            return;
116
        }
117
118
        $prime = $container->findDefinition('prime');
119
        $prime->addMethodCall('setSerializer', [new Reference($config['serializer'])]);
120
    }
121
122 7
    public function configureMapperCache(array $config, ContainerBuilder $container)
123
    {
124 7
        $definition = $container->getDefinition(MapperFactory::class);
125
126 7
        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 7
        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 7
    private function configureUpgrader(array $config, ContainerBuilder $container)
0 ignored issues
show
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 7
        $container->register(RepositoryUpgraderResolver::class)
172 7
            ->addArgument(new Reference(ServiceLocator::class))
173 7
        ;
174
175 7
        $container->register(StructureUpgraderResolverAggregate::class)
176 7
            ->setPublic(true)
177 7
            ->addMethodCall('register', [new Reference(RepositoryUpgraderResolver::class)])
178 7
        ;
179
180 7
        $container->setAlias(StructureUpgraderResolverInterface::class, StructureUpgraderResolverAggregate::class)
181 7
            ->setPublic(true)
182 7
        ;
183
184 7
        $container->findDefinition('prime.upgrade_command')
185 7
            ->replaceArgument(0, new Reference(StructureUpgraderResolverInterface::class))
186 7
        ;
187
    }
188
189 7
    public function mergeConfiguration(array $globalConfig, array $config): array
190
    {
191 7
        return [
192 7
            'types' => array_merge($globalConfig['types'], $config['types']),
193 7
            'auto_commit' => $config['auto_commit'] ?? $globalConfig['auto_commit'],
194 7
            'logging' => $config['logging'] ?? $globalConfig['logging'],
195 7
            'profiling' => $config['profiling'] ?? $globalConfig['profiling'],
196 7
            'platformTypes' => $config['platformTypes'] ?? [],
197 7
        ];
198
    }
199
200
    /**
201
     * Create and declare the configuration definition of the connection.
202
     */
203 7
    public function createConfiguration(string $name, array $config, ContainerBuilder $container): void
204
    {
205 7
        $namespace = "prime.{$name}_connection";
206
207 7
        $configuration = $container->setDefinition("$namespace.configuration", new ChildDefinition(PrimeConfiguration::class));
208 7
        $configuration->setPublic(true);
209 7
        $configuration->addMethodCall('setTypes', [new Reference("$namespace.types")]);
210
211 7
        $typeRegistry = $container->setDefinition("$namespace.types", new ChildDefinition(TypesRegistryInterface::class));
212 7
        foreach ($config['types'] as $type => $info) {
213 2
            $typeRegistry->addMethodCall('register', [$info['class'], is_int($type) ? null : $type]);
214
        }
215
216 7
        if (isset($config['auto_commit'])) {
217 3
            $configuration->addMethodCall('setAutoCommit', [$config['auto_commit']]);
218
        }
219
220 7
        $logger = null;
221 7
        if ($config['logging']) {
222 7
            $logger = new Reference('prime.logger');
223
        }
224
225 7
        if ($config['profiling']) {
226 7
            $profilingLogger = new Reference('prime.logger.profiling');
227
228 7
            if (null !== $logger) {
229 7
                $chainLogger = $container->findDefinition('prime.logger.chain');
230 7
                $chainLogger->replaceArgument(0, [$logger, $profilingLogger]);
231
232 7
                $logger = new Reference('prime.logger.chain');
233
            } else {
234
                $logger = $profilingLogger;
235
            }
236
        }
237
238 7
        if ($logger) {
239 7
            $configuration->addMethodCall('setSQLLogger', [$logger]);
240
        }
241
242 7
        foreach ($config['platformTypes'] as $type => $info) {
243 1
            $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
    /**
269
     * Create the cache result service.
270
     *
271
     * @return Reference|null
272
     */
273 2
    private function createResultCacheReference(string $namespace, array $config, ContainerBuilder $container)
274
    {
275 2
        if (isset($config['service'])) {
276 1
            return new Reference($config['service']);
277
        }
278
279 1
        if (isset($config['pool'])) {
280 1
            if (!$container->has($namespace)) {
281 1
                $definition = $container->register($namespace.'.doctrine-provider', DoctrineProvider::class);
282 1
                $definition->setFactory([DoctrineProvider::class, 'wrap']);
283 1
                $definition->addArgument(new Reference($config['pool']));
284
285 1
                $definition = $container->register($namespace, DoctrineCacheAdapter::class);
286 1
                $definition->addArgument(new Reference($namespace.'.doctrine-provider'));
287
            }
288
289 1
            return new Reference($namespace);
290
        }
291
292
        return null;
293
    }
294
295
    /**
296
     * Rearrange the key name of the configuration.
297
     */
298 7
    private function cleanConnectionOptions(array $options): array
299
    {
300 7
        if (isset($options['platform_service'])) {
301
            $options['platform'] = new Reference($options['platform_service']);
302
            unset($options['platform_service']);
303
        }
304
305
//        unset($options['mapping_types']);
306
307 7
        if (isset($options['shard_choser'])) {
308
            $options['shard_choser'] = new Reference($options['shard_choser']);
309
        }
310
311 7
        $parameters = [
312 7
            'options' => 'driverOptions',
313 7
            'driver_class' => 'driverClass',
314 7
            'wrapper_class' => 'wrapperClass',
315 7
            'shard_choser' => 'shardChoser',
316 7
            'distribution_key' => 'distributionKey',
317 7
            'server_version' => 'serverVersion',
318 7
            'default_table_options' => 'defaultTableOptions',
319 7
        ];
320
321 7
        foreach ($parameters as $old => $new) {
322 7
            if (isset($options[$old])) {
323 7
                $options[$new] = $options[$old];
324 7
                unset($options[$old]);
325
            }
326
        }
327
328 7
        if (!empty($options['read']) && !empty($options['shards'])) {
329
            throw new InvalidArgumentException('Sharding and master-slave connection cannot be used together');
330
        }
331
332 7
        $parameters = ['read', 'shards', 'driverOptions', 'defaultTableOptions'];
333
334 7
        foreach ($parameters as $key) {
335 7
            if (empty($options[$key])) {
336 7
                unset($options[$key]);
337
            }
338
        }
339
340 7
        return $options;
341
    }
342
343
    /**
344
     * {@inheritDoc}
345
     */
346 7
    public function getConfiguration(array $config, ContainerBuilder $container)
347
    {
348 7
        return new Configuration($container->getParameter('kernel.debug'));
349
    }
350
}
351