Completed
Pull Request — master (#1331)
by
unknown
05:06
created

FOSElasticaExtension::loadTypePagerProvider()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 50
Code Lines 33

Duplication

Lines 18
Ratio 36 %

Code Coverage

Tests 22
CRAP Score 7.0986

Importance

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