Completed
Pull Request — master (#1118)
by Karel
05:28
created

loadModelToElasticaTransformer()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3.0052

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 11
cts 12
cp 0.9167
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 12
nc 3
nop 4
crap 3.0052
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
114 14
            $clientDef->addTag('fos_elastica.client');
115
116 14
            $container->setDefinition($clientId, $clientDef);
117
118 14
            $this->clients[$name] = array(
119 14
                'id' => $clientId,
120 14
                'reference' => new Reference($clientId),
121
            );
122
        }
123 14
    }
124
125
    /**
126
     * Loads the configured indexes.
127
     *
128
     * @param array            $indexes   An array of indexes configurations
129
     * @param ContainerBuilder $container A ContainerBuilder instance
130
     *
131
     * @throws \InvalidArgumentException
132
     *
133
     * @return array
134
     */
135 14
    private function loadIndexes(array $indexes, ContainerBuilder $container)
136
    {
137 14
        $indexableCallbacks = array();
138
139 14
        foreach ($indexes as $name => $index) {
140 14
            $indexId = sprintf('fos_elastica.index.%s', $name);
141 14
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
142
143 14
            $indexDef = new DefinitionDecorator('fos_elastica.index_prototype');
144 14
            $indexDef->replaceArgument(0, $indexName);
145 14
            $indexDef->addTag('fos_elastica.index', array(
146 14
                'name' => $name,
147
            ));
148
149 14
            if (method_exists($indexDef, 'setFactory')) {
150 14
                $indexDef->setFactory(array(new Reference('fos_elastica.client'), 'getIndex'));
151
            } else {
152
                // To be removed when dependency on Symfony DependencyInjection is bumped to 2.6
153
                $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...
154
                $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...
155
            }
156
157 14
            if (isset($index['client'])) {
158 2
                $client = $this->getClient($index['client']);
159
160 2
                if (method_exists($indexDef, 'setFactory')) {
161 2
                    $indexDef->setFactory(array($client, 'getIndex'));
162
                } else {
163
                    // To be removed when dependency on Symfony DependencyInjection is bumped to 2.6
164
                    $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...
165
                    $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...
166
                }
167
            }
168
169 14
            $container->setDefinition($indexId, $indexDef);
170 14
            $reference = new Reference($indexId);
171
172 14
            $this->indexConfigs[$name] = array(
173 14
                'elasticsearch_name' => $indexName,
174 14
                'reference' => $reference,
175 14
                'name' => $name,
176 14
                'settings' => $index['settings'],
177 14
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : array(),
178 14
                'use_alias' => $index['use_alias'],
179
            );
180
181 14
            if ($index['finder']) {
182
                $this->loadIndexFinder($container, $name, $reference);
183
            }
184
185 14
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
186
        }
187
188 14
        $indexable = $container->getDefinition('fos_elastica.indexable');
189 14
        $indexable->replaceArgument(0, $indexableCallbacks);
190 14
    }
191
192
    /**
193
     * Loads the configured index finders.
194
     *
195
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
196
     * @param string                                                  $name      The index name
197
     * @param Reference                                               $index     Reference to the related index
198
     *
199
     * @return string
200
     */
201
    private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
202
    {
203
        /* Note: transformer services may conflict with "collection.index", if
204
         * an index and type names were "collection" and an index, respectively.
205
         */
206
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
207
        $transformerDef = new DefinitionDecorator('fos_elastica.elastica_to_model_transformer.collection');
208
        $container->setDefinition($transformerId, $transformerDef);
209
210
        $finderId = sprintf('fos_elastica.finder.%s', $name);
211
        $finderDef = new DefinitionDecorator('fos_elastica.finder');
212
        $finderDef->replaceArgument(0, $index);
213
        $finderDef->replaceArgument(1, new Reference($transformerId));
214
215
        $container->setDefinition($finderId, $finderDef);
216
    }
217
218
    /**
219
     * Loads the configured types.
220
     *
221
     * @param array            $types
222
     * @param ContainerBuilder $container
223
     * @param array            $indexConfig
224
     * @param array            $indexableCallbacks
225
     */
226 14
    private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
227
    {
228 14
        foreach ($types as $name => $type) {
229 14
            $indexName = $indexConfig['name'];
230
231 14
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
232 14
            $typeDef = new DefinitionDecorator('fos_elastica.type_prototype');
233 14
            $typeDef->replaceArgument(0, $name);
234
235 14
            if (method_exists($typeDef, 'setFactory')) {
236 14
                $typeDef->setFactory(array($indexConfig['reference'], 'getType'));
237
            } else {
238
                // To be removed when dependency on Symfony DependencyInjection is bumped to 2.6
239
                $typeDef->setFactoryService((string) $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...
240
                $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...
241
            }
242
243 14
            $container->setDefinition($typeId, $typeDef);
244
245
            $typeConfig = array(
246 14
                'name' => $name,
247
                'mapping' => array(), // An array containing anything that gets sent directly to ElasticSearch
248
                'config' => array(),
249
            );
250
251
            foreach (array(
252 14
                'dynamic_templates',
253
                'properties',
254
                '_all',
255
                '_boost',
256
                '_id',
257
                '_parent',
258
                '_routing',
259
                '_source',
260
                '_timestamp',
261
                '_ttl',
262
            ) as $field) {
263 14
                if (isset($type[$field])) {
264 14
                    $typeConfig['mapping'][$field] = $type[$field];
265
                }
266
            }
267
268
            foreach (array(
269 14
                'persistence',
270
                'serializer',
271
                'analyzer',
272
                'search_analyzer',
273
                'dynamic',
274
                'date_detection',
275
                'dynamic_date_formats',
276
                'numeric_detection',
277
            ) as $field) {
278 14
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
279 14
                    $type[$field] :
280 14
                    null;
281
            }
282
283 14
            $this->indexConfigs[$indexName]['types'][$name] = $typeConfig;
284
285 14
            if (isset($type['persistence'])) {
286 10
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
287
288 10
                $typeConfig['persistence'] = $type['persistence'];
289
            }
290
291 14
            if (isset($type['_parent'])) {
292
                // _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence`
293 5
                unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']);
294
            }
295
296 14
            if (isset($type['indexable_callback'])) {
297 5
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback'];
298
            }
299
300 14
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
301 3
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
302 3
                $typeSerializerDef = new DefinitionDecorator('fos_elastica.serializer_callback_prototype');
303
304 3
                if (isset($type['serializer']['groups'])) {
305 3
                    $typeSerializerDef->addMethodCall('setGroups', array($type['serializer']['groups']));
306
                }
307
308 3
                if (isset($type['serializer']['serialize_null'])) {
309 3
                    $typeSerializerDef->addMethodCall('setSerializeNull', array($type['serializer']['serialize_null']));
310
                }
311
312 3
                if (isset($type['serializer']['version'])) {
313 3
                    $typeSerializerDef->addMethodCall('setVersion', array($type['serializer']['version']));
314
                }
315
316 3
                $typeDef->addMethodCall('setSerializer', array(array(new Reference($typeSerializerId), 'serialize')));
317 14
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
318
            }
319
        }
320 14
    }
321
322
    /**
323
     * Loads the optional provider and finder for a type.
324
     *
325
     * @param array            $typeConfig
326
     * @param ContainerBuilder $container
327
     * @param Reference        $typeRef
328
     * @param string           $indexName
329
     * @param string           $typeName
330
     */
331 10
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
332
    {
333 10
        if (isset($typeConfig['driver'])) {
334 10
            $this->loadDriver($container, $typeConfig['driver']);
335
        }
336
337 10
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
338 10
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
339 10
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
340
341 10
        if (isset($typeConfig['provider'])) {
342 10
            $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
343
        }
344 10
        if (isset($typeConfig['finder'])) {
345 10
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
346
        }
347 10
        if (isset($typeConfig['listener'])) {
348 10
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
349
        }
350 10
    }
351
352
    /**
353
     * Creates and loads an ElasticaToModelTransformer.
354
     *
355
     * @param array            $typeConfig
356
     * @param ContainerBuilder $container
357
     * @param string           $indexName
358
     * @param string           $typeName
359
     *
360
     * @return string
361
     */
362 10
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
363
    {
364 10
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
365 1
            return $typeConfig['elastica_to_model_transformer']['service'];
366
        }
367
368
        /* Note: transformer services may conflict with "prototype.driver", if
369
         * the index and type names were "prototype" and a driver, respectively.
370
         */
371 9
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
372 9
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
373 9
        $serviceDef = new DefinitionDecorator($abstractId);
374 9
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', array('type' => $typeName, 'index' => $indexName));
375
376
        // Doctrine has a mandatory service as first argument
377 9
        $argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
378
379 9
        $serviceDef->replaceArgument($argPos, $typeConfig['model']);
380 9
        $serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], array(
381 9
            'identifier' => $typeConfig['identifier'],
382
        )));
383 9
        $container->setDefinition($serviceId, $serviceDef);
384
385 9
        return $serviceId;
386
    }
387
388
    /**
389
     * Creates and loads a ModelToElasticaTransformer for an index/type.
390
     *
391
     * @param array            $typeConfig
392
     * @param ContainerBuilder $container
393
     * @param string           $indexName
394
     * @param string           $typeName
395
     *
396
     * @return string
397
     */
398 10
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
399
    {
400 10
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
401
            return $typeConfig['model_to_elastica_transformer']['service'];
402
        }
403
404 10
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
405 3
            'fos_elastica.model_to_elastica_identifier_transformer' :
406 10
            'fos_elastica.model_to_elastica_transformer';
407
408 10
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
409 10
        $serviceDef = new DefinitionDecorator($abstractId);
410 10
        $serviceDef->replaceArgument(0, array(
411 10
            'identifier' => $typeConfig['identifier'],
412
        ));
413 10
        $container->setDefinition($serviceId, $serviceDef);
414
415 10
        return $serviceId;
416
    }
417
418
    /**
419
     * Creates and loads an object persister for a type.
420
     *
421
     * @param array            $typeConfig
422
     * @param Reference        $typeRef
423
     * @param ContainerBuilder $container
424
     * @param string           $indexName
425
     * @param string           $typeName
426
     * @param string           $transformerId
427
     *
428
     * @return string
429
     */
430 10
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
431
    {
432 10
        if (isset($typeConfig['persister']['service'])) {
433 1
            return $typeConfig['persister']['service'];
434
        }
435
436
        $arguments = array(
437 9
            $typeRef,
438 9
            new Reference($transformerId),
439 9
            $typeConfig['model'],
440
        );
441
442 9
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
443 3
            $abstractId = 'fos_elastica.object_serializer_persister';
444 3
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
445 3
            $arguments[] = array(new Reference($callbackId), 'serialize');
446
        } else {
447 6
            $abstractId = 'fos_elastica.object_persister';
448 6
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
449 6
            $argument = $mapping['properties'];
450 6
            if (isset($mapping['_parent'])) {
451 1
                $argument['_parent'] = $mapping['_parent'];
452
            }
453 6
            $arguments[] = $argument;
454
        }
455
456 9
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
457 9
        $serviceDef = new DefinitionDecorator($abstractId);
458 9
        foreach ($arguments as $i => $argument) {
459 9
            $serviceDef->replaceArgument($i, $argument);
460
        }
461
462 9
        $container->setDefinition($serviceId, $serviceDef);
463
464 9
        return $serviceId;
465
    }
466
467
    /**
468
     * Loads a provider for a type.
469
     *
470
     * @param array            $typeConfig
471
     * @param ContainerBuilder $container
472
     * @param string           $objectPersisterId
473
     * @param string           $indexName
474
     * @param string           $typeName
475
     *
476
     * @return string
477
     */
478 10
    private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
479
    {
480 10
        if (isset($typeConfig['provider']['service'])) {
481
            return $typeConfig['provider']['service'];
482
        }
483
484
        /* Note: provider services may conflict with "prototype.driver", if the
485
         * index and type names were "prototype" and a driver, respectively.
486
         */
487 10
        $providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName);
488 10
        $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.'.$typeConfig['driver']);
489 10
        $providerDef->addTag('fos_elastica.provider', array('index' => $indexName, 'type' => $typeName));
490 10
        $providerDef->replaceArgument(0, new Reference($objectPersisterId));
491 10
        $providerDef->replaceArgument(2, $typeConfig['model']);
492
        // Propel provider can simply ignore Doctrine-specific options
493 10
        $providerDef->replaceArgument(3, array_merge(array_diff_key($typeConfig['provider'], array('service' => 1)), array(
494 10
            'indexName' => $indexName,
495 10
            'typeName' => $typeName,
496
        )));
497 10
        $container->setDefinition($providerId, $providerDef);
498
499 10
        return $providerId;
500
    }
501
502
    /**
503
     * Loads doctrine listeners to handle indexing of new or updated objects.
504
     *
505
     * @param array            $typeConfig
506
     * @param ContainerBuilder $container
507
     * @param string           $objectPersisterId
508
     * @param string           $indexName
509
     * @param string           $typeName
510
     *
511
     * @return string
512
     */
513 10
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
514
    {
515 10
        if (isset($typeConfig['listener']['service'])) {
516
            return $typeConfig['listener']['service'];
517
        }
518
519
        /* Note: listener services may conflict with "prototype.driver", if the
520
         * index and type names were "prototype" and a driver, respectively.
521
         */
522 10
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
523 10
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
524 10
        $listenerDef = new DefinitionDecorator($abstractListenerId);
525 10
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
526 10
        $listenerDef->replaceArgument(2, array(
527 10
            'identifier' => $typeConfig['identifier'],
528 10
            'indexName' => $indexName,
529 10
            'typeName' => $typeName,
530
        ));
531 10
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
532
            new Reference($typeConfig['listener']['logger']) :
533 10
            null
534
        );
535
536 10
        $tagName = null;
537 10
        switch ($typeConfig['driver']) {
538 10
            case 'orm':
539 10
                $tagName = 'doctrine.event_listener';
540 10
                break;
541
            case 'phpcr':
542
                $tagName = 'doctrine_phpcr.event_listener';
543
                break;
544
            case 'mongodb':
545
                $tagName = 'doctrine_mongodb.odm.event_listener';
546
                break;
547
        }
548
549 10
        if (null !== $tagName) {
550 10
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
551 10
                $listenerDef->addTag($tagName, array('event' => $event));
552
            }
553
        }
554
555 10
        $container->setDefinition($listenerId, $listenerDef);
556
557 10
        return $listenerId;
558
    }
559
560
    /**
561
     * Map Elastica to Doctrine events for the current driver.
562
     */
563 10
    private function getDoctrineEvents(array $typeConfig)
564
    {
565 10
        switch ($typeConfig['driver']) {
566 10
            case 'orm':
567 10
                $eventsClass = '\Doctrine\ORM\Events';
568 10
                break;
569
            case 'phpcr':
570
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
571
                break;
572
            case 'mongodb':
573
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
574
                break;
575
            default:
576
                throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
577
        }
578
579 10
        $events = array();
580
        $eventMapping = array(
581 10
            'insert' => array(constant($eventsClass.'::postPersist')),
582 10
            'update' => array(constant($eventsClass.'::postUpdate')),
583 10
            'delete' => array(constant($eventsClass.'::preRemove')),
584 10
            'flush' => array(constant($eventsClass.'::postFlush')),
585
        );
586
587 10
        foreach ($eventMapping as $event => $doctrineEvents) {
588 10
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
589 10
                $events = array_merge($events, $doctrineEvents);
590
            }
591
        }
592
593 10
        return $events;
594
    }
595
596
    /**
597
     * Loads a Type specific Finder.
598
     *
599
     * @param array            $typeConfig
600
     * @param ContainerBuilder $container
601
     * @param string           $elasticaToModelId
602
     * @param Reference        $typeRef
603
     * @param string           $indexName
604
     * @param string           $typeName
605
     *
606
     * @return string
607
     */
608 10
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
609
    {
610 10
        if (isset($typeConfig['finder']['service'])) {
611
            $finderId = $typeConfig['finder']['service'];
612
        } else {
613 10
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
614 10
            $finderDef = new DefinitionDecorator('fos_elastica.finder');
615 10
            $finderDef->replaceArgument(0, $typeRef);
616 10
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
617 10
            $container->setDefinition($finderId, $finderDef);
618
        }
619
620 10
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
621 10
        $managerDef = $container->getDefinition($managerId);
622 10
        $arguments = array( $typeConfig['model'], new Reference($finderId));
623 10
        if (isset($typeConfig['repository'])) {
624
            $arguments[] = $typeConfig['repository'];
625
        }
626 10
        $managerDef->addMethodCall('addEntity', $arguments);
627
628 10
        return $finderId;
629
    }
630
631
    /**
632
     * Loads the index manager.
633
     *
634
     * @param ContainerBuilder $container
635
     **/
636
    private function loadIndexManager(ContainerBuilder $container)
637
    {
638 14
        $indexRefs = array_map(function ($index) {
639 14
            return $index['reference'];
640 14
        }, $this->indexConfigs);
641
642 14
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
643 14
        $managerDef->replaceArgument(0, $indexRefs);
644 14
    }
645
646
    /**
647
     * Makes sure a specific driver has been loaded.
648
     *
649
     * @param ContainerBuilder $container
650
     * @param string           $driver
651
     */
652 10
    private function loadDriver(ContainerBuilder $container, $driver)
653
    {
654 10
        if (in_array($driver, $this->loadedDrivers)) {
655 9
            return;
656
        }
657
658 10
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
659 10
        $loader->load($driver.'.xml');
660 10
        $this->loadedDrivers[] = $driver;
661 10
    }
662
663
    /**
664
     * Loads and configures the serializer prototype.
665
     *
666
     * @param array            $config
667
     * @param ContainerBuilder $container
668
     */
669 3
    private function loadSerializer($config, ContainerBuilder $container)
670
    {
671 3
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
672
673 3
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
674 3
        $serializer->setClass($config['callback_class']);
675
676 3
        $callbackClassImplementedInterfaces = class_implements($config['callback_class']);
677 3
        if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) {
678
            $serializer->addMethodCall('setContainer', array(new Reference('service_container')));
679
        }
680 3
    }
681
682
    /**
683
     * Creates a default manager alias for defined default manager or the first loaded driver.
684
     *
685
     * @param string           $defaultManager
686
     * @param ContainerBuilder $container
687
     */
688 14
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
689
    {
690 14
        if (0 == count($this->loadedDrivers)) {
691 4
            return;
692
        }
693
694 10
        if (count($this->loadedDrivers) > 1
695 10
            && in_array($defaultManager, $this->loadedDrivers)
696
        ) {
697
            $defaultManagerService = $defaultManager;
698
        } else {
699 10
            $defaultManagerService = $this->loadedDrivers[0];
700
        }
701
702 10
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
703 10
    }
704
705
    /**
706
     * Returns a reference to a client given its configured name.
707
     *
708
     * @param string $clientName
709
     *
710
     * @return Reference
711
     *
712
     * @throws \InvalidArgumentException
713
     */
714 2
    private function getClient($clientName)
715
    {
716 2
        if (!array_key_exists($clientName, $this->clients)) {
717
            throw new InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
718
        }
719
720 2
        return $this->clients[$clientName]['reference'];
721
    }
722
}
723