Completed
Pull Request — master (#1056)
by Christian
05:21
created

FOSElasticaExtension::loadClients()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 27
ccs 14
cts 14
cp 1
rs 8.5806
cc 4
eloc 15
nc 5
nop 2
crap 4
1
<?php
2
3
namespace FOS\ElasticaBundle\DependencyInjection;
4
5
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
6
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
7
use Symfony\Component\DependencyInjection\ContainerBuilder;
8
use Symfony\Component\DependencyInjection\DefinitionDecorator;
9
use Symfony\Component\DependencyInjection\Reference;
10
use Symfony\Component\Config\FileLocator;
11
use InvalidArgumentException;
12
13
class FOSElasticaExtension extends Extension
14
{
15
    /**
16
     * Definition of elastica clients as configured by this extension.
17
     *
18
     * @var array
19
     */
20
    private $clients = array();
21
22
    /**
23
     * An array of indexes as configured by the extension.
24
     *
25
     * @var array
26
     */
27
    private $indexConfigs = array();
28
29
    /**
30
     * If we've encountered a type mapped to a specific persistence driver, it will be loaded
31
     * here.
32
     *
33
     * @var array
34
     */
35
    private $loadedDrivers = array();
36
37 14
    public function load(array $configs, ContainerBuilder $container)
38
    {
39 14
        $configuration = $this->getConfiguration($configs, $container);
40 14
        $config = $this->processConfiguration($configuration, $configs);
41
42 14
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
43
44 14
        if (empty($config['clients']) || empty($config['indexes'])) {
45
            // No Clients or indexes are defined
46
            return;
47
        }
48
49 14
        foreach (array('config', 'index', 'persister', 'provider', 'source', 'transformer') as $basename) {
50 14
            $loader->load(sprintf('%s.xml', $basename));
51
        }
52
53 14
        if (empty($config['default_client'])) {
54 14
            $keys = array_keys($config['clients']);
55 14
            $config['default_client'] = reset($keys);
56
        }
57
58 14
        if (empty($config['default_index'])) {
59 14
            $keys = array_keys($config['indexes']);
60 14
            $config['default_index'] = reset($keys);
61
        }
62
63 14
        if (isset($config['serializer'])) {
64 3
            $loader->load('serializer.xml');
65
66 3
            $this->loadSerializer($config['serializer'], $container);
67
        }
68
69 14
        $this->loadClients($config['clients'], $container);
70 14
        $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
71
72 14
        $this->loadIndexes($config['indexes'], $container);
73 14
        $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
74
75 14
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
76
77 14
        $this->loadIndexManager($container);
78
79 14
        $this->createDefaultManagerAlias($config['default_manager'], $container);
80 14
    }
81
82
    /**
83
     * @param array            $config
84
     * @param ContainerBuilder $container
85
     *
86
     * @return Configuration
87
     */
88 14
    public function getConfiguration(array $config, ContainerBuilder $container)
89
    {
90 14
        return new Configuration($container->getParameter('kernel.debug'));
91
    }
92
93
    /**
94
     * Loads the configured clients.
95
     *
96
     * @param array            $clients   An array of clients configurations
97
     * @param ContainerBuilder $container A ContainerBuilder instance
98
     *
99
     * @return array
100
     */
101 14
    private function loadClients(array $clients, ContainerBuilder $container)
102
    {
103 14
        foreach ($clients as $name => $clientConfig) {
104 14
            $clientId = sprintf('fos_elastica.client.%s', $name);
105
106 14
            $clientDef = new DefinitionDecorator('fos_elastica.client_prototype');
107 14
            $clientDef->replaceArgument(0, $clientConfig);
108
109 14
            $logger = $clientConfig['connections'][0]['logger'];
110 14
            if (false !== $logger) {
111 14
                $clientDef->addMethodCall('setLogger', array(new Reference($logger)));
112
            }
113 14
114
            if (isset($clientConfig['connections'][0]['connectTimeout'])) {
115 14
                $clientDef->addMethodCall('setConnectTimeout', [$clientConfig['connections'][0]['connectTimeout']]);
116
            }
117 14
118 14
            $clientDef->addTag('fos_elastica.client');
119 14
120
            $container->setDefinition($clientId, $clientDef);
121
122 14
            $this->clients[$name] = array(
123
                'id' => $clientId,
124
                'reference' => new Reference($clientId),
125
            );
126
        }
127
    }
128
129
    /**
130
     * Loads the configured indexes.
131
     *
132
     * @param array            $indexes   An array of indexes configurations
133
     * @param ContainerBuilder $container A ContainerBuilder instance
134 14
     *
135
     * @throws \InvalidArgumentException
136 14
     *
137
     * @return array
138 14
     */
139 14
    private function loadIndexes(array $indexes, ContainerBuilder $container)
140 14
    {
141
        $indexableCallbacks = array();
142 14
143 14
        foreach ($indexes as $name => $index) {
144 14
            $indexId = sprintf('fos_elastica.index.%s', $name);
145 14
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
146
147
            $indexDef = new DefinitionDecorator('fos_elastica.index_prototype');
148 14
            $indexDef->replaceArgument(0, $indexName);
149 14
            $indexDef->addTag('fos_elastica.index', array(
150
                'name' => $name,
151
            ));
152
153
            if (method_exists($indexDef, 'setFactory')) {
154
                $indexDef->setFactory(array(new Reference('fos_elastica.client'), 'getIndex'));
155
            } else {
156 14
                // To be removed when dependency on Symfony DependencyInjection is bumped to 2.6
157 2
                $indexDef->setFactoryService('fos_elastica.client');
0 ignored issues
show
Bug introduced by
The method setFactoryService() does not exist on Symfony\Component\Depend...ion\DefinitionDecorator. Did you maybe mean setFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
158
                $indexDef->setFactoryMethod('getIndex');
0 ignored issues
show
Bug introduced by
The method setFactoryMethod() does not exist on Symfony\Component\Depend...ion\DefinitionDecorator. Did you maybe mean setFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
159 2
            }
160 2
161
            if (isset($index['client'])) {
162
                $client = $this->getClient($index['client']);
163
164
                if (method_exists($indexDef, 'setFactory')) {
165
                    $indexDef->setFactory(array($client, 'getIndex'));
166
                } else {
167
                    // To be removed when dependency on Symfony DependencyInjection is bumped to 2.6
168 14
                    $indexDef->setFactoryService($client);
0 ignored issues
show
Bug introduced by
The method setFactoryService() does not exist on Symfony\Component\Depend...ion\DefinitionDecorator. Did you maybe mean setFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
169 14
                    $indexDef->setFactoryMethod('getIndex');
0 ignored issues
show
Bug introduced by
The method setFactoryMethod() does not exist on Symfony\Component\Depend...ion\DefinitionDecorator. Did you maybe mean setFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
170
                }
171 14
            }
172 14
173 14
            $container->setDefinition($indexId, $indexDef);
174 14
            $reference = new Reference($indexId);
175 14
176 14
            $this->indexConfigs[$name] = array(
177 14
                'elasticsearch_name' => $indexName,
178
                'reference' => $reference,
179
                'name' => $name,
180 14
                'settings' => $index['settings'],
181
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : array(),
182
                'use_alias' => $index['use_alias'],
183
            );
184 14
185
            if ($index['finder']) {
186
                $this->loadIndexFinder($container, $name, $reference);
187 14
            }
188 14
189 14
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
190
        }
191
192
        $indexable = $container->getDefinition('fos_elastica.indexable');
193
        $indexable->replaceArgument(0, $indexableCallbacks);
194
    }
195
196
    /**
197
     * Loads the configured index finders.
198
     *
199
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
200
     * @param string                                                  $name      The index name
201
     * @param Reference                                               $index     Reference to the related index
202
     *
203
     * @return string
204
     */
205
    private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
206
    {
207
        /* Note: transformer services may conflict with "collection.index", if
208
         * an index and type names were "collection" and an index, respectively.
209
         */
210
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
211
        $transformerDef = new DefinitionDecorator('fos_elastica.elastica_to_model_transformer.collection');
212
        $container->setDefinition($transformerId, $transformerDef);
213
214
        $finderId = sprintf('fos_elastica.finder.%s', $name);
215
        $finderDef = new DefinitionDecorator('fos_elastica.finder');
216
        $finderDef->replaceArgument(0, $index);
217
        $finderDef->replaceArgument(1, new Reference($transformerId));
218
219
        $container->setDefinition($finderId, $finderDef);
220
    }
221
222
    /**
223
     * Loads the configured types.
224
     *
225 14
     * @param array            $types
226
     * @param ContainerBuilder $container
227 14
     * @param array            $indexConfig
228 14
     * @param array            $indexableCallbacks
229
     */
230 14
    private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
231 14
    {
232 14
        foreach ($types as $name => $type) {
233
            $indexName = $indexConfig['name'];
234 14
235 14
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
236
            $typeDef = new DefinitionDecorator('fos_elastica.type_prototype');
237
            $typeDef->replaceArgument(0, $name);
238
239
            if (method_exists($typeDef, 'setFactory')) {
240
                $typeDef->setFactory(array($indexConfig['reference'], 'getType'));
241
            } else {
242 14
                // To be removed when dependency on Symfony DependencyInjection is bumped to 2.6
243
                $typeDef->setFactoryService($indexConfig['reference']);
0 ignored issues
show
Bug introduced by
The method setFactoryService() does not exist on Symfony\Component\Depend...ion\DefinitionDecorator. Did you maybe mean setFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
244
                $typeDef->setFactoryMethod('getType');
0 ignored issues
show
Bug introduced by
The method setFactoryMethod() does not exist on Symfony\Component\Depend...ion\DefinitionDecorator. Did you maybe mean setFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
245 14
            }
246
247
            $container->setDefinition($typeId, $typeDef);
248
249
            $typeConfig = array(
250
                'name' => $name,
251 14
                'mapping' => array(), // An array containing anything that gets sent directly to ElasticSearch
252
                'config' => array(),
253
            );
254
255
            foreach (array(
256
                'dynamic_templates',
257
                'properties',
258
                '_all',
259
                '_boost',
260
                '_id',
261
                '_parent',
262 14
                '_routing',
263 14
                '_source',
264
                '_timestamp',
265
                '_ttl',
266
            ) as $field) {
267
                if (isset($type[$field])) {
268 14
                    $typeConfig['mapping'][$field] = $type[$field];
269
                }
270
            }
271
272
            foreach (array(
273
                'persistence',
274
                'serializer',
275
                'index_analyzer',
276
                'search_analyzer',
277 14
                'dynamic',
278 14
                'date_detection',
279 14
                'dynamic_date_formats',
280
                'numeric_detection',
281
            ) as $field) {
282 14
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
283
                    $type[$field] :
284 14
                    null;
285 10
            }
286
287 10
            $this->indexConfigs[$indexName]['types'][$name] = $typeConfig;
288
289
            if (isset($type['persistence'])) {
290 14
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
291 5
292
                $typeConfig['persistence'] = $type['persistence'];
293
            }
294 14
295 3
            if (isset($type['indexable_callback'])) {
296 3
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback'];
297
            }
298 3
299 3
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
300
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
301
                $typeSerializerDef = new DefinitionDecorator('fos_elastica.serializer_callback_prototype');
302 3
303 3
                if (isset($type['serializer']['groups'])) {
304
                    $typeSerializerDef->addMethodCall('setGroups', array($type['serializer']['groups']));
305
                }
306 3
307 3
                if (isset($type['serializer']['serialize_null'])) {
308
                    $typeSerializerDef->addMethodCall('setSerializeNull', array($type['serializer']['serialize_null']));
309
                }
310 3
311 14
                if (isset($type['serializer']['version'])) {
312
                    $typeSerializerDef->addMethodCall('setVersion', array($type['serializer']['version']));
313
                }
314 14
315
                $typeDef->addMethodCall('setSerializer', array(array(new Reference($typeSerializerId), 'serialize')));
316
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
317
            }
318
        }
319
    }
320
321
    /**
322
     * Loads the optional provider and finder for a type.
323
     *
324
     * @param array            $typeConfig
325 10
     * @param ContainerBuilder $container
326
     * @param Reference        $typeRef
327 10
     * @param string           $indexName
328 9
     * @param string           $typeName
329
     */
330
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
331 10
    {
332 10
        if (isset($typeConfig['driver'])) {
333 10
            $this->loadDriver($container, $typeConfig['driver']);
334
        }
335 10
336 5
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
337
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
338 10
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
339 5
340
        if (isset($typeConfig['provider'])) {
341 10
            $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
342 5
        }
343
        if (isset($typeConfig['finder'])) {
344 10
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
345
        }
346
        if (isset($typeConfig['listener'])) {
347
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
348
        }
349
    }
350
351
    /**
352
     * Creates and loads an ElasticaToModelTransformer.
353
     *
354
     * @param array            $typeConfig
355
     * @param ContainerBuilder $container
356 10
     * @param string           $indexName
357
     * @param string           $typeName
358 10
     *
359 1
     * @return string
360
     */
361
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
362
    {
363
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
364
            return $typeConfig['elastica_to_model_transformer']['service'];
365 9
        }
366 9
367 9
        /* Note: transformer services may conflict with "prototype.driver", if
368 9
         * the index and type names were "prototype" and a driver, respectively.
369
         */
370
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
371 9
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
372
        $serviceDef = new DefinitionDecorator($abstractId);
373 9
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', array('type' => $typeName, 'index' => $indexName));
374 9
375 9
        // Doctrine has a mandatory service as first argument
376
        $argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
377 9
378
        $serviceDef->replaceArgument($argPos, $typeConfig['model']);
379 9
        $serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], array(
380
            'identifier' => $typeConfig['identifier'],
381
        )));
382
        $container->setDefinition($serviceId, $serviceDef);
383
384
        return $serviceId;
385
    }
386
387
    /**
388
     * Creates and loads a ModelToElasticaTransformer for an index/type.
389
     *
390
     * @param array            $typeConfig
391
     * @param ContainerBuilder $container
392 10
     * @param string           $indexName
393
     * @param string           $typeName
394 10
     *
395
     * @return string
396
     */
397
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
398 10
    {
399 3
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
400 10
            return $typeConfig['model_to_elastica_transformer']['service'];
401
        }
402 10
403 10
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
404 10
            'fos_elastica.model_to_elastica_identifier_transformer' :
405 10
            'fos_elastica.model_to_elastica_transformer';
406
407 10
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
408
        $serviceDef = new DefinitionDecorator($abstractId);
409 10
        $serviceDef->replaceArgument(0, array(
410
            'identifier' => $typeConfig['identifier'],
411
        ));
412
        $container->setDefinition($serviceId, $serviceDef);
413
414
        return $serviceId;
415
    }
416
417
    /**
418
     * Creates and loads an object persister for a type.
419
     *
420
     * @param array            $typeConfig
421
     * @param Reference        $typeRef
422
     * @param ContainerBuilder $container
423
     * @param string           $indexName
424 10
     * @param string           $typeName
425
     * @param string           $transformerId
426 10
     *
427 1
     * @return string
428
     */
429
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
430
    {
431 9
        if (isset($typeConfig['persister']['service'])) {
432 9
            return $typeConfig['persister']['service'];
433 9
        }
434
435
        $arguments = array(
436 9
            $typeRef,
437 3
            new Reference($transformerId),
438 3
            $typeConfig['model'],
439 3
        );
440
441 6
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
442 6
            $abstractId = 'fos_elastica.object_serializer_persister';
443 6
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
444 6
            $arguments[] = array(new Reference($callbackId), 'serialize');
445 1
        } else {
446
            $abstractId = 'fos_elastica.object_persister';
447 6
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
448
            $argument = $mapping['properties'];
449
            if (isset($mapping['_parent'])) {
450 9
                $argument['_parent'] = $mapping['_parent'];
451 9
            }
452 9
            $arguments[] = $argument;
453 9
        }
454
455
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
456 9
        $serviceDef = new DefinitionDecorator($abstractId);
457
        foreach ($arguments as $i => $argument) {
458 9
            $serviceDef->replaceArgument($i, $argument);
459
        }
460
461
        $container->setDefinition($serviceId, $serviceDef);
462
463
        return $serviceId;
464
    }
465
466
    /**
467
     * Loads a provider for a type.
468
     *
469
     * @param array            $typeConfig
470
     * @param ContainerBuilder $container
471
     * @param string           $objectPersisterId
472 5
     * @param string           $indexName
473
     * @param string           $typeName
474 5
     *
475
     * @return string
476
     */
477
    private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
478
    {
479
        if (isset($typeConfig['provider']['service'])) {
480
            return $typeConfig['provider']['service'];
481 5
        }
482 5
483 5
        /* Note: provider services may conflict with "prototype.driver", if the
484 5
         * index and type names were "prototype" and a driver, respectively.
485 5
         */
486
        $providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName);
487 5
        $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.'.$typeConfig['driver']);
488 5
        $providerDef->addTag('fos_elastica.provider', array('index' => $indexName, 'type' => $typeName));
489 5
        $providerDef->replaceArgument(0, new Reference($objectPersisterId));
490
        $providerDef->replaceArgument(2, $typeConfig['model']);
491 5
        // Propel provider can simply ignore Doctrine-specific options
492
        $providerDef->replaceArgument(3, array_merge(array_diff_key($typeConfig['provider'], array('service' => 1)), array(
493 5
            'indexName' => $indexName,
494
            'typeName' => $typeName,
495
        )));
496
        $container->setDefinition($providerId, $providerDef);
497
498
        return $providerId;
499
    }
500
501
    /**
502
     * Loads doctrine listeners to handle indexing of new or updated objects.
503
     *
504
     * @param array            $typeConfig
505
     * @param ContainerBuilder $container
506
     * @param string           $objectPersisterId
507 5
     * @param string           $indexName
508
     * @param string           $typeName
509 5
     *
510
     * @return string
511
     */
512
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
513
    {
514
        if (isset($typeConfig['listener']['service'])) {
515
            return $typeConfig['listener']['service'];
516 5
        }
517 5
518 5
        /* Note: listener services may conflict with "prototype.driver", if the
519 5
         * index and type names were "prototype" and a driver, respectively.
520 5
         */
521 5
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
522 5
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
523 5
        $listenerDef = new DefinitionDecorator($abstractListenerId);
524
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
525 5
        $listenerDef->replaceArgument(2, array(
526
            'identifier' => $typeConfig['identifier'],
527 5
            'indexName' => $indexName,
528
            'typeName' => $typeName,
529
        ));
530 5
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
531 5
            new Reference($typeConfig['listener']['logger']) :
532
            null
533 5
        );
534 5
535
        $tagName = null;
536
        switch ($typeConfig['driver']) {
537
            case 'orm':
538
                $tagName = 'doctrine.event_listener';
539
                break;
540
            case 'phpcr':
541
                $tagName = 'doctrine_phpcr.event_listener';
542
                break;
543 5
            case 'mongodb':
544 5
                $tagName = 'doctrine_mongodb.odm.event_listener';
545 5
                break;
546
        }
547
548
        if (null !== $tagName) {
549 5
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
550
                $listenerDef->addTag($tagName, array('event' => $event));
551 5
            }
552
        }
553
554
        $container->setDefinition($listenerId, $listenerDef);
555
556
        return $listenerId;
557 5
    }
558
559 5
    /**
560
     * Map Elastica to Doctrine events for the current driver.
561 5
     */
562 5
    private function getDoctrineEvents(array $typeConfig)
563
    {
564
        switch ($typeConfig['driver']) {
565
            case 'orm':
566
                $eventsClass = '\Doctrine\ORM\Events';
567
                break;
568
            case 'phpcr':
569
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
570
                break;
571
            case 'mongodb':
572
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
573 5
                break;
574
            default:
575 5
                throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
576 5
        }
577 5
578 5
        $events = array();
579
        $eventMapping = array(
580
            'insert' => array(constant($eventsClass.'::postPersist')),
581 5
            'update' => array(constant($eventsClass.'::postUpdate')),
582 5
            'delete' => array(constant($eventsClass.'::preRemove')),
583 5
            'flush' => array($typeConfig['listener']['immediate'] ? constant($eventsClass.'::preFlush') : constant($eventsClass.'::postFlush')),
584
        );
585
586
        foreach ($eventMapping as $event => $doctrineEvents) {
587 5
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
588
                $events = array_merge($events, $doctrineEvents);
589
            }
590
        }
591
592
        return $events;
593
    }
594
595
    /**
596
     * Loads a Type specific Finder.
597
     *
598
     * @param array            $typeConfig
599
     * @param ContainerBuilder $container
600
     * @param string           $elasticaToModelId
601
     * @param Reference        $typeRef
602 5
     * @param string           $indexName
603
     * @param string           $typeName
604 5
     *
605
     * @return string
606
     */
607 5
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
608 5
    {
609 5
        if (isset($typeConfig['finder']['service'])) {
610 5
            $finderId = $typeConfig['finder']['service'];
611 5
        } else {
612
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
613
            $finderDef = new DefinitionDecorator('fos_elastica.finder');
614 5
            $finderDef->replaceArgument(0, $typeRef);
615 5
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
616 5
            $container->setDefinition($finderId, $finderDef);
617 5
        }
618
619
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
620 5
        $managerDef = $container->getDefinition($managerId);
621
        $arguments = array( $typeConfig['model'], new Reference($finderId));
622 5
        if (isset($typeConfig['repository'])) {
623
            $arguments[] = $typeConfig['repository'];
624
        }
625
        $managerDef->addMethodCall('addEntity', $arguments);
626
627
        return $finderId;
628
    }
629
630
    /**
631
     * Loads the index manager.
632 14
     *
633 14
     * @param ContainerBuilder $container
634 14
     **/
635
    private function loadIndexManager(ContainerBuilder $container)
636 14
    {
637 14
        $indexRefs = array_map(function ($index) {
638 14
            return $index['reference'];
639
        }, $this->indexConfigs);
640
641
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
642
        $managerDef->replaceArgument(0, $indexRefs);
643
    }
644
645
    /**
646 9
     * Makes sure a specific driver has been loaded.
647
     *
648 9
     * @param ContainerBuilder $container
649 9
     * @param string           $driver
650
     */
651
    private function loadDriver(ContainerBuilder $container, $driver)
652 9
    {
653 9
        if (in_array($driver, $this->loadedDrivers)) {
654 9
            return;
655 9
        }
656
657
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
658
        $loader->load($driver.'.xml');
659
        $this->loadedDrivers[] = $driver;
660
    }
661
662
    /**
663 3
     * Loads and configures the serializer prototype.
664
     *
665 3
     * @param array            $config
666
     * @param ContainerBuilder $container
667 3
     */
668 3
    private function loadSerializer($config, ContainerBuilder $container)
669
    {
670 3
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
671 3
672
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
673
        $serializer->setClass($config['callback_class']);
674 3
675
        $callbackClassImplementedInterfaces = class_implements($config['callback_class']);
676
        if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) {
677
            $serializer->addMethodCall('setContainer', array(new Reference('service_container')));
678
        }
679
    }
680
681
    /**
682 14
     * Creates a default manager alias for defined default manager or the first loaded driver.
683
     *
684 14
     * @param string           $defaultManager
685 5
     * @param ContainerBuilder $container
686
     */
687
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
688 9
    {
689 9
        if (0 == count($this->loadedDrivers)) {
690
            return;
691
        }
692
693 9
        if (count($this->loadedDrivers) > 1
694
            && in_array($defaultManager, $this->loadedDrivers)
695
        ) {
696 9
            $defaultManagerService = $defaultManager;
697 9
        } else {
698
            $defaultManagerService = $this->loadedDrivers[0];
699
        }
700
701
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
702
    }
703
704
    /**
705
     * Returns a reference to a client given its configured name.
706
     *
707
     * @param string $clientName
708 2
     *
709
     * @return Reference
710 2
     *
711
     * @throws \InvalidArgumentException
712
     */
713
    private function getClient($clientName)
714 2
    {
715
        if (!array_key_exists($clientName, $this->clients)) {
716
            throw new InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
717
        }
718
719
        return $this->clients[$clientName]['reference'];
720
    }
721
}
722