Completed
Pull Request — master (#1706)
by Karel
04:04
created

FOSElasticaExtension   F

Complexity

Total Complexity 96

Size/Duplication

Total Lines 722
Duplicated Lines 3.74 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 89.01%

Importance

Changes 0
Metric Value
wmc 96
lcom 1
cbo 9
dl 27
loc 722
ccs 316
cts 355
cp 0.8901
rs 1.878
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
B load() 0 60 9
A getConfiguration() 0 4 1
A loadClients() 0 24 3
B loadIndexes() 5 54 6
A loadIndexTemplates() 4 32 3
A loadIndexFinder() 0 9 1
A loadIndexConfig() 0 30 5
B buildCallback() 0 25 7
A transformServiceReference() 0 4 2
A loadIndexSerializerIntegration() 0 21 5
B loadIndexPersistenceIntegration() 0 20 6
A loadElasticaToModelTransformer() 0 22 2
A loadModelToElasticaTransformer() 0 20 3
A loadObjectPersister() 0 37 4
A loadIndexPagerProvider() 0 33 5
B loadIndexListener() 0 59 9
B getDoctrineEvents() 0 32 7
A loadTypeFinder() 0 26 3
A loadIndexManager() 9 9 1
A loadIndexTemplateManager() 9 9 1
A loadDriver() 0 10 2
A loadSerializer() 0 11 2
A createDefaultManagerAlias() 0 17 4
A getClient() 0 8 2
A registerMessengerConfiguration() 0 12 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like FOSElasticaExtension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FOSElasticaExtension, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the FOSElasticaBundle package.
5
 *
6
 * (c) FriendsOfSymfony <https://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\ElasticaBundle\DependencyInjection;
13
14
use Elastica\Client as ElasticaClient;
15
use FOS\ElasticaBundle\Elastica\Client;
16
use FOS\ElasticaBundle\Manager\RepositoryManagerInterface;
17
use Symfony\Component\Config\FileLocator;
18
use Symfony\Component\DependencyInjection\Alias;
19
use Symfony\Component\DependencyInjection\ChildDefinition;
20
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
21
use Symfony\Component\DependencyInjection\ContainerBuilder;
22
use Symfony\Component\DependencyInjection\Exception\LogicException;
23
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
24
use Symfony\Component\DependencyInjection\Reference;
25
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
26
use Symfony\Component\Messenger\MessageBusInterface;
27
28
class FOSElasticaExtension extends Extension
29
{
30
    /**
31
     * Definition of elastica clients as configured by this extension.
32
     *
33
     * @var array
34
     */
35
    private $clients = [];
36
37
    /**
38
     * An array of indexes as configured by the extension.
39
     *
40
     * @var array
41
     */
42
    private $indexConfigs = [];
43
44
    /**
45
     * An array of index templates as configured by the extension.
46
     *
47
     * @var array
48
     */
49
    private $indexTemplateConfigs = [];
50
51
    /**
52
     * If we've encountered a type mapped to a specific persistence driver, it will be loaded
53
     * here.
54
     *
55
     * @var array
56
     */
57
    private $loadedDrivers = [];
58
59 22
    public function load(array $configs, ContainerBuilder $container)
60
    {
61 22
        $configuration = $this->getConfiguration($configs, $container);
62 22
        $config = $this->processConfiguration($configuration, $configs);
63
64 22
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
65
66 22
        if (empty($config['clients']) || empty($config['indexes'])) {
67
            // No Clients or indexes are defined
68
            return;
69
        }
70
71 22
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener', 'commands'] as $basename) {
72 22
            $loader->load(\sprintf('%s.xml', $basename));
73
        }
74
75 22
        if (empty($config['default_client'])) {
76 22
            $keys = \array_keys($config['clients']);
77 22
            $config['default_client'] = \reset($keys);
78
        }
79
80 22
        if (empty($config['default_index'])) {
81 22
            $keys = \array_keys($config['indexes']);
82 22
            $config['default_index'] = \reset($keys);
83
        }
84
85 22
        if ($this->isConfigEnabled($container, $config['messenger'])) {
86
            $this->registerMessengerConfiguration($config['messenger'], $container, $loader);
87
        }
88
89 22
        if (isset($config['serializer'])) {
90 1
            $loader->load('serializer.xml');
91
92 1
            $this->loadSerializer($config['serializer'], $container);
93
        }
94
95 22
        $this->loadClients($config['clients'], $container);
96 22
        $container->setAlias('fos_elastica.client', \sprintf('fos_elastica.client.%s', $config['default_client']));
97 22
        $container->setAlias(ElasticaClient::class, 'fos_elastica.client');
98 22
        $container->setAlias(Client::class, 'fos_elastica.client');
99
100 22
        $this->loadIndexes($config['indexes'], $container);
101 22
        $container->setAlias('fos_elastica.index', \sprintf('fos_elastica.index.%s', $config['default_index']));
102 22
        $container->setParameter('fos_elastica.default_index', $config['default_index']);
103
104 22
        if ($usedIndexNames = \array_intersect_key($config['indexes'], $config['index_templates'])) {
105
            throw new \DomainException(\sprintf('Index names "%s" are already in use and can not be used for index templates names', \implode('","', \array_keys($usedIndexNames))));
106
        }
107 22
        $this->loadIndexTemplates($config['index_templates'], $container);
108
109 22
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
110
        $container
111 22
            ->getDefinition('fos_elastica.config_source.template_container')
112 22
            ->replaceArgument(0, $this->indexTemplateConfigs);
113
114 22
        $this->loadIndexManager($container);
115 22
        $this->loadIndexTemplateManager($container);
116
117 22
        $this->createDefaultManagerAlias($config['default_manager'], $container);
118 22
    }
119
120
    /**
121
     * @return Configuration
122
     */
123 22
    public function getConfiguration(array $config, ContainerBuilder $container)
124
    {
125 22
        return new Configuration($container->getParameter('kernel.debug'));
126
    }
127
128
    /**
129
     * Loads the configured clients.
130
     *
131
     * @param array            $clients   An array of clients configurations
132
     * @param ContainerBuilder $container A ContainerBuilder instance
133
     */
134 22
    private function loadClients(array $clients, ContainerBuilder $container): void
135
    {
136 22
        foreach ($clients as $name => $clientConfig) {
137 22
            $clientId = \sprintf('fos_elastica.client.%s', $name);
138
139 22
            $clientDef = new ChildDefinition('fos_elastica.client_prototype');
140 22
            $clientDef->replaceArgument(0, $clientConfig);
141 22
            $clientDef->replaceArgument(1, null);
142
143 22
            $logger = $clientConfig['connections'][0]['logger'];
144 22
            if (false !== $logger) {
145 22
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
146
            }
147
148 22
            $clientDef->addTag('fos_elastica.client');
149
150 22
            $container->setDefinition($clientId, $clientDef);
151
152 22
            $this->clients[$name] = [
153 22
                'id' => $clientId,
154 22
                'reference' => new Reference($clientId),
155
            ];
156
        }
157 22
    }
158
159
    /**
160
     * Loads the configured indexes.
161
     *
162
     * @param array            $indexes   An array of indexes configurations
163
     * @param ContainerBuilder $container A ContainerBuilder instance
164
     *
165
     * @throws \InvalidArgumentException
166
     */
167 22
    private function loadIndexes(array $indexes, ContainerBuilder $container): void
168
    {
169 22
        $indexableCallbacks = [];
170
171 22
        foreach ($indexes as $name => $index) {
172 22
            $indexId = \sprintf('fos_elastica.index.%s', $name);
173 22
            $indexName = $index['index_name'] ?? $name;
174
175 22
            $indexDef = new ChildDefinition('fos_elastica.index_prototype');
176 22
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
177 22
            $indexDef->replaceArgument(0, $indexName);
178 22
            $indexDef->addTag('fos_elastica.index', [
179 22
                'name' => $name,
180
            ]);
181
182 22 View Code Duplication
            if (isset($index['client'])) {
183 2
                $client = $this->getClient($index['client']);
184
185 2
                $indexDef->setFactory([$client, 'getIndex']);
186
            }
187
188 22
            $container->setDefinition($indexId, $indexDef);
189 22
            $reference = new Reference($indexId);
190
191 22
            $this->indexConfigs[$name] = [
192 22
                'elasticsearch_name' => $indexName,
193 22
                'reference' => $reference,
194 22
                'model' => $index['persistence']['model'] ?? null,
195 22
                'name' => $name,
196 22
                'settings' => $index['settings'],
197 22
                'index_prototype' => $index['index_prototype'] ?? [],
198 22
                'use_alias' => $index['use_alias'],
199
            ];
200
201 22
            if ($index['finder']) {
202
                $this->loadIndexFinder($container, $name, $reference);
203
            }
204
205 22
            $this->loadIndexConfig((array) $index, $this->indexConfigs[$name]);
206
207 22
            if (isset($index['indexable_callback'])) {
208 4
                $indexableCallbacks[$name] = $this->buildCallback($index['indexable_callback'], $name);
209
            }
210
211 22
            $this->loadIndexSerializerIntegration($index['serializer'] ?? [], $container, $reference);
212
213 22
            if (isset($index['persistence'])) {
214 16
                $this->loadIndexPersistenceIntegration($index['persistence'], $container, $reference, $name);
215
            }
216
        }
217
218 22
        $indexable = $container->getDefinition('fos_elastica.indexable');
219 22
        $indexable->replaceArgument(0, $indexableCallbacks);
220 22
    }
221
222
    /**
223
     * Loads the configured indexes.
224
     *
225
     * @param array            $indexTemplates An array of indexes configurations
226
     * @param ContainerBuilder $container      A ContainerBuilder instance
227
     *
228
     * @throws \InvalidArgumentException
229
     */
230 22
    private function loadIndexTemplates(array $indexTemplates, ContainerBuilder $container): void
231
    {
232 22
        foreach ($indexTemplates as $name => $indexTemplate) {
233 6
            $indexId = \sprintf('fos_elastica.index_template.%s', $name);
234 6
            $indexTemplateName = $indexTemplate['template_name'] ?? $name;
235
236 6
            $indexDef = new ChildDefinition('fos_elastica.index_template_prototype');
237 6
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndexTemplate']);
238 6
            $indexDef->replaceArgument(0, $indexTemplateName);
239 6
            $indexDef->addTag('fos_elastica.index_template', [
240 6
                'name' => $name,
241
            ]);
242
243 6 View Code Duplication
            if (isset($indexTemplate['client'])) {
244 6
                $client = $this->getClient($indexTemplate['client']);
245 6
                $indexDef->setFactory([$client, 'getIndexTemplate']);
246
            }
247
248 6
            $container->setDefinition($indexId, $indexDef);
249 6
            $reference = new Reference($indexId);
250
251 6
            $this->indexTemplateConfigs[$name] = [
252 6
                'elasticsearch_name' => $indexTemplateName,
253 6
                'reference' => $reference,
254 6
                'name' => $name,
255 6
                'settings' => $indexTemplate['settings'],
256 6
                'template' => $indexTemplate['template'],
257
            ];
258
259 6
            $this->loadIndexConfig((array) $indexTemplate, $this->indexTemplateConfigs[$name]);
260
        }
261 22
    }
262
263
    /**
264
     * Loads the configured index finders.
265
     *
266
     * @param string    $name  The index name
267
     * @param Reference $index Reference to the related index
268
     */
269
    private function loadIndexFinder(ContainerBuilder $container, string $name, Reference $index): void
270
    {
271
        $finderId = \sprintf('fos_elastica.finder.%s', $name);
272
        $finderDef = new ChildDefinition('fos_elastica.finder');
273
        $finderDef->replaceArgument(0, $index);
274
        $finderDef->replaceArgument(1, new Reference(\sprintf('fos_elastica.elastica_to_model_transformer.%s', $name)));
275
276
        $container->setDefinition($finderId, $finderDef);
277
    }
278
279
    /**
280
     * Loads the configured $index.
281
     */
282 22
    private function loadIndexConfig(array $index, array &$indexConfig): void
283
    {
284 22
        $indexConfig = \array_merge($indexConfig, [
285 22
            'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch
286
            'config' => [],
287
        ]);
288
289
        foreach ([
290 22
            'dynamic_templates',
291
            'properties',
292
            '_id',
293
            '_routing',
294
            '_source',
295
        ] as $field) {
296 22
            if (isset($index[$field])) {
297 22
                $indexConfig['mapping'][$field] = $index[$field];
298
            }
299
        }
300
301
        foreach ([
302 22
            'analyzer',
303
            'search_analyzer',
304
            'dynamic',
305
            'date_detection',
306
            'dynamic_date_formats',
307
            'numeric_detection',
308
        ] as $field) {
309 22
            $indexConfig['config'][$field] = \array_key_exists($field, $index) ? $index[$field] : null;
310
        }
311 22
    }
312
313 4
    private function buildCallback($indexCallback, $indexName)
314
    {
315 4
        if (\is_array($indexCallback)) {
316 4
            if (!isset($indexCallback[0])) {
317
                throw new \InvalidArgumentException(\sprintf('Invalid indexable_callback for index "%s"', $indexName));
318
            }
319
320 4
            $classOrServiceRef = $this->transformServiceReference($indexCallback[0]);
321 4
            if ($classOrServiceRef instanceof Reference && !isset($indexCallback[1])) {
322
                return $classOrServiceRef; // __invoke
323
            }
324
325 4
            if (!isset($indexCallback[1])) {
326
                throw new \InvalidArgumentException(\sprintf('Invalid indexable_callback for index "%s"', $indexName));
327
            }
328
329 4
            return [$classOrServiceRef, $indexCallback[1]];
330
        }
331
332 4
        if (\is_string($indexCallback)) {
333 4
            return $this->transformServiceReference($indexCallback);
334
        }
335
336
        throw new \InvalidArgumentException(\sprintf('Invalid indexable_callback for index "%s"', $indexName));
337
    }
338
339 4
    private function transformServiceReference($classOrService)
340
    {
341 4
        return 0 === \strpos($classOrService, '@') ? new Reference(\substr($classOrService, 1)) : $classOrService;
342
    }
343
344 22
    private function loadIndexSerializerIntegration(array $config, ContainerBuilder $container, Reference $indexRef): void
345
    {
346 22
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
347 1
            $indexSerializerId = \sprintf('%s.serializer.callback', $indexRef);
348 1
            $indexSerializerDef = new ChildDefinition('fos_elastica.serializer_callback_prototype');
349
350 1
            if (isset($config['groups'])) {
351 1
                $indexSerializerDef->addMethodCall('setGroups', [$config['groups']]);
352
            }
353
354 1
            if (isset($config['serialize_null'])) {
355 1
                $indexSerializerDef->addMethodCall('setSerializeNull', [$config['serialize_null']]);
356
            }
357
358 1
            if (isset($config['version'])) {
359 1
                $indexSerializerDef->addMethodCall('setVersion', [$config['version']]);
360
            }
361
362 1
            $container->setDefinition($indexSerializerId, $indexSerializerDef);
363
        }
364 22
    }
365
366
    /**
367
     * Loads the optional provider and finder for a type.
368
     */
369 16
    private function loadIndexPersistenceIntegration(array $config, ContainerBuilder $container, Reference $indexRef, string $indexName): void
370
    {
371 16
        if (isset($config['driver'])) {
372 16
            $this->loadDriver($container, $config['driver']);
373
        }
374
375 16
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($config, $container, $indexName);
376 16
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($config, $container, $indexName);
377 16
        $objectPersisterId = $this->loadObjectPersister($config, $indexRef, $container, $indexName, $modelToElasticaTransformerId);
378
379 16
        if (isset($config['provider'])) {
380 16
            $this->loadIndexPagerProvider($config, $container, $indexName);
381
        }
382 16
        if (isset($config['finder'])) {
383 16
            $this->loadTypeFinder($config, $container, $elasticaToModelTransformerId, $indexRef, $indexName);
384
        }
385 16
        if (isset($config['listener']) && $config['listener']['enabled']) {
386 15
            $this->loadIndexListener($config, $container, $objectPersisterId, $indexName);
387
        }
388 16
    }
389
390
    /**
391
     * Creates and loads an ElasticaToModelTransformer.
392
     */
393 16
    private function loadElasticaToModelTransformer(array $persistenceConfig, ContainerBuilder $container, string $indexName): string
394
    {
395 16
        if (isset($persistenceConfig['elastica_to_model_transformer']['service'])) {
396 1
            return $persistenceConfig['elastica_to_model_transformer']['service'];
397
        }
398
399
        /* Note: transformer services may conflict with "prototype.driver", if
400
         * the index and type names were "prototype" and a driver, respectively.
401
         */
402 15
        $abstractId = \sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $persistenceConfig['driver']);
403 15
        $serviceId = \sprintf('fos_elastica.elastica_to_model_transformer.%s', $indexName);
404 15
        $serviceDef = new ChildDefinition($abstractId);
405 15
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['index' => $indexName]);
406
407 15
        $serviceDef->replaceArgument(1, $persistenceConfig['model']);
408 15
        $serviceDef->replaceArgument(2, \array_merge($persistenceConfig['elastica_to_model_transformer'], [
409 15
            'identifier' => $persistenceConfig['identifier'],
410
        ]));
411 15
        $container->setDefinition($serviceId, $serviceDef);
412
413 15
        return $serviceId;
414
    }
415
416
    /**
417
     * Creates and loads a ModelToElasticaTransformer for an index.
418
     */
419 16
    private function loadModelToElasticaTransformer(array $config, ContainerBuilder $container, string $indexName): string
420
    {
421 16
        if (isset($config['model_to_elastica_transformer']['service'])) {
422
            return $config['model_to_elastica_transformer']['service'];
423
        }
424
425 16
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
426 1
            'fos_elastica.model_to_elastica_identifier_transformer' :
427 16
            'fos_elastica.model_to_elastica_transformer';
428
429 16
        $serviceId = \sprintf('fos_elastica.model_to_elastica_transformer.%s', $indexName);
430 16
        $serviceDef = new ChildDefinition($abstractId);
431 16
        $serviceDef->replaceArgument(0, [
432 16
            'identifier' => $config['identifier'],
433 16
            'index' => $indexName,
434
        ]);
435 16
        $container->setDefinition($serviceId, $serviceDef);
436
437 16
        return $serviceId;
438
    }
439
440
    /**
441
     * Creates and loads an object persister for a index.
442
     */
443 16
    private function loadObjectPersister(array $config, Reference $indexRef, ContainerBuilder $container, string $indexName, string $transformerId): string
444
    {
445 16
        if (isset($config['persister']['service'])) {
446 1
            return $config['persister']['service'];
447
        }
448
449
        $arguments = [
450 15
            $indexRef,
451 15
            new Reference($transformerId),
452 15
            $config['model'],
453
        ];
454
455 15
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
456 1
            $abstractId = 'fos_elastica.object_serializer_persister';
457 1
            $callbackId = \sprintf('%s.serializer.callback', $indexRef);
458 1
            $arguments[] = [new Reference($callbackId), 'serialize'];
459
        } else {
460 14
            $abstractId = 'fos_elastica.object_persister';
461 14
            $mapping = $this->indexConfigs[$indexName]['mapping'];
462 14
            $argument = $mapping['properties'];
463 14
            $arguments[] = $argument;
464
        }
465
466 15
        $arguments[] = \array_intersect_key($config['persister'], \array_flip(['refresh']));
467
468 15
        $serviceId = \sprintf('fos_elastica.object_persister.%s', $indexName);
469 15
        $serviceDef = new ChildDefinition($abstractId);
470 15
        foreach ($arguments as $i => $argument) {
471 15
            $serviceDef->replaceArgument($i, $argument);
472
        }
473
474 15
        $serviceDef->addTag('fos_elastica.persister', ['index' => $indexName]);
475
476 15
        $container->setDefinition($serviceId, $serviceDef);
477
478 15
        return $serviceId;
479
    }
480
481
    /**
482
     * Loads a pager provider for a index.
483
     */
484 16
    private function loadIndexPagerProvider(array $indexConfig, ContainerBuilder $container, string $indexName): string
485
    {
486 16
        if (isset($indexConfig['provider']['service'])) {
487
            return $indexConfig['provider']['service'];
488
        }
489
490 16
        $baseConfig = $indexConfig['provider'];
491 16
        unset($baseConfig['service']);
492
493 16
        $driver = $indexConfig['driver'];
494
495 16
        switch ($driver) {
496 16
            case 'orm':
497 2
            case 'mongodb':
498 1
            case 'phpcr':
499 16
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
500 16
                $providerDef->replaceArgument(2, $indexConfig['model']);
501 16
                $providerDef->replaceArgument(3, $baseConfig);
502 16
                break;
503
            default:
504
                throw new \LogicException(\sprintf('The pager provider for driver "%s" does not exist.', $driver));
505
        }
506
507
        /* Note: provider services may conflict with "prototype.driver", if the
508
         * index and type names were "prototype" and a driver, respectively.
509
         */
510 16
        $providerId = \sprintf('fos_elastica.pager_provider.%s', $indexName);
511 16
        $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName]);
512
513 16
        $container->setDefinition($providerId, $providerDef);
514
515 16
        return $providerId;
516
    }
517
518
    /**
519
     * Loads doctrine listeners to handle indexing of new or updated objects.
520
     */
521 15
    private function loadIndexListener(array $indexConfig, ContainerBuilder $container, string $objectPersisterId, string $indexName): string
522
    {
523 15
        if (isset($indexConfig['listener']['service'])) {
524
            return $indexConfig['listener']['service'];
525
        }
526
527
        /* Note: listener services may conflict with "prototype.driver", if the
528
         * index names were "prototype" and a driver, respectively.
529
         */
530 15
        $abstractListenerId = \sprintf('fos_elastica.listener.prototype.%s', $indexConfig['driver']);
531 15
        $listenerId = \sprintf('fos_elastica.listener.%s', $indexName);
532 15
        $listenerDef = new ChildDefinition($abstractListenerId);
533 15
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
534 15
        $listenerDef->replaceArgument(3, $indexConfig['listener']['logger'] ?
535
            new Reference($indexConfig['listener']['logger']) :
536 15
            null
537
        );
538
        $listenerConfig = [
539 15
            'identifier' => $indexConfig['identifier'],
540 15
            'indexName' => $indexName,
541
        ];
542
543 15
        $tagName = null;
544 15
        switch ($indexConfig['driver']) {
545 15
            case 'orm':
546 13
                $tagName = 'doctrine.event_listener';
547 13
                break;
548 2
            case 'phpcr':
549 1
                $tagName = 'doctrine_phpcr.event_listener';
550 1
                break;
551 1
            case 'mongodb':
552 1
                $tagName = 'doctrine_mongodb.odm.event_listener';
553 1
                break;
554
        }
555
556 15
        if ($indexConfig['listener']['defer']) {
557
            $listenerDef->addTag(
558
                'kernel.event_listener',
559
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
560
            );
561
            $listenerDef->addTag(
562
                'kernel.event_listener',
563
                ['event' => 'console.terminate', 'method' => 'onTerminate']
564
            );
565
            $listenerConfig['defer'] = true;
566
        }
567
568 15
        $listenerDef->replaceArgument(2, $listenerConfig);
569
570 15
        if (null !== $tagName) {
571 15
            foreach ($this->getDoctrineEvents($indexConfig) as $event) {
572 15
                $listenerDef->addTag($tagName, ['event' => $event]);
573
            }
574
        }
575
576 15
        $container->setDefinition($listenerId, $listenerDef);
577
578 15
        return $listenerId;
579
    }
580
581
    /**
582
     * Map Elastica to Doctrine events for the current driver.
583
     */
584 15
    private function getDoctrineEvents(array $indexConfig)
585
    {
586 15
        switch ($indexConfig['driver']) {
587 15
            case 'orm':
588 13
                $eventsClass = '\Doctrine\ORM\Events';
589 13
                break;
590 2
            case 'phpcr':
591 1
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
592 1
                break;
593 1
            case 'mongodb':
594 1
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
595 1
                break;
596
            default:
597
                throw new \InvalidArgumentException(\sprintf('Cannot determine events for driver "%s"', $indexConfig['driver']));
598
        }
599
600 15
        $events = [];
601
        $eventMapping = [
602 15
            'insert' => [\constant($eventsClass.'::postPersist')],
603 15
            'update' => [\constant($eventsClass.'::postUpdate')],
604 15
            'delete' => [\constant($eventsClass.'::preRemove')],
605 15
            'flush' => [\constant($eventsClass.'::postFlush')],
606
        ];
607
608 15
        foreach ($eventMapping as $event => $doctrineEvents) {
609 15
            if (isset($indexConfig['listener'][$event]) && $indexConfig['listener'][$event]) {
610 15
                $events = \array_merge($events, $doctrineEvents);
611
            }
612
        }
613
614 15
        return $events;
615
    }
616
617
    /**
618
     * Loads a Type specific Finder.
619
     */
620 16
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, string $elasticaToModelId, Reference $indexRef, string $indexName): string
621
    {
622 16
        if (isset($typeConfig['finder']['service'])) {
623
            $finderId = $typeConfig['finder']['service'];
624
        } else {
625 16
            $finderId = \sprintf('fos_elastica.finder.%s', $indexName);
626 16
            $finderDef = new ChildDefinition('fos_elastica.finder');
627 16
            $finderDef->replaceArgument(0, $indexRef);
628 16
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
629 16
            $container->setDefinition($finderId, $finderDef);
630
        }
631
632 16
        $arguments = [$indexName, new Reference($finderId)];
633 16
        if (isset($typeConfig['repository'])) {
634 4
            $arguments[] = $typeConfig['repository'];
635
        }
636
637 16
        $container->getDefinition('fos_elastica.repository_manager')
638 16
            ->addMethodCall('addIndex', $arguments);
639
640 16
        $managerId = \sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
641 16
        $container->getDefinition($managerId)
642 16
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexName]);
643
644 16
        return $finderId;
645
    }
646
647
    /**
648
     * Loads the index manager.
649
     **/
650 22 View Code Duplication
    private function loadIndexManager(ContainerBuilder $container): void
651
    {
652 22
        $indexRefs = \array_map(function ($index) {
653 22
            return $index['reference'];
654 22
        }, $this->indexConfigs);
655
656 22
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
657 22
        $managerDef->replaceArgument(0, $indexRefs);
658 22
    }
659
660
    /**
661
     * Load index template manager.
662
     */
663 22 View Code Duplication
    private function loadIndexTemplateManager(ContainerBuilder $container): void
664
    {
665 22
        $indexTemplateRefs = \array_map(function ($index) {
666 6
            return $index['reference'];
667 22
        }, $this->indexTemplateConfigs);
668
669 22
        $managerDef = $container->getDefinition('fos_elastica.index_template_manager');
670 22
        $managerDef->replaceArgument(0, $indexTemplateRefs);
671 22
    }
672
673
    /**
674
     * Makes sure a specific driver has been loaded.
675
     */
676 16
    private function loadDriver(ContainerBuilder $container, string $driver): void
677
    {
678 16
        if (\in_array($driver, $this->loadedDrivers, true)) {
679 5
            return;
680
        }
681
682 16
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
683 16
        $loader->load($driver.'.xml');
684 16
        $this->loadedDrivers[] = $driver;
685 16
    }
686
687
    /**
688
     * Loads and configures the serializer prototype.
689
     */
690 1
    private function loadSerializer(array $config, ContainerBuilder $container): void
691
    {
692 1
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
693
694 1
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
695 1
        $serializer->setClass($config['callback_class']);
696
697 1
        if (\is_subclass_of($config['callback_class'], ContainerAwareInterface::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Symfony\Component\Depen...erAwareInterface::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
698
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
699
        }
700 1
    }
701
702
    /**
703
     * Creates a default manager alias for defined default manager or the first loaded driver.
704
     */
705 22
    private function createDefaultManagerAlias(string $defaultManager, ContainerBuilder $container): void
706
    {
707 22
        if (0 == \count($this->loadedDrivers)) {
708 6
            return;
709
        }
710
711 16
        if (\count($this->loadedDrivers) > 1
712 16
            && \in_array($defaultManager, $this->loadedDrivers, true)
713
        ) {
714
            $defaultManagerService = $defaultManager;
715
        } else {
716 16
            $defaultManagerService = $this->loadedDrivers[0];
717
        }
718
719 16
        $container->setAlias('fos_elastica.manager', \sprintf('fos_elastica.manager.%s', $defaultManagerService));
720 16
        $container->setAlias(RepositoryManagerInterface::class, 'fos_elastica.manager');
721 16
    }
722
723
    /**
724
     * Returns a reference to a client given its configured name.
725
     *
726
     * @throws \InvalidArgumentException
727
     */
728 8
    private function getClient(string $clientName): Reference
729
    {
730 8
        if (!\array_key_exists($clientName, $this->clients)) {
731
            throw new \InvalidArgumentException(\sprintf('The elastica client with name "%s" is not defined', $clientName));
732
        }
733
734 8
        return $this->clients[$clientName]['reference'];
735
    }
736
737
    private function registerMessengerConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader): void
738
    {
739
        if (!\interface_exists(MessageBusInterface::class)) {
740
            throw new LogicException('Messenger support cannot be enabled as the Messenger component is not installed. Try running "composer require symfony/messenger".');
741
        }
742
743
        $loader->load('messenger.xml');
744
745
        $container->getDefinition('fos_elastica.async_pager_persister')
746
            ->replaceArgument(2, $config['message_bus'] ? new Reference($config['message_bus']) : new Reference('messenger.default_bus'))
747
        ;
748
    }
749
}
750