Completed
Push — master ( 7b9575...49c7e6 )
by Maksim
17s
created

FOSElasticaExtension::buildCallback()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 8.4275

Importance

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