Completed
Pull Request — master (#1326)
by
unknown
03:42
created

FOSElasticaExtension::loadIndexes()   B

Complexity

Conditions 6
Paths 17

Size

Total Lines 43
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 6.0016

Importance

Changes 0
Metric Value
dl 0
loc 43
ccs 27
cts 28
cp 0.9643
rs 8.439
c 0
b 0
f 0
cc 6
eloc 27
nc 17
nop 2
crap 6.0016
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 Pagerfanta\Pagerfanta;
16
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\DefinitionDecorator;
19
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
22
23
class FOSElasticaExtension extends Extension
24
{
25
    /**
26
     * Definition of elastica clients as configured by this extension.
27
     *
28
     * @var array
29
     */
30
    private $clients = [];
31
32
    /**
33
     * An array of indexes as configured by the extension.
34
     *
35
     * @var array
36
     */
37
    private $indexConfigs = [];
38
39
    /**
40
     * If we've encountered a type mapped to a specific persistence driver, it will be loaded
41
     * here.
42
     *
43
     * @var array
44
     */
45
    private $loadedDrivers = [];
46
47 17
    public function load(array $configs, ContainerBuilder $container)
48
    {
49 17
        $configuration = $this->getConfiguration($configs, $container);
50 17
        $config = $this->processConfiguration($configuration, $configs);
51
52 17
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
53
54 17
        if (empty($config['clients']) || empty($config['indexes'])) {
55
            // No Clients or indexes are defined
56
            return;
57
        }
58
59 17
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener'] as $basename) {
60 17
            $loader->load(sprintf('%s.xml', $basename));
61
        }
62
63 17
        if (empty($config['default_client'])) {
64 17
            $keys = array_keys($config['clients']);
65 17
            $config['default_client'] = reset($keys);
66
        }
67
68 17
        if (empty($config['default_index'])) {
69 17
            $keys = array_keys($config['indexes']);
70 17
            $config['default_index'] = reset($keys);
71
        }
72
73 17
        if (isset($config['serializer'])) {
74 1
            $loader->load('serializer.xml');
75
76 1
            $this->loadSerializer($config['serializer'], $container);
77
        }
78
79 17
        $this->loadClients($config['clients'], $container);
80 17
        $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
81
82 17
        $this->loadIndexes($config['indexes'], $container);
83 17
        $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
84 17
        $container->setParameter('fos_elastica.default_index', $config['default_index']);
85
86 17
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
87
88 17
        $this->loadIndexManager($container);
89
90 17
        $this->createDefaultManagerAlias($config['default_manager'], $container);
91 17
    }
92
93
    /**
94
     * @param array            $config
95
     * @param ContainerBuilder $container
96
     *
97
     * @return Configuration
98
     */
99 17
    public function getConfiguration(array $config, ContainerBuilder $container)
100
    {
101 17
        return new Configuration($container->getParameter('kernel.debug'));
102
    }
103
104
    /**
105
     * Loads the configured clients.
106
     *
107
     * @param array            $clients   An array of clients configurations
108
     * @param ContainerBuilder $container A ContainerBuilder instance
109
     *
110
     * @return array
111
     */
112 17
    private function loadClients(array $clients, ContainerBuilder $container)
113
    {
114 17
        foreach ($clients as $name => $clientConfig) {
115 17
            $clientId = sprintf('fos_elastica.client.%s', $name);
116
117 17
            $clientDef = new DefinitionDecorator('fos_elastica.client_prototype');
118 17
            $clientDef->replaceArgument(0, $clientConfig);
119
120 17
            $logger = $clientConfig['connections'][0]['logger'];
121 17
            if (false !== $logger) {
122 17
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
123
            }
124
125 17
            $clientDef->addTag('fos_elastica.client');
126
127 17
            $container->setDefinition($clientId, $clientDef);
128
129 17
            $this->clients[$name] = [
130 17
                'id' => $clientId,
131 17
                'reference' => new Reference($clientId),
132
            ];
133
        }
134 17
    }
135
136
    /**
137
     * Loads the configured indexes.
138
     *
139
     * @param array            $indexes   An array of indexes configurations
140
     * @param ContainerBuilder $container A ContainerBuilder instance
141
     *
142
     * @throws \InvalidArgumentException
143
     *
144
     * @return array
145
     */
146 17
    private function loadIndexes(array $indexes, ContainerBuilder $container)
147
    {
148 17
        $indexableCallbacks = [];
149
150 17
        foreach ($indexes as $name => $index) {
151 17
            $indexId = sprintf('fos_elastica.index.%s', $name);
152 17
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
153
154 17
            $indexDef = new DefinitionDecorator('fos_elastica.index_prototype');
155 17
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
156 17
            $indexDef->replaceArgument(0, $indexName);
157 17
            $indexDef->addTag('fos_elastica.index', [
158 17
                'name' => $name,
159
            ]);
160
161 17
            if (isset($index['client'])) {
162 2
                $client = $this->getClient($index['client']);
163
164 2
                $indexDef->setFactory([$client, 'getIndex']);
165
            }
166
167 17
            $container->setDefinition($indexId, $indexDef);
168 17
            $reference = new Reference($indexId);
169
170 17
            $this->indexConfigs[$name] = [
171 17
                'elasticsearch_name' => $indexName,
172 17
                'reference' => $reference,
173 17
                'name' => $name,
174 17
                'settings' => $index['settings'],
175 17
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
176 17
                'use_alias' => $index['use_alias'],
177
            ];
178
179 17
            if ($index['finder']) {
180
                $this->loadIndexFinder($container, $name, $reference);
181
            }
182
183 17
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
184
        }
185
186 17
        $indexable = $container->getDefinition('fos_elastica.indexable');
187 17
        $indexable->replaceArgument(0, $indexableCallbacks);
188 17
    }
189
190
    /**
191
     * Loads the configured index finders.
192
     *
193
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
194
     * @param string                                                  $name      The index name
195
     * @param Reference                                               $index     Reference to the related index
196
     *
197
     * @return string
198
     */
199
    private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
200
    {
201
        /* Note: transformer services may conflict with "collection.index", if
202
         * an index and type names were "collection" and an index, respectively.
203
         */
204
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
205
        $transformerDef = new DefinitionDecorator('fos_elastica.elastica_to_model_transformer.collection');
206
        $container->setDefinition($transformerId, $transformerDef);
207
208
        $finderId = sprintf('fos_elastica.finder.%s', $name);
209
        $finderDef = new DefinitionDecorator('fos_elastica.finder');
210
        $finderDef->replaceArgument(0, $index);
211
        $finderDef->replaceArgument(1, new Reference($transformerId));
212
213
        $container->setDefinition($finderId, $finderDef);
214
    }
215
216
    /**
217
     * Loads the configured types.
218
     *
219
     * @param array            $types
220
     * @param ContainerBuilder $container
221
     * @param array            $indexConfig
222
     * @param array            $indexableCallbacks
223
     */
224 17
    private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
225
    {
226 17
        foreach ($types as $name => $type) {
227 17
            $indexName = $indexConfig['name'];
228
229 17
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
230 17
            $typeDef = new DefinitionDecorator('fos_elastica.type_prototype');
231 17
            $typeDef->setFactory([$indexConfig['reference'], 'getType']);
232 17
            $typeDef->replaceArgument(0, $name);
233
234 17
            $container->setDefinition($typeId, $typeDef);
235
236
            $typeConfig = [
237 17
                'name' => $name,
238
                'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch
239
                'config' => [],
240
            ];
241
242
            foreach ([
243 17
                'dynamic_templates',
244
                'properties',
245
                '_all',
246
                '_id',
247
                '_parent',
248
                '_routing',
249
                '_source',
250
            ] as $field) {
251 17
                if (isset($type[$field])) {
252 17
                    $typeConfig['mapping'][$field] = $type[$field];
253
                }
254
            }
255
256
            foreach ([
257 17
                'persistence',
258
                'serializer',
259
                'analyzer',
260
                'search_analyzer',
261
                'dynamic',
262
                'date_detection',
263
                'dynamic_date_formats',
264
                'numeric_detection',
265
            ] as $field) {
266 17
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
267 17
                    $type[$field] :
268 17
                    null;
269
            }
270
271 17
            $this->indexConfigs[$indexName]['types'][$name] = $typeConfig;
272
273 17
            if (isset($type['persistence'])) {
274 14
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
275
276 14
                $typeConfig['persistence'] = $type['persistence'];
277
            }
278
279 17
            if (isset($type['_parent'])) {
280
                // _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence`
281 4
                unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']);
282
            }
283
284 17
            if (isset($type['indexable_callback'])) {
285 4
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback'];
286
            }
287
288 17
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
289 1
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
290 1
                $typeSerializerDef = new DefinitionDecorator('fos_elastica.serializer_callback_prototype');
291
292 1
                if (isset($type['serializer']['groups'])) {
293 1
                    $typeSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]);
294
                }
295
296 1
                if (isset($type['serializer']['serialize_null'])) {
297 1
                    $typeSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]);
298
                }
299
300 1
                if (isset($type['serializer']['version'])) {
301 1
                    $typeSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]);
302
                }
303
304 1
                $typeDef->addMethodCall('setSerializer', [[new Reference($typeSerializerId), 'serialize']]);
305 17
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
306
            }
307
        }
308 17
    }
309
310
    /**
311
     * Loads the optional provider and finder for a type.
312
     *
313
     * @param array            $typeConfig
314
     * @param ContainerBuilder $container
315
     * @param Reference        $typeRef
316
     * @param string           $indexName
317
     * @param string           $typeName
318
     */
319 14
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
320
    {
321 14
        if (isset($typeConfig['driver'])) {
322 14
            $this->loadDriver($container, $typeConfig['driver']);
323
        }
324
325 14
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
326 14
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
327 14
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
328
329 14
        if (isset($typeConfig['provider'])) {
330 14
            $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
331
332 14
            if (isset($typeConfig['provider']['pager_provider']) && $typeConfig['provider']['pager_provider']) {
333 6
                if (!class_exists(Pagerfanta::class)) {
334
                    throw new \InvalidArgumentException('A pager provider needs "pagerfanta/pagerfanta:^1"  to be installed.');
335
                }
336
337 6
                $this->loadTypePagerProvider($typeConfig, $container, $indexName, $typeName);
338
            }
339
        }
340 14
        if (isset($typeConfig['finder'])) {
341 14
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
342
        }
343 14
        if (isset($typeConfig['listener'])) {
344 14
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
345
        }
346 14
    }
347
348
    /**
349
     * Creates and loads an ElasticaToModelTransformer.
350
     *
351
     * @param array            $typeConfig
352
     * @param ContainerBuilder $container
353
     * @param string           $indexName
354
     * @param string           $typeName
355
     *
356
     * @return string
357
     */
358 14
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
359
    {
360 14
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
361 1
            return $typeConfig['elastica_to_model_transformer']['service'];
362
        }
363
364
        /* Note: transformer services may conflict with "prototype.driver", if
365
         * the index and type names were "prototype" and a driver, respectively.
366
         */
367 13
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
368 13
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
369 13
        $serviceDef = new DefinitionDecorator($abstractId);
370 13
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['type' => $typeName, 'index' => $indexName]);
371
372
        // Doctrine has a mandatory service as first argument
373 13
        $argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
374
375 13
        $serviceDef->replaceArgument($argPos, $typeConfig['model']);
376 13
        $serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], [
377 13
            'identifier' => $typeConfig['identifier'],
378
        ]));
379 13
        $container->setDefinition($serviceId, $serviceDef);
380
381 13
        return $serviceId;
382
    }
383
384
    /**
385
     * Creates and loads a ModelToElasticaTransformer for an index/type.
386
     *
387
     * @param array            $typeConfig
388
     * @param ContainerBuilder $container
389
     * @param string           $indexName
390
     * @param string           $typeName
391
     *
392
     * @return string
393
     */
394 14
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
395
    {
396 14
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
397
            return $typeConfig['model_to_elastica_transformer']['service'];
398
        }
399
400 14
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
401 1
            'fos_elastica.model_to_elastica_identifier_transformer' :
402 14
            'fos_elastica.model_to_elastica_transformer';
403
404 14
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
405 14
        $serviceDef = new DefinitionDecorator($abstractId);
406 14
        $serviceDef->replaceArgument(0, [
407 14
            'identifier' => $typeConfig['identifier'],
408
        ]);
409 14
        $container->setDefinition($serviceId, $serviceDef);
410
411 14
        return $serviceId;
412
    }
413
414
    /**
415
     * Creates and loads an object persister for a type.
416
     *
417
     * @param array            $typeConfig
418
     * @param Reference        $typeRef
419
     * @param ContainerBuilder $container
420
     * @param string           $indexName
421
     * @param string           $typeName
422
     * @param string           $transformerId
423
     *
424
     * @return string
425
     */
426 14
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
427
    {
428 14
        if (isset($typeConfig['persister']['service'])) {
429 1
            return $typeConfig['persister']['service'];
430
        }
431
432
        $arguments = [
433 13
            $typeRef,
434 13
            new Reference($transformerId),
435 13
            $typeConfig['model'],
436
        ];
437
438 13
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
439 1
            $abstractId = 'fos_elastica.object_serializer_persister';
440 1
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
441 1
            $arguments[] = [new Reference($callbackId), 'serialize'];
442
        } else {
443 12
            $abstractId = 'fos_elastica.object_persister';
444 12
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
445 12
            $argument = $mapping['properties'];
446 12
            if (isset($mapping['_parent'])) {
447 1
                $argument['_parent'] = $mapping['_parent'];
448
            }
449 12
            $arguments[] = $argument;
450
        }
451
452 13
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
453 13
        $serviceDef = new DefinitionDecorator($abstractId);
454 13
        foreach ($arguments as $i => $argument) {
455 13
            $serviceDef->replaceArgument($i, $argument);
456
        }
457
458 13
        $serviceDef->addTag('fos_elastica.persister', ['index' => $indexName, 'type' => $typeName]);
459
460 13
        $container->setDefinition($serviceId, $serviceDef);
461
462 13
        return $serviceId;
463
    }
464
465
    /**
466
     * Loads a provider for a type.
467
     *
468
     * @param array            $typeConfig
469
     * @param ContainerBuilder $container
470
     * @param string           $objectPersisterId
471
     * @param string           $indexName
472
     * @param string           $typpeName
0 ignored issues
show
Documentation introduced by
There is no parameter named $typpeName. Did you maybe mean $typeName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
473
     *
474
     * @return string
475
     */
476 14
    private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
477
    {
478 14
        if (isset($typeConfig['provider']['service'])) {
479
            return $typeConfig['provider']['service'];
480
        }
481
482
        /* Note: provider services may conflict with "prototype.driver", if the
483
         * index and type names were "prototype" and a driver, respectively.
484
         */
485 14
        $providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName);
486 14
        $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.'.$typeConfig['driver']);
487 14
        $providerDef->addTag('fos_elastica.provider', ['index' => $indexName, 'type' => $typeName]);
488 14
        $providerDef->replaceArgument(0, new Reference($objectPersisterId));
489 14
        $providerDef->replaceArgument(2, $typeConfig['model']);
490
        // Propel provider can simply ignore Doctrine-specific options
491 14
        $providerDef->replaceArgument(3, array_merge(array_diff_key($typeConfig['provider'], ['service' => 1]), [
492 14
            'indexName' => $indexName,
493 14
            'typeName' => $typeName,
494
        ]));
495 14
        $container->setDefinition($providerId, $providerDef);
496
497 14
        return $providerId;
498
    }
499
500
    /**
501
     * Loads a pager provider for a type.
502
     *
503
     * @param array            $typeConfig
504
     * @param ContainerBuilder $container
505
     * @param string           $indexName
506
     * @param string           $typeName
507
     *
508
     * @return string
509
     */
510 6
    private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
511
    {
512
//     TODO don't forget to uncomment in master branch
513
//        if (isset($typeConfig['provider']['service'])) {
514
//            return $typeConfig['provider']['service'];
515
//        }
516
517 6
        $baseConfig = $typeConfig['provider'];
518 6
        unset($baseConfig['service']);
519
520 6
        $driver = $typeConfig['driver'];
521
522
        switch ($driver) {
523 6
            case 'orm':
524 2
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
525 2
                $providerDef->replaceArgument(2, $typeConfig['model']);
526 2
                $providerDef->replaceArgument(3, $baseConfig);
527
528 2
                break;
529 4 View Code Duplication
            case 'mongodb':
530
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
531
                $providerDef->replaceArgument(2, $typeConfig['model']);
532
                $providerDef->replaceArgument(3, $baseConfig);
533
534
                break;
535 4 View Code Duplication
            case 'phpcr':
536 1
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
537 1
                $providerDef->replaceArgument(2, $typeConfig['model']);
538 1
                $providerDef->replaceArgument(3, $baseConfig);
539
540 1
                break;
541 3 View Code Duplication
            case 'propel':
542 3
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
543 3
                $providerDef->replaceArgument(0, $typeConfig['model']);
544 3
                $providerDef->replaceArgument(1, $baseConfig);
545
546 3
                break;
547
            default:
548
                throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver));
549
        }
550
551
        /* Note: provider services may conflict with "prototype.driver", if the
552
         * index and type names were "prototype" and a driver, respectively.
553
         */
554 6
        $providerId = sprintf('fos_elastica.pager_provider.%s.%s', $indexName, $typeName);
555 6
        $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName, 'type' => $typeName]);
556
557 6
        $container->setDefinition($providerId, $providerDef);
558
559 6
        return $providerId;
560
    }
561
562
    /**
563
     * Loads doctrine listeners to handle indexing of new or updated objects.
564
     *
565
     * @param array            $typeConfig
566
     * @param ContainerBuilder $container
567
     * @param string           $objectPersisterId
568
     * @param string           $indexName
569
     * @param string           $typeName
570
     *
571
     * @return string
572
     */
573 14
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
574
    {
575 14
        if (isset($typeConfig['listener']['service'])) {
576
            return $typeConfig['listener']['service'];
577
        }
578
579
        /* Note: listener services may conflict with "prototype.driver", if the
580
         * index and type names were "prototype" and a driver, respectively.
581
         */
582 14
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
583 14
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
584 14
        $listenerDef = new DefinitionDecorator($abstractListenerId);
585 14
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
586 14
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
587
            new Reference($typeConfig['listener']['logger']) :
588 14
            null
589
        );
590
        $listenerConfig = [
591 14
            'identifier' => $typeConfig['identifier'],
592 14
            'indexName' => $indexName,
593 14
            'typeName' => $typeName,
594
        ];
595
596 14
        $tagName = null;
597 14
        switch ($typeConfig['driver']) {
598 14
            case 'orm':
599 10
                $tagName = 'doctrine.event_listener';
600 10
                break;
601 4
            case 'phpcr':
602 1
                $tagName = 'doctrine_phpcr.event_listener';
603 1
                break;
604 3
            case 'mongodb':
605
                $tagName = 'doctrine_mongodb.odm.event_listener';
606
                break;
607
        }
608
609 14
        if ($typeConfig['listener']['defer']) {
610
            $listenerDef->setPublic(true);
611
            $listenerDef->addTag(
612
                'kernel.event_listener',
613
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
614
            );
615
            $listenerDef->addTag(
616
                'kernel.event_listener',
617
                ['event' => 'console.terminate', 'method' => 'onTerminate']
618
            );
619
            $listenerConfig['defer'] = true;
620
        }
621
622 14
        $listenerDef->replaceArgument(2, $listenerConfig);
623
624 14
        if (null !== $tagName) {
625 11
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
626 11
                $listenerDef->addTag($tagName, ['event' => $event]);
627
            }
628
        }
629
630 14
        $container->setDefinition($listenerId, $listenerDef);
631
632 14
        return $listenerId;
633
    }
634
635
    /**
636
     * Map Elastica to Doctrine events for the current driver.
637
     */
638 11
    private function getDoctrineEvents(array $typeConfig)
639
    {
640 11
        switch ($typeConfig['driver']) {
641 11
            case 'orm':
642 10
                $eventsClass = '\Doctrine\ORM\Events';
643 10
                break;
644 1
            case 'phpcr':
645 1
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
646 1
                break;
647
            case 'mongodb':
648
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
649
                break;
650
            default:
651
                throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
652
        }
653
654 11
        $events = [];
655
        $eventMapping = [
656 11
            'insert' => [constant($eventsClass.'::postPersist')],
657 11
            'update' => [constant($eventsClass.'::postUpdate')],
658 11
            'delete' => [constant($eventsClass.'::preRemove')],
659 11
            'flush' => [constant($eventsClass.'::postFlush')],
660
        ];
661
662 11
        foreach ($eventMapping as $event => $doctrineEvents) {
663 11
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
664 11
                $events = array_merge($events, $doctrineEvents);
665
            }
666
        }
667
668 11
        return $events;
669
    }
670
671
    /**
672
     * Loads a Type specific Finder.
673
     *
674
     * @param array            $typeConfig
675
     * @param ContainerBuilder $container
676
     * @param string           $elasticaToModelId
677
     * @param Reference        $typeRef
678
     * @param string           $indexName
679
     * @param string           $typeName
680
     *
681
     * @return string
682
     */
683 14
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
684
    {
685 14
        if (isset($typeConfig['finder']['service'])) {
686
            $finderId = $typeConfig['finder']['service'];
687
        } else {
688 14
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
689 14
            $finderDef = new DefinitionDecorator('fos_elastica.finder');
690 14
            $finderDef->replaceArgument(0, $typeRef);
691 14
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
692 14
            $container->setDefinition($finderId, $finderDef);
693
        }
694
695 14
        $indexTypeName = "$indexName/$typeName";
696 14
        $arguments = [$indexTypeName, new Reference($finderId)];
697 14
        if (isset($typeConfig['repository'])) {
698 4
            $arguments[] = $typeConfig['repository'];
699
        }
700
701 14
        $container->getDefinition('fos_elastica.repository_manager')
702 14
            ->addMethodCall('addType', $arguments);
703
704 14
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
705 14
        $container->getDefinition($managerId)
706 14
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]);
707
708 14
        return $finderId;
709
    }
710
711
    /**
712
     * Loads the index manager.
713
     *
714
     * @param ContainerBuilder $container
715
     **/
716
    private function loadIndexManager(ContainerBuilder $container)
717
    {
718 17
        $indexRefs = array_map(function ($index) {
719 17
            return $index['reference'];
720 17
        }, $this->indexConfigs);
721
722 17
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
723 17
        $managerDef->replaceArgument(0, $indexRefs);
724 17
    }
725
726
    /**
727
     * Makes sure a specific driver has been loaded.
728
     *
729
     * @param ContainerBuilder $container
730
     * @param string           $driver
731
     */
732 14
    private function loadDriver(ContainerBuilder $container, $driver)
733
    {
734 14
        if (in_array($driver, $this->loadedDrivers)) {
735 6
            return;
736
        }
737
738 14
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
739 14
        $loader->load($driver.'.xml');
740 14
        $this->loadedDrivers[] = $driver;
741 14
    }
742
743
    /**
744
     * Loads and configures the serializer prototype.
745
     *
746
     * @param array            $config
747
     * @param ContainerBuilder $container
748
     */
749 1
    private function loadSerializer($config, ContainerBuilder $container)
750
    {
751 1
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
752
753 1
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
754 1
        $serializer->setClass($config['callback_class']);
755
756 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...
757
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
758
        }
759 1
    }
760
761
    /**
762
     * Creates a default manager alias for defined default manager or the first loaded driver.
763
     *
764
     * @param string           $defaultManager
765
     * @param ContainerBuilder $container
766
     */
767 17
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
768
    {
769 17
        if (0 == count($this->loadedDrivers)) {
770 3
            return;
771
        }
772
773 14
        if (count($this->loadedDrivers) > 1
774 14
            && in_array($defaultManager, $this->loadedDrivers)
775
        ) {
776
            $defaultManagerService = $defaultManager;
777
        } else {
778 14
            $defaultManagerService = $this->loadedDrivers[0];
779
        }
780
781 14
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
782 14
    }
783
784
    /**
785
     * Returns a reference to a client given its configured name.
786
     *
787
     * @param string $clientName
788
     *
789
     * @return Reference
790
     *
791
     * @throws \InvalidArgumentException
792
     */
793 2
    private function getClient($clientName)
794
    {
795 2
        if (!array_key_exists($clientName, $this->clients)) {
796
            throw new \InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
797
        }
798
799 2
        return $this->clients[$clientName]['reference'];
800
    }
801
}
802