Completed
Pull Request — master (#1343)
by Dmitry
04:26
created

FOSElasticaExtension::getConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

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