Completed
Pull Request — master (#1315)
by Mathieu
03:54
created

FOSElasticaExtension   C

Complexity

Total Complexity 79

Size/Duplication

Total Lines 706
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 85.95%

Importance

Changes 0
Metric Value
wmc 79
lcom 1
cbo 8
dl 0
loc 706
ccs 257
cts 299
cp 0.8595
rs 5
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
C load() 0 44 7
A getConfiguration() 0 4 1
A loadClients() 0 23 3
B loadIndexes() 0 43 6
A loadIndexFinder() 0 16 1
F loadTypes() 0 85 13
B loadTypePersistenceIntegration() 0 20 5
B loadElasticaToModelTransformer() 0 25 3
A loadModelToElasticaTransformer() 0 19 3
B loadObjectPersister() 0 36 5
A loadTypeProvider() 0 23 2
C loadTypeListener() 0 61 9
C getDoctrineEvents() 0 32 7
B loadTypeFinder() 0 27 3
A loadIndexManager() 0 9 1
A loadDriver() 0 10 2
A loadSerializer() 0 11 2
A createDefaultManagerAlias() 0 16 4
A getClient() 0 8 2

How to fix   Complexity   

Complex Class

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 InvalidArgumentException;
15
use Symfony\Component\Config\FileLocator;
16
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\DefinitionDecorator;
19
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
22
23
class FOSElasticaExtension extends Extension
24
{
25
    /**
26
     * Definition of elastica clients as configured by this extension.
27
     *
28
     * @var array
29
     */
30
    private $clients = [];
31
32
    /**
33
     * An array of indexes as configured by the extension.
34
     *
35
     * @var array
36
     */
37
    private $indexConfigs = [];
38
39
    /**
40
     * If we've encountered a type mapped to a specific persistence driver, it will be loaded
41
     * here.
42
     *
43
     * @var array
44
     */
45
    private $loadedDrivers = [];
46
47 4
    public function load(array $configs, ContainerBuilder $container)
48
    {
49 4
        $configuration = $this->getConfiguration($configs, $container);
50 4
        $config = $this->processConfiguration($configuration, $configs);
51
52 4
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
53
54 4
        if (empty($config['clients']) || empty($config['indexes'])) {
55
            // No Clients or indexes are defined
56
            return;
57
        }
58
59 4
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener'] as $basename) {
60 4
            $loader->load(sprintf('%s.xml', $basename));
61
        }
62
63 4
        if (empty($config['default_client'])) {
64 4
            $keys = array_keys($config['clients']);
65 4
            $config['default_client'] = reset($keys);
66
        }
67
68 4
        if (empty($config['default_index'])) {
69 4
            $keys = array_keys($config['indexes']);
70 4
            $config['default_index'] = reset($keys);
71
        }
72
73 4
        if (isset($config['serializer'])) {
74 1
            $loader->load('serializer.xml');
75
76 1
            $this->loadSerializer($config['serializer'], $container);
77
        }
78
79 4
        $this->loadClients($config['clients'], $container);
80 4
        $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
81
82 4
        $this->loadIndexes($config['indexes'], $container);
83 4
        $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
84
85 4
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
86
87 4
        $this->loadIndexManager($container);
88
89 4
        $this->createDefaultManagerAlias($config['default_manager'], $container);
90 4
    }
91
92
    /**
93
     * @param array            $config
94
     * @param ContainerBuilder $container
95
     *
96
     * @return Configuration
97
     */
98 4
    public function getConfiguration(array $config, ContainerBuilder $container)
99
    {
100 4
        return new Configuration($container->getParameter('kernel.debug'));
101
    }
102
103
    /**
104
     * Loads the configured clients.
105
     *
106
     * @param array            $clients   An array of clients configurations
107
     * @param ContainerBuilder $container A ContainerBuilder instance
108
     *
109
     * @return array
110
     */
111 4
    private function loadClients(array $clients, ContainerBuilder $container)
112
    {
113 4
        foreach ($clients as $name => $clientConfig) {
114 4
            $clientId = sprintf('fos_elastica.client.%s', $name);
115
116 4
            $clientDef = new DefinitionDecorator('fos_elastica.client_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
117 4
            $clientDef->replaceArgument(0, $clientConfig);
118
119 4
            $logger = $clientConfig['connections'][0]['logger'];
120 4
            if (false !== $logger) {
121 4
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
122
            }
123
124 4
            $clientDef->addTag('fos_elastica.client');
125
126 4
            $container->setDefinition($clientId, $clientDef);
127
128 4
            $this->clients[$name] = [
129 4
                'id' => $clientId,
130 4
                'reference' => new Reference($clientId),
131
            ];
132
        }
133 4
    }
134
135
    /**
136
     * Loads the configured indexes.
137
     *
138
     * @param array            $indexes   An array of indexes configurations
139
     * @param ContainerBuilder $container A ContainerBuilder instance
140
     *
141
     * @throws \InvalidArgumentException
142
     *
143
     * @return array
144
     */
145 4
    private function loadIndexes(array $indexes, ContainerBuilder $container)
146
    {
147 4
        $indexableCallbacks = [];
148
149 4
        foreach ($indexes as $name => $index) {
150 4
            $indexId = sprintf('fos_elastica.index.%s', $name);
151 4
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
152
153 4
            $indexDef = new DefinitionDecorator('fos_elastica.index_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
154 4
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
155 4
            $indexDef->replaceArgument(0, $indexName);
156 4
            $indexDef->addTag('fos_elastica.index', [
157 4
                'name' => $name,
158
            ]);
159
160 4
            if (isset($index['client'])) {
161 2
                $client = $this->getClient($index['client']);
162
163 2
                $indexDef->setFactory([$client, 'getIndex']);
164
            }
165
166 4
            $container->setDefinition($indexId, $indexDef);
167 4
            $reference = new Reference($indexId);
168
169 4
            $this->indexConfigs[$name] = [
170 4
                'elasticsearch_name' => $indexName,
171 4
                'reference' => $reference,
172 4
                'name' => $name,
173 4
                'settings' => $index['settings'],
174 4
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
175 4
                'use_alias' => $index['use_alias'],
176
            ];
177
178 4
            if ($index['finder']) {
179
                $this->loadIndexFinder($container, $name, $reference);
180
            }
181
182 4
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
183
        }
184
185 4
        $indexable = $container->getDefinition('fos_elastica.indexable');
186 4
        $indexable->replaceArgument(0, $indexableCallbacks);
187 4
    }
188
189
    /**
190
     * Loads the configured index finders.
191
     *
192
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
193
     * @param string                                                  $name      The index name
194
     * @param Reference                                               $index     Reference to the related index
195
     *
196
     * @return string
197
     */
198
    private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
199
    {
200
        /* Note: transformer services may conflict with "collection.index", if
201
         * an index and type names were "collection" and an index, respectively.
202
         */
203
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
204
        $transformerDef = new DefinitionDecorator('fos_elastica.elastica_to_model_transformer.collection');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
205
        $container->setDefinition($transformerId, $transformerDef);
206
207
        $finderId = sprintf('fos_elastica.finder.%s', $name);
208
        $finderDef = new DefinitionDecorator('fos_elastica.finder');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
209
        $finderDef->replaceArgument(0, $index);
210
        $finderDef->replaceArgument(1, new Reference($transformerId));
211
212
        $container->setDefinition($finderId, $finderDef);
213
    }
214
215
    /**
216
     * Loads the configured types.
217
     *
218
     * @param array            $types
219
     * @param ContainerBuilder $container
220
     * @param array            $indexConfig
221
     * @param array            $indexableCallbacks
222
     */
223 4
    private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
224
    {
225 4
        foreach ($types as $name => $type) {
226 4
            $indexName = $indexConfig['name'];
227
228 4
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
229 4
            $typeDef = new DefinitionDecorator('fos_elastica.type_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
230 4
            $typeDef->setFactory([$indexConfig['reference'], 'getType']);
231 4
            $typeDef->replaceArgument(0, $name);
232
233 4
            $container->setDefinition($typeId, $typeDef);
234
235
            $typeConfig = [
236 4
                'name' => $name,
237
                'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch
238
                'config' => [],
239
            ];
240
241
            foreach ([
242 4
                'dynamic_templates',
243
                'properties',
244
                '_all',
245
                '_id',
246
                '_parent',
247
                '_routing',
248
                '_source',
249
            ] as $field) {
250 4
                if (isset($type[$field])) {
251 4
                    $typeConfig['mapping'][$field] = $type[$field];
252
                }
253
            }
254
255
            foreach ([
256 4
                'persistence',
257
                'serializer',
258
                'analyzer',
259
                'search_analyzer',
260
                'dynamic',
261
                'date_detection',
262
                'dynamic_date_formats',
263
                'numeric_detection',
264
            ] as $field) {
265 4
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
266 4
                    $type[$field] :
267 4
                    null;
268
            }
269
270 4
            $this->indexConfigs[$indexName]['types'][$name] = $typeConfig;
271
272 4
            if (isset($type['persistence'])) {
273 4
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
274
275 4
                $typeConfig['persistence'] = $type['persistence'];
276
            }
277
278 4
            if (isset($type['_parent'])) {
279
                // _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence`
280 1
                unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']);
281
            }
282
283 4
            if (isset($type['indexable_callback'])) {
284 1
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback'];
285
            }
286
287 4
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
288 1
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
289 1
                $typeSerializerDef = new DefinitionDecorator('fos_elastica.serializer_callback_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
290
291 1
                if (isset($type['serializer']['groups'])) {
292 1
                    $typeSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]);
293
                }
294
295 1
                if (isset($type['serializer']['serialize_null'])) {
296 1
                    $typeSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]);
297
                }
298
299 1
                if (isset($type['serializer']['version'])) {
300 1
                    $typeSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]);
301
                }
302
303 1
                $typeDef->addMethodCall('setSerializer', [[new Reference($typeSerializerId), 'serialize']]);
304 4
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
305
            }
306
        }
307 4
    }
308
309
    /**
310
     * Loads the optional provider and finder for a type.
311
     *
312
     * @param array            $typeConfig
313
     * @param ContainerBuilder $container
314
     * @param Reference        $typeRef
315
     * @param string           $indexName
316
     * @param string           $typeName
317
     */
318 4
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
319
    {
320 4
        if (isset($typeConfig['driver'])) {
321 4
            $this->loadDriver($container, $typeConfig['driver']);
322
        }
323
324 4
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
325 4
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
326 4
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
327
328 4
        if (isset($typeConfig['provider'])) {
329 4
            $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
330
        }
331 4
        if (isset($typeConfig['finder'])) {
332 4
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
333
        }
334 4
        if (isset($typeConfig['listener'])) {
335 4
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
336
        }
337 4
    }
338
339
    /**
340
     * Creates and loads an ElasticaToModelTransformer.
341
     *
342
     * @param array            $typeConfig
343
     * @param ContainerBuilder $container
344
     * @param string           $indexName
345
     * @param string           $typeName
346
     *
347
     * @return string
348
     */
349 4
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
350
    {
351 4
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
352 1
            return $typeConfig['elastica_to_model_transformer']['service'];
353
        }
354
355
        /* Note: transformer services may conflict with "prototype.driver", if
356
         * the index and type names were "prototype" and a driver, respectively.
357
         */
358 3
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
359 3
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
360 3
        $serviceDef = new DefinitionDecorator($abstractId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
361 3
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['type' => $typeName, 'index' => $indexName]);
362
363
        // Doctrine has a mandatory service as first argument
364 3
        $argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
365
366 3
        $serviceDef->replaceArgument($argPos, $typeConfig['model']);
367 3
        $serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], [
368 3
            'identifier' => $typeConfig['identifier'],
369
        ]));
370 3
        $container->setDefinition($serviceId, $serviceDef);
371
372 3
        return $serviceId;
373
    }
374
375
    /**
376
     * Creates and loads a ModelToElasticaTransformer for an index/type.
377
     *
378
     * @param array            $typeConfig
379
     * @param ContainerBuilder $container
380
     * @param string           $indexName
381
     * @param string           $typeName
382
     *
383
     * @return string
384
     */
385 4
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
386
    {
387 4
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
388
            return $typeConfig['model_to_elastica_transformer']['service'];
389
        }
390
391 4
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
392 1
            'fos_elastica.model_to_elastica_identifier_transformer' :
393 4
            'fos_elastica.model_to_elastica_transformer';
394
395 4
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
396 4
        $serviceDef = new DefinitionDecorator($abstractId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
397 4
        $serviceDef->replaceArgument(0, [
398 4
            'identifier' => $typeConfig['identifier'],
399
        ]);
400 4
        $container->setDefinition($serviceId, $serviceDef);
401
402 4
        return $serviceId;
403
    }
404
405
    /**
406
     * Creates and loads an object persister for a type.
407
     *
408
     * @param array            $typeConfig
409
     * @param Reference        $typeRef
410
     * @param ContainerBuilder $container
411
     * @param string           $indexName
412
     * @param string           $typeName
413
     * @param string           $transformerId
414
     *
415
     * @return string
416
     */
417 4
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
418
    {
419 4
        if (isset($typeConfig['persister']['service'])) {
420 1
            return $typeConfig['persister']['service'];
421
        }
422
423
        $arguments = [
424 3
            $typeRef,
425 3
            new Reference($transformerId),
426 3
            $typeConfig['model'],
427
        ];
428
429 3
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
430 1
            $abstractId = 'fos_elastica.object_serializer_persister';
431 1
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
432 1
            $arguments[] = [new Reference($callbackId), 'serialize'];
433
        } else {
434 2
            $abstractId = 'fos_elastica.object_persister';
435 2
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
436 2
            $argument = $mapping['properties'];
437 2
            if (isset($mapping['_parent'])) {
438 1
                $argument['_parent'] = $mapping['_parent'];
439
            }
440 2
            $arguments[] = $argument;
441
        }
442
443 3
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
444 3
        $serviceDef = new DefinitionDecorator($abstractId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
445 3
        foreach ($arguments as $i => $argument) {
446 3
            $serviceDef->replaceArgument($i, $argument);
447
        }
448
449 3
        $container->setDefinition($serviceId, $serviceDef);
450
451 3
        return $serviceId;
452
    }
453
454
    /**
455
     * Loads a provider for a type.
456
     *
457
     * @param array            $typeConfig
458
     * @param ContainerBuilder $container
459
     * @param string           $objectPersisterId
460
     * @param string           $indexName
461
     * @param string           $typeName
462
     *
463
     * @return string
464
     */
465 4
    private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
466
    {
467 4
        if (isset($typeConfig['provider']['service'])) {
468
            return $typeConfig['provider']['service'];
469
        }
470
471
        /* Note: provider services may conflict with "prototype.driver", if the
472
         * index and type names were "prototype" and a driver, respectively.
473
         */
474 4
        $providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName);
475 4
        $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.'.$typeConfig['driver']);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
476 4
        $providerDef->addTag('fos_elastica.provider', ['index' => $indexName, 'type' => $typeName]);
477 4
        $providerDef->replaceArgument(0, new Reference($objectPersisterId));
478 4
        $providerDef->replaceArgument(2, $typeConfig['model']);
479
        // Propel provider can simply ignore Doctrine-specific options
480 4
        $providerDef->replaceArgument(3, array_merge(array_diff_key($typeConfig['provider'], ['service' => 1]), [
481 4
            'indexName' => $indexName,
482 4
            'typeName' => $typeName,
483
        ]));
484 4
        $container->setDefinition($providerId, $providerDef);
485
486 4
        return $providerId;
487
    }
488
489
    /**
490
     * Loads doctrine listeners to handle indexing of new or updated objects.
491
     *
492
     * @param array            $typeConfig
493
     * @param ContainerBuilder $container
494
     * @param string           $objectPersisterId
495
     * @param string           $indexName
496
     * @param string           $typeName
497
     *
498
     * @return string
499
     */
500 4
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
501
    {
502 4
        if (isset($typeConfig['listener']['service'])) {
503
            return $typeConfig['listener']['service'];
504
        }
505
506
        /* Note: listener services may conflict with "prototype.driver", if the
507
         * index and type names were "prototype" and a driver, respectively.
508
         */
509 4
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
510 4
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
511 4
        $listenerDef = new DefinitionDecorator($abstractListenerId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
512 4
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
513 4
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
514
            new Reference($typeConfig['listener']['logger']) :
515 4
            null
516
        );
517
        $listenerConfig = [
518 4
            'identifier' => $typeConfig['identifier'],
519 4
            'indexName' => $indexName,
520 4
            'typeName' => $typeName,
521
        ];
522
523 4
        $tagName = null;
524 4
        switch ($typeConfig['driver']) {
525 4
            case 'orm':
526 4
                $tagName = 'doctrine.event_listener';
527 4
                break;
528
            case 'phpcr':
529
                $tagName = 'doctrine_phpcr.event_listener';
530
                break;
531
            case 'mongodb':
532
                $tagName = 'doctrine_mongodb.odm.event_listener';
533
                break;
534
        }
535
536 4
        if ($typeConfig['listener']['defer']) {
537
            $listenerDef->setPublic(true);
538
            $listenerDef->addTag(
539
                'kernel.event_listener',
540
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
541
            );
542
            $listenerDef->addTag(
543
                'kernel.event_listener',
544
                ['event' => 'console.terminate', 'method' => 'onTerminate']
545
            );
546
            $listenerConfig['defer'] = true;
547
        }
548
549 4
        $listenerDef->replaceArgument(2, $listenerConfig);
550
551 4
        if (null !== $tagName) {
552 4
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
553 4
                $listenerDef->addTag($tagName, ['event' => $event]);
554
            }
555
        }
556
557 4
        $container->setDefinition($listenerId, $listenerDef);
558
559 4
        return $listenerId;
560
    }
561
562
    /**
563
     * Map Elastica to Doctrine events for the current driver.
564
     */
565 4
    private function getDoctrineEvents(array $typeConfig)
566
    {
567 4
        switch ($typeConfig['driver']) {
568 4
            case 'orm':
569 4
                $eventsClass = '\Doctrine\ORM\Events';
570 4
                break;
571
            case 'phpcr':
572
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
573
                break;
574
            case 'mongodb':
575
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
576
                break;
577
            default:
578
                throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
579
        }
580
581 4
        $events = [];
582
        $eventMapping = [
583 4
            'insert' => [constant($eventsClass.'::postPersist')],
584 4
            'update' => [constant($eventsClass.'::postUpdate')],
585 4
            'delete' => [constant($eventsClass.'::preRemove')],
586 4
            'flush' => [constant($eventsClass.'::postFlush')],
587
        ];
588
589 4
        foreach ($eventMapping as $event => $doctrineEvents) {
590 4
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
591 4
                $events = array_merge($events, $doctrineEvents);
592
            }
593
        }
594
595 4
        return $events;
596
    }
597
598
    /**
599
     * Loads a Type specific Finder.
600
     *
601
     * @param array            $typeConfig
602
     * @param ContainerBuilder $container
603
     * @param string           $elasticaToModelId
604
     * @param Reference        $typeRef
605
     * @param string           $indexName
606
     * @param string           $typeName
607
     *
608
     * @return string
609
     */
610 4
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
611
    {
612 4
        if (isset($typeConfig['finder']['service'])) {
613
            $finderId = $typeConfig['finder']['service'];
614
        } else {
615 4
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
616 4
            $finderDef = new DefinitionDecorator('fos_elastica.finder');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
617 4
            $finderDef->replaceArgument(0, $typeRef);
618 4
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
619 4
            $container->setDefinition($finderId, $finderDef);
620
        }
621
622 4
        $indexTypeName = "$indexName/$typeName";
623 4
        $arguments = [$indexTypeName, new Reference($finderId)];
624 4
        if (isset($typeConfig['repository'])) {
625 1
            $arguments[] = $typeConfig['repository'];
626
        }
627
628 4
        $container->getDefinition('fos_elastica.repository_manager')
629 4
            ->addMethodCall('addType', $arguments);
630
631 4
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
632 4
        $container->getDefinition($managerId)
633 4
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]);
634
635 4
        return $finderId;
636
    }
637
638
    /**
639
     * Loads the index manager.
640
     *
641
     * @param ContainerBuilder $container
642
     **/
643
    private function loadIndexManager(ContainerBuilder $container)
644
    {
645 4
        $indexRefs = array_map(function ($index) {
646 4
            return $index['reference'];
647 4
        }, $this->indexConfigs);
648
649 4
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
650 4
        $managerDef->replaceArgument(0, $indexRefs);
651 4
    }
652
653
    /**
654
     * Makes sure a specific driver has been loaded.
655
     *
656
     * @param ContainerBuilder $container
657
     * @param string           $driver
658
     */
659 4
    private function loadDriver(ContainerBuilder $container, $driver)
660
    {
661 4
        if (in_array($driver, $this->loadedDrivers)) {
662 3
            return;
663
        }
664
665 4
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
666 4
        $loader->load($driver.'.xml');
667 4
        $this->loadedDrivers[] = $driver;
668 4
    }
669
670
    /**
671
     * Loads and configures the serializer prototype.
672
     *
673
     * @param array            $config
674
     * @param ContainerBuilder $container
675
     */
676 1
    private function loadSerializer($config, ContainerBuilder $container)
677
    {
678 1
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
679
680 1
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
681 1
        $serializer->setClass($config['callback_class']);
682
683 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...
684
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
685
        }
686 1
    }
687
688
    /**
689
     * Creates a default manager alias for defined default manager or the first loaded driver.
690
     *
691
     * @param string           $defaultManager
692
     * @param ContainerBuilder $container
693
     */
694 4
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
695
    {
696 4
        if (0 == count($this->loadedDrivers)) {
697
            return;
698
        }
699
700 4
        if (count($this->loadedDrivers) > 1
701 4
            && in_array($defaultManager, $this->loadedDrivers)
702
        ) {
703
            $defaultManagerService = $defaultManager;
704
        } else {
705 4
            $defaultManagerService = $this->loadedDrivers[0];
706
        }
707
708 4
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
709 4
    }
710
711
    /**
712
     * Returns a reference to a client given its configured name.
713
     *
714
     * @param string $clientName
715
     *
716
     * @return Reference
717
     *
718
     * @throws \InvalidArgumentException
719
     */
720 2
    private function getClient($clientName)
721
    {
722 2
        if (!array_key_exists($clientName, $this->clients)) {
723
            throw new InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
724
        }
725
726 2
        return $this->clients[$clientName]['reference'];
727
    }
728
}
729