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
|
|||
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 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.