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

FOSElasticaExtension::loadIndexTemplateManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 9
loc 9
ccs 0
cts 0
cp 0
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
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
        if ($usedIndexNames = \array_intersect_key($config['indexes'], $config['index_templates'])) {
102
            throw new \DomainException(
103
                \sprintf(
104
                    'Index names "%s" are already in use and can not be used for index templates names',
105
                    \implode('","', \array_keys($usedIndexNames))
106
                )
107 18
            );
108
        }
109 18
        $this->loadIndexTemplates($config['index_templates'], $container);
110
111
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
112
        $container
113
            ->getDefinition('fos_elastica.config_source.template_container')
114
            ->replaceArgument(0, $this->indexTemplateConfigs);
115
116
        $this->loadIndexManager($container);
117
        $this->loadIndexTemplateManager($container);
118
119
        $this->createDefaultManagerAlias($config['default_manager'], $container);
120 18
    }
121
122 18
    /**
123 18
     * @param array            $config
124
     * @param ContainerBuilder $container
125 18
     *
126 18
     * @return Configuration
127
     */
128 18
    public function getConfiguration(array $config, ContainerBuilder $container)
129 18
    {
130 18
        return new Configuration($container->getParameter('kernel.debug'));
131
    }
132
133 18
    /**
134
     * Loads the configured clients.
135 18
     *
136
     * @param array            $clients   An array of clients configurations
137 18
     * @param ContainerBuilder $container A ContainerBuilder instance
138 18
     *
139 18
     * @return array
140
     */
141
    private function loadClients(array $clients, ContainerBuilder $container)
142 18
    {
143
        foreach ($clients as $name => $clientConfig) {
144
            $clientId = sprintf('fos_elastica.client.%s', $name);
145
146
            $clientDef = new ChildDefinition('fos_elastica.client_prototype');
147
            $clientDef->replaceArgument(0, $clientConfig);
148
149
            $logger = $clientConfig['connections'][0]['logger'];
150
            if (false !== $logger) {
151
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
152
            }
153
154 18
            $clientDef->addTag('fos_elastica.client');
155
156 18
            $container->setDefinition($clientId, $clientDef);
157
158 18
            $this->clients[$name] = [
159 18
                'id' => $clientId,
160 18
                'reference' => new Reference($clientId),
161
            ];
162 18
        }
163 18
    }
164 18
165 18
    /**
166 18
     * Loads the configured indexes.
167
     *
168
     * @param array            $indexes   An array of indexes configurations
169 18
     * @param ContainerBuilder $container A ContainerBuilder instance
170 2
     *
171
     * @throws \InvalidArgumentException
172 2
     *
173
     * @return array
174
     */
175 18
    private function loadIndexes(array $indexes, ContainerBuilder $container)
176 18
    {
177
        $indexableCallbacks = [];
178 18
179 18
        foreach ($indexes as $name => $index) {
180 18
            $indexId = sprintf('fos_elastica.index.%s', $name);
181 18
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
182 18
183 18
            $indexDef = new ChildDefinition('fos_elastica.index_prototype');
184 18
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
185
            $indexDef->replaceArgument(0, $indexName);
186
            $indexDef->addTag('fos_elastica.index', [
187 18
                'name' => $name,
188
            ]);
189
190 View Code Duplication
            if (isset($index['client'])) {
191 18
                $client = $this->getClient($index['client']);
192
193
                $indexDef->setFactory([$client, 'getIndex']);
194 18
            }
195 18
196 18
            $container->setDefinition($indexId, $indexDef);
197
            $reference = new Reference($indexId);
198
199
            $this->indexConfigs[$name] = [
200
                'elasticsearch_name' => $indexName,
201
                'reference' => $reference,
202
                'name' => $name,
203
                'settings' => $index['settings'],
204
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
205
                'use_alias' => $index['use_alias'],
206
            ];
207
208
            if ($index['finder']) {
209
                $this->loadIndexFinder($container, $name, $reference);
210
            }
211
212
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
213
        }
214
215
        $indexable = $container->getDefinition('fos_elastica.indexable');
216
        $indexable->replaceArgument(0, $indexableCallbacks);
217
    }
218
219
    /**
220
     * Loads the configured indexes.
221
     *
222
     * @param array            $indexTemplates   An array of indexes configurations
223
     * @param ContainerBuilder $container A ContainerBuilder instance
224
     *
225
     * @throws \InvalidArgumentException
226
     *
227
     * @return void
228
     */
229
    private function loadIndexTemplates(array $indexTemplates, ContainerBuilder $container)
230
    {
231
        $indexableCallbacks = array();
232 18
        foreach ($indexTemplates as $name => $indexTemplate) {
233
            $indexId = sprintf('fos_elastica.index_template.%s', $name);
234 18
            $indexTemplateName = isset($indexTemplate['template_name']) ? $indexTemplate['template_name'] : $name;
235 18
236
            $indexDef = new ChildDefinition('fos_elastica.index_template_prototype');
237 18
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndexTemplate']);
238 18
            $indexDef->replaceArgument(0, $indexTemplateName);
239 18
            $indexDef->addTag('fos_elastica.index_template', array(
240 18
                'name' => $name,
241
            ));
242 18
243 View Code Duplication
            if (isset($indexTemplate['client'])) {
244
                $client = $this->getClient($indexTemplate['client']);
245 18
                $indexDef->setFactory([$client, 'getIndexTemplate']);
246
            }
247
248
            $container->setDefinition($indexId, $indexDef);
249
            $reference = new Reference($indexId);
250
251 18
            $this->indexTemplateConfigs[$name] = array(
252
                'elasticsearch_name' => $indexTemplateName,
253
                'reference' => $reference,
254
                'name' => $name,
255
                'settings' => $indexTemplate['settings'],
256
                'template' => $indexTemplate['template'],
257
            );
258
259 18
            $this->loadTypes(
260 18
                (array) $indexTemplate['types'],
261
                $container,
262
                $this->indexTemplateConfigs[$name],
263
                $indexableCallbacks
264
            );
265 18
        }
266
267
        if ($indexableCallbacks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $indexableCallbacks of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
268
            throw new \RuntimeException('`indexable_callback` option is not supported by index templates');
269
        }
270
    }
271
272
    /**
273
     * Loads the configured index finders.
274 18
     *
275 18
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
276 18
     * @param string                                                  $name      The index name
277
     * @param Reference                                               $index     Reference to the related index
278
     *
279 18
     * @return string
280
     */
281 18
    private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
282 15
    {
283
        /* Note: transformer services may conflict with "collection.index", if
284 15
         * an index and type names were "collection" and an index, respectively.
285
         */
286
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
287 18
        $transformerDef = new ChildDefinition('fos_elastica.elastica_to_model_transformer.collection');
288
        $container->setDefinition($transformerId, $transformerDef);
289 4
290
        $finderId = sprintf('fos_elastica.finder.%s', $name);
291
        $finderDef = new ChildDefinition('fos_elastica.finder');
292 18
        $finderDef->replaceArgument(0, $index);
293 4
        $finderDef->replaceArgument(1, new Reference($transformerId));
294
295
        $container->setDefinition($finderId, $finderDef);
296 18
    }
297 1
298 1
    /**
299
     * Loads the configured types.
300 1
     *
301 1
     * @param array            $types
302
     * @param ContainerBuilder $container
303
     * @param array            $indexConfig
304 1
     * @param array            $indexableCallbacks
305 1
     */
306
    private function loadTypes(array $types, ContainerBuilder $container, array &$indexConfig, array &$indexableCallbacks)
307
    {
308 1
        foreach ($types as $name => $type) {
309 1
            $indexName = $indexConfig['name'];
310
311
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
312 1
            $typeDef = new ChildDefinition('fos_elastica.type_prototype');
313 18
            $typeDef->setFactory([$indexConfig['reference'], 'getType']);
314
            $typeDef->replaceArgument(0, $name);
315
316 18
            $container->setDefinition($typeId, $typeDef);
317
318 4
            $typeConfig = [
319
                'name' => $name,
320 4
                'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch
321 4
                'config' => [],
322
            ];
323
324
            foreach ([
325 4
                'dynamic_templates',
326 4
                'properties',
327
                '_all',
328
                '_id',
329
                '_parent',
330 4
                '_routing',
331
                '_source',
332
            ] as $field) {
333
                if (isset($type[$field])) {
334 4
                    $typeConfig['mapping'][$field] = $type[$field];
335
                }
336
            }
337 4
338 4
            foreach ([
339
                'persistence',
340
                'serializer',
341
                'analyzer',
342
                'search_analyzer',
343
                'dynamic',
344 4
                'date_detection',
345
                'dynamic_date_formats',
346 4
                'numeric_detection',
347
            ] as $field) {
348
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
349
                    $type[$field] :
350
                    null;
351
            }
352
353
            $indexConfig['types'][$name] = $typeConfig;
354
355
            if (isset($type['persistence'])) {
356
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
357
358 15
                $typeConfig['persistence'] = $type['persistence'];
359
            }
360 15
361 15
            if (isset($type['_parent'])) {
362
                // _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence`
363
                unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']);
364 15
            }
365 15
366 15
            if (isset($type['indexable_callback'])) {
367
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $this->buildCallback($type['indexable_callback'], $name);
368 15
            }
369 15
370
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
371 15
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
372 15
                $typeSerializerDef = new ChildDefinition('fos_elastica.serializer_callback_prototype');
373
374 15
                if (isset($type['serializer']['groups'])) {
375 14
                    $typeSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]);
376
                }
377 15
378
                if (isset($type['serializer']['serialize_null'])) {
379
                    $typeSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]);
380
                }
381
382
                if (isset($type['serializer']['version'])) {
383
                    $typeSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]);
384
                }
385
386
                $typeDef->addMethodCall('setSerializer', [[new Reference($typeSerializerId), 'serialize']]);
387
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
388
            }
389 15
        }
390
    }
391 15
392 1
    private function buildCallback($indexCallback, $typeName)
393
    {
394
        if (is_array($indexCallback)) {
395
            if (!isset($indexCallback[0])) {
396
                throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName));
397
            }
398 14
399 14
            $classOrServiceRef = $this->transformServiceReference($indexCallback[0]);
400 14
            if ($classOrServiceRef instanceof Reference && !isset($indexCallback[1])) {
401 14
                return $classOrServiceRef; // __invoke
402
            }
403 14
404 14
            if (!isset($indexCallback[1])) {
405 14
                throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName));
406
            }
407 14
408
            return [$classOrServiceRef, $indexCallback[1]];
409 14
        }
410
411
        if (is_string($indexCallback)) {
412
            return $this->transformServiceReference($indexCallback);
413
        }
414
415
        throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName));
416
    }
417
418
    private function transformServiceReference($classOrService)
419
    {
420
        return 0 === strpos($classOrService, '@') ? new Reference(substr($classOrService, 1)) : $classOrService;
421
    }
422 15
423
    /**
424 15
     * Loads the optional provider and finder for a type.
425
     *
426
     * @param array            $typeConfig
427
     * @param ContainerBuilder $container
428 15
     * @param Reference        $typeRef
429 1
     * @param string           $indexName
430 15
     * @param string           $typeName
431
     */
432 15
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
433 15
    {
434 15
        if (isset($typeConfig['driver'])) {
435 15
            $this->loadDriver($container, $typeConfig['driver']);
436 15
        }
437
438 15
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
439
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
440 15
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
441
442
        if (isset($typeConfig['provider'])) {
443
            $this->loadTypePagerProvider($typeConfig, $container, $indexName, $typeName);
444
        }
445
        if (isset($typeConfig['finder'])) {
446
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
447
        }
448
        if (isset($typeConfig['listener']) && $typeConfig['listener']['enabled']) {
449
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
450
        }
451
    }
452
453
    /**
454
     * Creates and loads an ElasticaToModelTransformer.
455 15
     *
456
     * @param array            $typeConfig
457 15
     * @param ContainerBuilder $container
458 1
     * @param string           $indexName
459
     * @param string           $typeName
460
     *
461
     * @return string
462 14
     */
463 14
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
464 14
    {
465
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
466
            return $typeConfig['elastica_to_model_transformer']['service'];
467 14
        }
468 1
469 1
        /* Note: transformer services may conflict with "prototype.driver", if
470 1
         * the index and type names were "prototype" and a driver, respectively.
471
         */
472 13
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
473 13
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
474 13
        $serviceDef = new ChildDefinition($abstractId);
475 13
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['type' => $typeName, 'index' => $indexName]);
476 1
477
        $serviceDef->replaceArgument(1, $typeConfig['model']);
478 13
        $serviceDef->replaceArgument(2, array_merge($typeConfig['elastica_to_model_transformer'], [
479
            'identifier' => $typeConfig['identifier'],
480
        ]));
481 14
        $container->setDefinition($serviceId, $serviceDef);
482
483 14
        return $serviceId;
484 14
    }
485 14
486 14
    /**
487
     * Creates and loads a ModelToElasticaTransformer for an index/type.
488
     *
489 14
     * @param array            $typeConfig
490
     * @param ContainerBuilder $container
491 14
     * @param string           $indexName
492
     * @param string           $typeName
493 14
     *
494
     * @return string
495
     */
496
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
497
    {
498
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
499
            return $typeConfig['model_to_elastica_transformer']['service'];
500
        }
501
502
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
503
            'fos_elastica.model_to_elastica_identifier_transformer' :
504
            'fos_elastica.model_to_elastica_transformer';
505
506 15
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
507
        $serviceDef = new ChildDefinition($abstractId);
508 15
        $serviceDef->replaceArgument(0, [
509
            'identifier' => $typeConfig['identifier'],
510
            'index' => $indexName,
511
        ]);
512 15
        $container->setDefinition($serviceId, $serviceDef);
513 15
514
        return $serviceId;
515 15
    }
516
517 15
    /**
518 15
     * Creates and loads an object persister for a type.
519 14
     *
520 14
     * @param array            $typeConfig
521 14
     * @param Reference        $typeRef
522
     * @param ContainerBuilder $container
523 14
     * @param string           $indexName
524 1
     * @param string           $typeName
525
     * @param string           $transformerId
526
     *
527
     * @return string
528
     */
529
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
530 1
    {
531 1
        if (isset($typeConfig['persister']['service'])) {
532 1
            return $typeConfig['persister']['service'];
533 1
        }
534
535 1
        $arguments = [
536
            $typeRef,
537
            new Reference($transformerId),
538
            $typeConfig['model'],
539
        ];
540
541
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
542
            $abstractId = 'fos_elastica.object_serializer_persister';
543 15
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
544 15
            $arguments[] = [new Reference($callbackId), 'serialize'];
545
        } else {
546 15
            $abstractId = 'fos_elastica.object_persister';
547
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
548 15
            $argument = $mapping['properties'];
549
            if (isset($mapping['_parent'])) {
550
                $argument['_parent'] = $mapping['_parent'];
551
            }
552
            $arguments[] = $argument;
553
        }
554
555
        $arguments[] = array_intersect_key($typeConfig['persister'], array_flip(['refresh']));
556
557
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
558
        $serviceDef = new ChildDefinition($abstractId);
559
        foreach ($arguments as $i => $argument) {
560
            $serviceDef->replaceArgument($i, $argument);
561
        }
562 14
563
        $serviceDef->addTag('fos_elastica.persister', ['index' => $indexName, 'type' => $typeName]);
564 14
565
        $container->setDefinition($serviceId, $serviceDef);
566
567
        return $serviceId;
568
    }
569
570
    /**
571 14
     * Loads a pager provider for a type.
572 14
     *
573 14
     * @param array            $typeConfig
574 14
     * @param ContainerBuilder $container
575 14
     * @param string           $indexName
576
     * @param string           $typeName
577 14
     *
578
     * @return string
579
     */
580 14
    private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
581 14
    {
582 14
        if (isset($typeConfig['provider']['service'])) {
583
            return $typeConfig['provider']['service'];
584
        }
585 14
586 14
        $baseConfig = $typeConfig['provider'];
587 14
        unset($baseConfig['service']);
588 13
589 13
        $driver = $typeConfig['driver'];
590 1
591 1
        switch ($driver) {
592 1
            case 'orm':
593
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
594
                $providerDef->replaceArgument(2, $typeConfig['model']);
595
                $providerDef->replaceArgument(3, $baseConfig);
596
597
                break;
598 14 View Code Duplication
            case 'mongodb':
599
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
600
                $providerDef->replaceArgument(2, $typeConfig['model']);
601
                $providerDef->replaceArgument(3, $baseConfig);
602
603
                break;
604 View Code Duplication
            case 'phpcr':
605
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
606
                $providerDef->replaceArgument(2, $typeConfig['model']);
607
                $providerDef->replaceArgument(3, $baseConfig);
608
609
                break;
610
            default:
611 14
                throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver));
612
        }
613 14
614 14
        /* Note: provider services may conflict with "prototype.driver", if the
615 14
         * index and type names were "prototype" and a driver, respectively.
616
         */
617
        $providerId = sprintf('fos_elastica.pager_provider.%s.%s', $indexName, $typeName);
618
        $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName, 'type' => $typeName]);
619 14
620
        $container->setDefinition($providerId, $providerDef);
621 14
622
        return $providerId;
623
    }
624
625
    /**
626
     * Loads doctrine listeners to handle indexing of new or updated objects.
627 14
     *
628
     * @param array            $typeConfig
629 14
     * @param ContainerBuilder $container
630 14
     * @param string           $objectPersisterId
631 13
     * @param string           $indexName
632 13
     * @param string           $typeName
633 1
     *
634 1
     * @return string
635 1
     */
636
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
637
    {
638
        if (isset($typeConfig['listener']['service'])) {
639
            return $typeConfig['listener']['service'];
640
        }
641
642
        /* Note: listener services may conflict with "prototype.driver", if the
643 14
         * index and type names were "prototype" and a driver, respectively.
644
         */
645 14
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
646 14
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
647 14
        $listenerDef = new ChildDefinition($abstractListenerId);
648 14
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
649
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
650
            new Reference($typeConfig['listener']['logger']) :
651 14
            null
652 14
        );
653 14
        $listenerConfig = [
654
            'identifier' => $typeConfig['identifier'],
655
            'indexName' => $indexName,
656
            'typeName' => $typeName,
657 14
        ];
658
659
        $tagName = null;
660
        switch ($typeConfig['driver']) {
661
            case 'orm':
662
                $tagName = 'doctrine.event_listener';
663
                break;
664
            case 'phpcr':
665
                $tagName = 'doctrine_phpcr.event_listener';
666
                break;
667
            case 'mongodb':
668
                $tagName = 'doctrine_mongodb.odm.event_listener';
669
                break;
670
        }
671
672 15
        if ($typeConfig['listener']['defer']) {
673
            $listenerDef->setPublic(true);
674 15
            $listenerDef->addTag(
675
                'kernel.event_listener',
676
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
677 15
            );
678 15
            $listenerDef->addTag(
679 15
                'kernel.event_listener',
680 15
                ['event' => 'console.terminate', 'method' => 'onTerminate']
681 15
            );
682
            $listenerConfig['defer'] = true;
683
        }
684 15
685 15
        $listenerDef->replaceArgument(2, $listenerConfig);
686 15
687 4
        if (null !== $tagName) {
688
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
689
                $listenerDef->addTag($tagName, ['event' => $event]);
690 15
            }
691 15
        }
692
693 15
        $container->setDefinition($listenerId, $listenerDef);
694 15
695 15
        return $listenerId;
696
    }
697 15
698
    /**
699
     * Map Elastica to Doctrine events for the current driver.
700
     */
701
    private function getDoctrineEvents(array $typeConfig)
702
    {
703
        switch ($typeConfig['driver']) {
704
            case 'orm':
705
                $eventsClass = '\Doctrine\ORM\Events';
706
                break;
707 18
            case 'phpcr':
708 18
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
709 18
                break;
710
            case 'mongodb':
711 18
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
712 18
                break;
713 18
            default:
714
                throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
715
        }
716
717
        $events = [];
718
        $eventMapping = [
719
            'insert' => [constant($eventsClass.'::postPersist')],
720
            'update' => [constant($eventsClass.'::postUpdate')],
721 15
            'delete' => [constant($eventsClass.'::preRemove')],
722
            'flush' => [constant($eventsClass.'::postFlush')],
723 15
        ];
724 6
725
        foreach ($eventMapping as $event => $doctrineEvents) {
726
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
727 15
                $events = array_merge($events, $doctrineEvents);
728 15
            }
729 15
        }
730 15
731
        return $events;
732
    }
733
734
    /**
735
     * Loads a Type specific Finder.
736
     *
737
     * @param array            $typeConfig
738 1
     * @param ContainerBuilder $container
739
     * @param string           $elasticaToModelId
740 1
     * @param Reference        $typeRef
741
     * @param string           $indexName
742 1
     * @param string           $typeName
743 1
     *
744
     * @return string
745 1
     */
746
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
747
    {
748 1
        if (isset($typeConfig['finder']['service'])) {
749
            $finderId = $typeConfig['finder']['service'];
750
        } else {
751
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
752
            $finderDef = new ChildDefinition('fos_elastica.finder');
753
            $finderDef->replaceArgument(0, $typeRef);
754
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
755
            $container->setDefinition($finderId, $finderDef);
756 18
        }
757
758 18
        $indexTypeName = "$indexName/$typeName";
759 3
        $arguments = [$indexTypeName, new Reference($finderId)];
760
        if (isset($typeConfig['repository'])) {
761
            $arguments[] = $typeConfig['repository'];
762 15
        }
763 15
764
        $container->getDefinition('fos_elastica.repository_manager')
765
            ->addMethodCall('addType', $arguments);
766
767 15
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
768
        $container->getDefinition($managerId)
769
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]);
770 15
771 15
        return $finderId;
772 15
    }
773 15
774 15
    /**
775
     * Loads the index manager.
776
     *
777
     * @param ContainerBuilder $container
778
     **/
779 View Code Duplication
    private function loadIndexManager(ContainerBuilder $container)
780
    {
781
        $indexRefs = array_map(function ($index) {
782
            return $index['reference'];
783
        }, $this->indexConfigs);
784
785 2
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
786
        $managerDef->replaceArgument(0, $indexRefs);
787 2
    }
788
789
    /**
790
     * Load index template manager
791 2
     *
792
     * @param ContainerBuilder $container
793
     *
794
     * @return void
795
     */
796 View Code Duplication
    private function loadIndexTemplateManager(ContainerBuilder $container)
797
    {
798
        $indexTemplateRefs = array_map(function ($index) {
799
            return $index['reference'];
800
        }, $this->indexTemplateConfigs);
801
802
        $managerDef = $container->getDefinition('fos_elastica.index_template_manager');
803
        $managerDef->replaceArgument(0, $indexTemplateRefs);
804
    }
805
806
    /**
807
     * Makes sure a specific driver has been loaded.
808
     *
809
     * @param ContainerBuilder $container
810
     * @param string           $driver
811
     */
812
    private function loadDriver(ContainerBuilder $container, $driver)
813
    {
814
        if (in_array($driver, $this->loadedDrivers)) {
815
            return;
816
        }
817
818
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
819
        $loader->load($driver.'.xml');
820
        $this->loadedDrivers[] = $driver;
821
    }
822
823
    /**
824
     * Loads and configures the serializer prototype.
825
     *
826
     * @param array            $config
827
     * @param ContainerBuilder $container
828
     */
829
    private function loadSerializer($config, ContainerBuilder $container)
830
    {
831
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
832
833
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
834
        $serializer->setClass($config['callback_class']);
835
836
        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...
837
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
838
        }
839
    }
840
841
    /**
842
     * Creates a default manager alias for defined default manager or the first loaded driver.
843
     *
844
     * @param string           $defaultManager
845
     * @param ContainerBuilder $container
846
     */
847
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
848
    {
849
        if (0 == count($this->loadedDrivers)) {
850
            return;
851
        }
852
853
        if (count($this->loadedDrivers) > 1
854
            && in_array($defaultManager, $this->loadedDrivers)
855
        ) {
856
            $defaultManagerService = $defaultManager;
857
        } else {
858
            $defaultManagerService = $this->loadedDrivers[0];
859
        }
860
861
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
862
        $container->getAlias('fos_elastica.manager')->setPublic(true);
863
        $container->setAlias(RepositoryManagerInterface::class, 'fos_elastica.manager');
864
        $container->getAlias(RepositoryManagerInterface::class)->setPublic(false);
865
    }
866
867
    /**
868
     * Returns a reference to a client given its configured name.
869
     *
870
     * @param string $clientName
871
     *
872
     * @return Reference
873
     *
874
     * @throws \InvalidArgumentException
875
     */
876
    private function getClient($clientName)
877
    {
878
        if (!array_key_exists($clientName, $this->clients)) {
879
            throw new \InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
880
        }
881
882
        return $this->clients[$clientName]['reference'];
883
    }
884
}
885