Completed
Push — master ( 0aa154...6fc129 )
by Maksim
05:50
created

FOSElasticaExtension::loadIndexManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
c 0
b 0
f 0
ccs 6
cts 6
cp 1
rs 9.6666
cc 1
eloc 6
nc 1
nop 1
crap 1
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 Symfony\Component\Config\FileLocator;
15
use Pagerfanta\Pagerfanta;
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 12
    public function load(array $configs, ContainerBuilder $container)
48
    {
49 12
        $configuration = $this->getConfiguration($configs, $container);
50 12
        $config = $this->processConfiguration($configuration, $configs);
51
52 12
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
53
54 12
        if (empty($config['clients']) || empty($config['indexes'])) {
55
            // No Clients or indexes are defined
56
            return;
57
        }
58
59 12
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener'] as $basename) {
60 12
            $loader->load(sprintf('%s.xml', $basename));
61
        }
62
63 12
        if (empty($config['default_client'])) {
64 12
            $keys = array_keys($config['clients']);
65 12
            $config['default_client'] = reset($keys);
66
        }
67
68 12
        if (empty($config['default_index'])) {
69 12
            $keys = array_keys($config['indexes']);
70 12
            $config['default_index'] = reset($keys);
71
        }
72
73 12
        if (isset($config['serializer'])) {
74 1
            $loader->load('serializer.xml');
75
76 1
            $this->loadSerializer($config['serializer'], $container);
77
        }
78
79 12
        $this->loadClients($config['clients'], $container);
80 12
        $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
81
82 12
        $this->loadIndexes($config['indexes'], $container);
83 12
        $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
84 12
        $container->setParameter('fos_elastica.default_index', $config['default_index']);
85
86 12
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
87
88 12
        $this->loadIndexManager($container);
89
90 12
        $this->createDefaultManagerAlias($config['default_manager'], $container);
91 12
    }
92
93
    /**
94
     * @param array            $config
95
     * @param ContainerBuilder $container
96
     *
97
     * @return Configuration
98
     */
99 12
    public function getConfiguration(array $config, ContainerBuilder $container)
100
    {
101 12
        return new Configuration($container->getParameter('kernel.debug'));
102
    }
103
104
    /**
105
     * Loads the configured clients.
106
     *
107
     * @param array            $clients   An array of clients configurations
108
     * @param ContainerBuilder $container A ContainerBuilder instance
109
     *
110
     * @return array
111
     */
112 12
    private function loadClients(array $clients, ContainerBuilder $container)
113
    {
114 12
        foreach ($clients as $name => $clientConfig) {
115 12
            $clientId = sprintf('fos_elastica.client.%s', $name);
116
117 12
            $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...
118 12
            $clientDef->replaceArgument(0, $clientConfig);
119
120 12
            $logger = $clientConfig['connections'][0]['logger'];
121 12
            if (false !== $logger) {
122 12
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
123
            }
124
125 12
            $clientDef->addTag('fos_elastica.client');
126
127 12
            $container->setDefinition($clientId, $clientDef);
128
129 12
            $this->clients[$name] = [
130 12
                'id' => $clientId,
131 12
                'reference' => new Reference($clientId),
132
            ];
133
        }
134 12
    }
135
136
    /**
137
     * Loads the configured indexes.
138
     *
139
     * @param array            $indexes   An array of indexes configurations
140
     * @param ContainerBuilder $container A ContainerBuilder instance
141
     *
142
     * @throws \InvalidArgumentException
143
     *
144
     * @return array
145
     */
146 12
    private function loadIndexes(array $indexes, ContainerBuilder $container)
147
    {
148 12
        $indexableCallbacks = [];
149
150 12
        foreach ($indexes as $name => $index) {
151 12
            $indexId = sprintf('fos_elastica.index.%s', $name);
152 12
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
153
154 12
            $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...
155 12
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
156 12
            $indexDef->replaceArgument(0, $indexName);
157 12
            $indexDef->addTag('fos_elastica.index', [
158 12
                'name' => $name,
159
            ]);
160
161 12
            if (isset($index['client'])) {
162 2
                $client = $this->getClient($index['client']);
163
164 2
                $indexDef->setFactory([$client, 'getIndex']);
165
            }
166
167 12
            $container->setDefinition($indexId, $indexDef);
168 12
            $reference = new Reference($indexId);
169
170 12
            $this->indexConfigs[$name] = [
171 12
                'elasticsearch_name' => $indexName,
172 12
                'reference' => $reference,
173 12
                'name' => $name,
174 12
                'settings' => $index['settings'],
175 12
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
176 12
                'use_alias' => $index['use_alias'],
177
            ];
178
179 12
            if ($index['finder']) {
180
                $this->loadIndexFinder($container, $name, $reference);
181
            }
182
183 12
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
184
        }
185
186 12
        $indexable = $container->getDefinition('fos_elastica.indexable');
187 12
        $indexable->replaceArgument(0, $indexableCallbacks);
188 12
    }
189
190
    /**
191
     * Loads the configured index finders.
192
     *
193
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
194
     * @param string                                                  $name      The index name
195
     * @param Reference                                               $index     Reference to the related index
196
     *
197
     * @return string
198
     */
199
    private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
200
    {
201
        /* Note: transformer services may conflict with "collection.index", if
202
         * an index and type names were "collection" and an index, respectively.
203
         */
204
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
205
        $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...
206
        $container->setDefinition($transformerId, $transformerDef);
207
208
        $finderId = sprintf('fos_elastica.finder.%s', $name);
209
        $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...
210
        $finderDef->replaceArgument(0, $index);
211
        $finderDef->replaceArgument(1, new Reference($transformerId));
212
213
        $container->setDefinition($finderId, $finderDef);
214
    }
215
216
    /**
217
     * Loads the configured types.
218
     *
219
     * @param array            $types
220
     * @param ContainerBuilder $container
221
     * @param array            $indexConfig
222
     * @param array            $indexableCallbacks
223
     */
224 12
    private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
225
    {
226 12
        foreach ($types as $name => $type) {
227 12
            $indexName = $indexConfig['name'];
228
229 12
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
230 12
            $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...
231 12
            $typeDef->setFactory([$indexConfig['reference'], 'getType']);
232 12
            $typeDef->replaceArgument(0, $name);
233
234 12
            $container->setDefinition($typeId, $typeDef);
235
236
            $typeConfig = [
237 12
                'name' => $name,
238
                'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch
239
                'config' => [],
240
            ];
241
242
            foreach ([
243 12
                'dynamic_templates',
244
                'properties',
245
                '_all',
246
                '_id',
247
                '_parent',
248
                '_routing',
249
                '_source',
250
            ] as $field) {
251 12
                if (isset($type[$field])) {
252 12
                    $typeConfig['mapping'][$field] = $type[$field];
253
                }
254
            }
255
256
            foreach ([
257 12
                'persistence',
258
                'serializer',
259
                'analyzer',
260
                'search_analyzer',
261
                'dynamic',
262
                'date_detection',
263
                'dynamic_date_formats',
264
                'numeric_detection',
265
            ] as $field) {
266 12
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
267 12
                    $type[$field] :
268 12
                    null;
269
            }
270
271 12
            $this->indexConfigs[$indexName]['types'][$name] = $typeConfig;
272
273 12
            if (isset($type['persistence'])) {
274 11
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
275
276 11
                $typeConfig['persistence'] = $type['persistence'];
277
            }
278
279 12
            if (isset($type['_parent'])) {
280
                // _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence`
281 2
                unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']);
282
            }
283
284 12
            if (isset($type['indexable_callback'])) {
285 1
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback'];
286
            }
287
288 12
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
289 1
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
290 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...
291
292 1
                if (isset($type['serializer']['groups'])) {
293 1
                    $typeSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]);
294
                }
295
296 1
                if (isset($type['serializer']['serialize_null'])) {
297 1
                    $typeSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]);
298
                }
299
300 1
                if (isset($type['serializer']['version'])) {
301 1
                    $typeSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]);
302
                }
303
304 1
                $typeDef->addMethodCall('setSerializer', [[new Reference($typeSerializerId), 'serialize']]);
305 12
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
306
            }
307
        }
308 12
    }
309
310
    /**
311
     * Loads the optional provider and finder for a type.
312
     *
313
     * @param array            $typeConfig
314
     * @param ContainerBuilder $container
315
     * @param Reference        $typeRef
316
     * @param string           $indexName
317
     * @param string           $typeName
318
     */
319 11
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
320
    {
321 11
        if (isset($typeConfig['driver'])) {
322 11
            $this->loadDriver($container, $typeConfig['driver']);
323
        }
324
325 11
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
326 11
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
327 11
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
328
329 11
        if (isset($typeConfig['provider'])) {
330 11
            $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
331
332 11
            if (isset($typeConfig['provider']['pager_provider']) && $typeConfig['provider']['pager_provider']) {
333 6
                if (!class_exists(Pagerfanta::class)) {
334
                    throw new \InvalidArgumentException('A pager provider needs "pagerfanta/pagerfanta:^1"  to be installed.');
335
                }
336
337 6
                $this->loadTypePagerProvider($typeConfig, $container, $indexName, $typeName);
338
            }
339
        }
340 11
        if (isset($typeConfig['finder'])) {
341 11
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
342
        }
343 11
        if (isset($typeConfig['listener'])) {
344 11
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
345
        }
346 11
    }
347
348
    /**
349
     * Creates and loads an ElasticaToModelTransformer.
350
     *
351
     * @param array            $typeConfig
352
     * @param ContainerBuilder $container
353
     * @param string           $indexName
354
     * @param string           $typeName
355
     *
356
     * @return string
357
     */
358 11
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
359
    {
360 11
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
361 1
            return $typeConfig['elastica_to_model_transformer']['service'];
362
        }
363
364
        /* Note: transformer services may conflict with "prototype.driver", if
365
         * the index and type names were "prototype" and a driver, respectively.
366
         */
367 10
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
368 10
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
369 10
        $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...
370 10
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['type' => $typeName, 'index' => $indexName]);
371
372
        // Doctrine has a mandatory service as first argument
373 10
        $argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
374
375 10
        $serviceDef->replaceArgument($argPos, $typeConfig['model']);
376 10
        $serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], [
377 10
            'identifier' => $typeConfig['identifier'],
378
        ]));
379 10
        $container->setDefinition($serviceId, $serviceDef);
380
381 10
        return $serviceId;
382
    }
383
384
    /**
385
     * Creates and loads a ModelToElasticaTransformer for an index/type.
386
     *
387
     * @param array            $typeConfig
388
     * @param ContainerBuilder $container
389
     * @param string           $indexName
390
     * @param string           $typeName
391
     *
392
     * @return string
393
     */
394 11
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
395
    {
396 11
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
397
            return $typeConfig['model_to_elastica_transformer']['service'];
398
        }
399
400 11
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
401 1
            'fos_elastica.model_to_elastica_identifier_transformer' :
402 11
            'fos_elastica.model_to_elastica_transformer';
403
404 11
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
405 11
        $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...
406 11
        $serviceDef->replaceArgument(0, [
407 11
            'identifier' => $typeConfig['identifier'],
408
        ]);
409 11
        $container->setDefinition($serviceId, $serviceDef);
410
411 11
        return $serviceId;
412
    }
413
414
    /**
415
     * Creates and loads an object persister for a type.
416
     *
417
     * @param array            $typeConfig
418
     * @param Reference        $typeRef
419
     * @param ContainerBuilder $container
420
     * @param string           $indexName
421
     * @param string           $typeName
422
     * @param string           $transformerId
423
     *
424
     * @return string
425
     */
426 11
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
427
    {
428 11
        if (isset($typeConfig['persister']['service'])) {
429 1
            return $typeConfig['persister']['service'];
430
        }
431
432
        $arguments = [
433 10
            $typeRef,
434 10
            new Reference($transformerId),
435 10
            $typeConfig['model'],
436
        ];
437
438 10
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
439 1
            $abstractId = 'fos_elastica.object_serializer_persister';
440 1
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
441 1
            $arguments[] = [new Reference($callbackId), 'serialize'];
442
        } else {
443 9
            $abstractId = 'fos_elastica.object_persister';
444 9
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
445 9
            $argument = $mapping['properties'];
446 9
            if (isset($mapping['_parent'])) {
447 1
                $argument['_parent'] = $mapping['_parent'];
448
            }
449 9
            $arguments[] = $argument;
450
        }
451
452 10
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
453 10
        $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...
454 10
        foreach ($arguments as $i => $argument) {
455 10
            $serviceDef->replaceArgument($i, $argument);
456
        }
457
458 10
        $serviceDef->addTag('fos_elastica.persister', ['index' => $indexName, 'type' => $typeName]);
459
460 10
        $container->setDefinition($serviceId, $serviceDef);
461
462 10
        return $serviceId;
463
    }
464
465
    /**
466
     * Loads a provider for a type.
467
     *
468
     * @param array            $typeConfig
469
     * @param ContainerBuilder $container
470
     * @param string           $objectPersisterId
471
     * @param string           $indexName
472
     * @param string           $typpeName
0 ignored issues
show
Documentation introduced by
There is no parameter named $typpeName. Did you maybe mean $typeName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
473
     *
474
     * @return string
475
     */
476 11
    private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
477
    {
478 11
        if (isset($typeConfig['provider']['service'])) {
479
            return $typeConfig['provider']['service'];
480
        }
481
482
        /* Note: provider services may conflict with "prototype.driver", if the
483
         * index and type names were "prototype" and a driver, respectively.
484
         */
485 11
        $providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName);
486 11
        $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...
487 11
        $providerDef->addTag('fos_elastica.provider', ['index' => $indexName, 'type' => $typeName]);
488 11
        $providerDef->replaceArgument(0, new Reference($objectPersisterId));
489 11
        $providerDef->replaceArgument(2, $typeConfig['model']);
490
        // Propel provider can simply ignore Doctrine-specific options
491 11
        $providerDef->replaceArgument(3, array_merge(array_diff_key($typeConfig['provider'], ['service' => 1]), [
492 11
            'indexName' => $indexName,
493 11
            'typeName' => $typeName,
494
        ]));
495 11
        $container->setDefinition($providerId, $providerDef);
496
497 11
        return $providerId;
498
    }
499
500
    /**
501
     * Loads a pager provider for a type.
502
     *
503
     * @param array            $typeConfig
504
     * @param ContainerBuilder $container
505
     * @param string           $indexName
506
     * @param string           $typeName
507
     *
508
     * @return string
509
     */
510 6
    private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
511
    {
512
//     TODO don't forget to uncomment in master branch
513
//        if (isset($typeConfig['provider']['service'])) {
514
//            return $typeConfig['provider']['service'];
515
//        }
516
517 6
        $baseConfig = $typeConfig['provider'];
518 6
        unset($baseConfig['service']);
519
520 6
        $driver = $typeConfig['driver'];
521
522
        switch ($driver) {
523 6
            case 'orm':
524 2
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$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...
525 2
                $providerDef->replaceArgument(2, $typeConfig['model']);
526 2
                $providerDef->replaceArgument(3, $baseConfig);
527
528 2
                break;
529 4 View Code Duplication
            case 'mongodb':
530
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$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...
531
                $providerDef->replaceArgument(2, $typeConfig['model']);
532
                $providerDef->replaceArgument(3, $baseConfig);
533
534
                break;
535 4 View Code Duplication
            case 'phpcr':
536 1
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$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...
537 1
                $providerDef->replaceArgument(2, $typeConfig['model']);
538 1
                $providerDef->replaceArgument(3, $baseConfig);
539
540 1
                break;
541 3 View Code Duplication
            case 'propel':
542 3
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$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...
543 3
                $providerDef->replaceArgument(0, $typeConfig['model']);
544 3
                $providerDef->replaceArgument(1, $baseConfig);
545
546 3
                break;
547
            default:
548
                throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver));
549
        }
550
551
        /* Note: provider services may conflict with "prototype.driver", if the
552
         * index and type names were "prototype" and a driver, respectively.
553
         */
554 6
        $providerId = sprintf('fos_elastica.pager_provider.%s.%s', $indexName, $typeName);
555 6
        $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName, 'type' => $typeName]);
556
557 6
        $container->setDefinition($providerId, $providerDef);
558
559 6
        return $providerId;
560
    }
561
562
    /**
563
     * Loads doctrine listeners to handle indexing of new or updated objects.
564
     *
565
     * @param array            $typeConfig
566
     * @param ContainerBuilder $container
567
     * @param string           $objectPersisterId
568
     * @param string           $indexName
569
     * @param string           $typeName
570
     *
571
     * @return string
572
     */
573 11
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
574
    {
575 11
        if (isset($typeConfig['listener']['service'])) {
576
            return $typeConfig['listener']['service'];
577
        }
578
579
        /* Note: listener services may conflict with "prototype.driver", if the
580
         * index and type names were "prototype" and a driver, respectively.
581
         */
582 11
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
583 11
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
584 11
        $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...
585 11
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
586 11
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
587
            new Reference($typeConfig['listener']['logger']) :
588 11
            null
589
        );
590
        $listenerConfig = [
591 11
            'identifier' => $typeConfig['identifier'],
592 11
            'indexName' => $indexName,
593 11
            'typeName' => $typeName,
594
        ];
595
596 11
        $tagName = null;
597 11
        switch ($typeConfig['driver']) {
598 11
            case 'orm':
599 7
                $tagName = 'doctrine.event_listener';
600 7
                break;
601 4
            case 'phpcr':
602 1
                $tagName = 'doctrine_phpcr.event_listener';
603 1
                break;
604 3
            case 'mongodb':
605
                $tagName = 'doctrine_mongodb.odm.event_listener';
606
                break;
607
        }
608
609 11
        if ($typeConfig['listener']['defer']) {
610
            $listenerDef->setPublic(true);
611
            $listenerDef->addTag(
612
                'kernel.event_listener',
613
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
614
            );
615
            $listenerDef->addTag(
616
                'kernel.event_listener',
617
                ['event' => 'console.terminate', 'method' => 'onTerminate']
618
            );
619
            $listenerConfig['defer'] = true;
620
        }
621
622 11
        $listenerDef->replaceArgument(2, $listenerConfig);
623
624 11
        if (null !== $tagName) {
625 8
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
626 8
                $listenerDef->addTag($tagName, ['event' => $event]);
627
            }
628
        }
629
630 11
        $container->setDefinition($listenerId, $listenerDef);
631
632 11
        return $listenerId;
633
    }
634
635
    /**
636
     * Map Elastica to Doctrine events for the current driver.
637
     */
638 8
    private function getDoctrineEvents(array $typeConfig)
639
    {
640 8
        switch ($typeConfig['driver']) {
641 8
            case 'orm':
642 7
                $eventsClass = '\Doctrine\ORM\Events';
643 7
                break;
644 1
            case 'phpcr':
645 1
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
646 1
                break;
647
            case 'mongodb':
648
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
649
                break;
650
            default:
651
                throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
652
        }
653
654 8
        $events = [];
655
        $eventMapping = [
656 8
            'insert' => [constant($eventsClass.'::postPersist')],
657 8
            'update' => [constant($eventsClass.'::postUpdate')],
658 8
            'delete' => [constant($eventsClass.'::preRemove')],
659 8
            'flush' => [constant($eventsClass.'::postFlush')],
660
        ];
661
662 8
        foreach ($eventMapping as $event => $doctrineEvents) {
663 8
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
664 8
                $events = array_merge($events, $doctrineEvents);
665
            }
666
        }
667
668 8
        return $events;
669
    }
670
671
    /**
672
     * Loads a Type specific Finder.
673
     *
674
     * @param array            $typeConfig
675
     * @param ContainerBuilder $container
676
     * @param string           $elasticaToModelId
677
     * @param Reference        $typeRef
678
     * @param string           $indexName
679
     * @param string           $typeName
680
     *
681
     * @return string
682
     */
683 11
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
684
    {
685 11
        if (isset($typeConfig['finder']['service'])) {
686
            $finderId = $typeConfig['finder']['service'];
687
        } else {
688 11
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
689 11
            $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...
690 11
            $finderDef->replaceArgument(0, $typeRef);
691 11
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
692 11
            $container->setDefinition($finderId, $finderDef);
693
        }
694
695 11
        $indexTypeName = "$indexName/$typeName";
696 11
        $arguments = [$indexTypeName, new Reference($finderId)];
697 11
        if (isset($typeConfig['repository'])) {
698 1
            $arguments[] = $typeConfig['repository'];
699
        }
700
701 11
        $container->getDefinition('fos_elastica.repository_manager')
702 11
            ->addMethodCall('addType', $arguments);
703
704 11
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
705 11
        $container->getDefinition($managerId)
706 11
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]);
707
708 11
        return $finderId;
709
    }
710
711
    /**
712
     * Loads the index manager.
713
     *
714
     * @param ContainerBuilder $container
715
     **/
716
    private function loadIndexManager(ContainerBuilder $container)
717
    {
718 12
        $indexRefs = array_map(function ($index) {
719 12
            return $index['reference'];
720 12
        }, $this->indexConfigs);
721
722 12
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
723 12
        $managerDef->replaceArgument(0, $indexRefs);
724 12
    }
725
726
    /**
727
     * Makes sure a specific driver has been loaded.
728
     *
729
     * @param ContainerBuilder $container
730
     * @param string           $driver
731
     */
732 11
    private function loadDriver(ContainerBuilder $container, $driver)
733
    {
734 11
        if (in_array($driver, $this->loadedDrivers)) {
735 3
            return;
736
        }
737
738 11
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
739 11
        $loader->load($driver.'.xml');
740 11
        $this->loadedDrivers[] = $driver;
741 11
    }
742
743
    /**
744
     * Loads and configures the serializer prototype.
745
     *
746
     * @param array            $config
747
     * @param ContainerBuilder $container
748
     */
749 1
    private function loadSerializer($config, ContainerBuilder $container)
750
    {
751 1
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
752
753 1
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
754 1
        $serializer->setClass($config['callback_class']);
755
756 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...
757
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
758
        }
759 1
    }
760
761
    /**
762
     * Creates a default manager alias for defined default manager or the first loaded driver.
763
     *
764
     * @param string           $defaultManager
765
     * @param ContainerBuilder $container
766
     */
767 12
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
768
    {
769 12
        if (0 == count($this->loadedDrivers)) {
770 1
            return;
771
        }
772
773 11
        if (count($this->loadedDrivers) > 1
774 11
            && in_array($defaultManager, $this->loadedDrivers)
775
        ) {
776
            $defaultManagerService = $defaultManager;
777
        } else {
778 11
            $defaultManagerService = $this->loadedDrivers[0];
779
        }
780
781 11
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
782 11
    }
783
784
    /**
785
     * Returns a reference to a client given its configured name.
786
     *
787
     * @param string $clientName
788
     *
789
     * @return Reference
790
     *
791
     * @throws \InvalidArgumentException
792
     */
793 2
    private function getClient($clientName)
794
    {
795 2
        if (!array_key_exists($clientName, $this->clients)) {
796
            throw new \InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
797
        }
798
799 2
        return $this->clients[$clientName]['reference'];
800
    }
801
}
802