Completed
Pull Request — master (#1569)
by
unknown
03:09
created

FOSElasticaExtension   F

Complexity

Total Complexity 95

Size/Duplication

Total Lines 751
Duplicated Lines 5.19 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 87.64%

Importance

Changes 0
Metric Value
wmc 95
lcom 1
cbo 9
dl 39
loc 751
ccs 319
cts 364
cp 0.8764
rs 1.849
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
B load() 0 64 8
A getConfiguration() 0 4 1
A loadClients() 0 24 3
B loadIndexes() 5 47 7
A loadIndexTemplates() 4 36 4
A loadIndexFinder() 0 9 1
C loadTypes() 0 67 11
B buildCallback() 0 25 7
A transformServiceReference() 0 4 2
B loadTypePersistenceIntegration() 0 20 6
A loadElasticaToModelTransformer() 0 22 2
A loadModelToElasticaTransformer() 0 20 3
A loadObjectPersister() 0 37 4
B loadTypePagerProvider() 12 44 5
B loadTypeListener() 0 60 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 19 4
A getClient() 0 8 2

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