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

FOSElasticaExtension::createDefaultManagerAlias()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0092

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 11
cts 12
cp 0.9167
rs 9.6333
c 0
b 0
f 0
cc 4
nc 3
nop 2
crap 4.0092
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
     * If we've encountered a type mapped to a specific persistence driver, it will be loaded
51
     * here.
52
     *
53
     * @var array
54
     */
55
    private $loadedDrivers = [];
56
57 18
    public function load(array $configs, ContainerBuilder $container)
58
    {
59 18
        $configuration = $this->getConfiguration($configs, $container);
60 18
        $config = $this->processConfiguration($configuration, $configs);
61
62 18
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
63
64 18
        if (empty($config['clients']) || empty($config['indexes'])) {
65
            // No Clients or indexes are defined
66
            return;
67
        }
68
69 18
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener', 'commands'] as $basename) {
70 18
            $loader->load(sprintf('%s.xml', $basename));
71
        }
72
73 18
        if (empty($config['default_client'])) {
74 18
            $keys = array_keys($config['clients']);
75 18
            $config['default_client'] = reset($keys);
76
        }
77
78 18
        if (empty($config['default_index'])) {
79 18
            $keys = array_keys($config['indexes']);
80 18
            $config['default_index'] = reset($keys);
81
        }
82
83 18
        if (isset($config['serializer'])) {
84 1
            $loader->load('serializer.xml');
85
86 1
            $this->loadSerializer($config['serializer'], $container);
87
        }
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 18
        $container->setAlias(Client::class, 'fos_elastica.client');
94 18
        $container->getAlias(Client::class)->setPublic(false);
95
96 18
        $this->loadIndexes($config['indexes'], $container);
97 18
        $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 18
        $this->loadIndexTemplates($config['index_templates'], $container);
102
103 18
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
104
        $container
105 18
            ->getDefinition('fos_elastica.config_source.template_container')
106 18
            ->replaceArgument(0, $this->indexTemplateConfigs);
107
108 18
        $this->loadIndexManager($container);
109 18
        $this->loadIndexTemplateManager($container);
110
111 18
        $this->createDefaultManagerAlias($config['default_manager'], $container);
112 18
    }
113
114
    /**
115
     * @param array            $config
116
     * @param ContainerBuilder $container
117
     *
118
     * @return Configuration
119
     */
120 18
    public function getConfiguration(array $config, ContainerBuilder $container)
121
    {
122 18
        return new Configuration($container->getParameter('kernel.debug'));
123
    }
124
125
    /**
126
     * Loads the configured clients.
127
     *
128
     * @param array            $clients   An array of clients configurations
129
     * @param ContainerBuilder $container A ContainerBuilder instance
130
     *
131
     * @return array
132
     */
133 18
    private function loadClients(array $clients, ContainerBuilder $container)
134
    {
135 18
        foreach ($clients as $name => $clientConfig) {
136 18
            $clientId = sprintf('fos_elastica.client.%s', $name);
137
138 18
            $clientDef = new ChildDefinition('fos_elastica.client_prototype');
139 18
            $clientDef->replaceArgument(0, $clientConfig);
140
141 18
            $logger = $clientConfig['connections'][0]['logger'];
142 18
            if (false !== $logger) {
143 18
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
144
            }
145
146 18
            $clientDef->addTag('fos_elastica.client');
147
148 18
            $container->setDefinition($clientId, $clientDef);
149
150 18
            $this->clients[$name] = [
151 18
                'id' => $clientId,
152 18
                'reference' => new Reference($clientId),
153
            ];
154
        }
155 18
    }
156
157
    /**
158
     * Loads the configured indexes.
159
     *
160
     * @param array            $indexes   An array of indexes configurations
161
     * @param ContainerBuilder $container A ContainerBuilder instance
162
     *
163
     * @throws \InvalidArgumentException
164
     *
165
     * @return array
166
     */
167 18
    private function loadIndexes(array $indexes, ContainerBuilder $container)
168
    {
169 18
        $indexableCallbacks = [];
170
171 18
        foreach ($indexes as $name => $index) {
172 18
            $indexId = sprintf('fos_elastica.index.%s', $name);
173 18
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
174
175 18
            $indexDef = new ChildDefinition('fos_elastica.index_prototype');
176 18
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
177 18
            $indexDef->replaceArgument(0, $indexName);
178 18
            $indexDef->addTag('fos_elastica.index', [
179 18
                'name' => $name,
180
            ]);
181
182 18
            if (isset($index['client'])) {
183 2
                $client = $this->getClient($index['client']);
184
185 2
                $indexDef->setFactory([$client, 'getIndex']);
186
            }
187
188 18
            $container->setDefinition($indexId, $indexDef);
189 18
            $reference = new Reference($indexId);
190
191 18
            $this->indexConfigs[$name] = [
192 18
                'elasticsearch_name' => $indexName,
193 18
                'reference' => $reference,
194 18
                'name' => $name,
195 18
                'settings' => $index['settings'],
196 18
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
197 18
                'use_alias' => $index['use_alias'],
198
            ];
199
200 18
            if ($index['finder']) {
201
                $this->loadIndexFinder($container, $name, $reference);
202
            }
203
204 18
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
205
        }
206
207 18
        $indexable = $container->getDefinition('fos_elastica.indexable');
208 18
        $indexable->replaceArgument(0, $indexableCallbacks);
209 18
    }
210
211
212
    /**
213
     * Loads the configured indexes.
214
     *
215
     * @param array            $indexTemplates   An array of indexes configurations
216
     * @param ContainerBuilder $container A ContainerBuilder instance
217
     *
218
     * @throws \InvalidArgumentException
219
     *
220
     * @return void
221
     */
222 18
    private function loadIndexTemplates(array $indexTemplates, ContainerBuilder $container)
223
    {
224 18
        $indexableCallbacks = array();
225 18
        foreach ($indexTemplates as $name => $indexTemplate) {
226
            $indexId = sprintf('fos_elastica.index_template.%s', $name);
227
            $indexTemplateName = isset($indexTemplate['template_name']) ? $indexTemplate['template_name'] : $name;
228
229
            $indexDef = new ChildDefinition('fos_elastica.index_template_prototype');
230
            $indexDef->replaceArgument(0, $indexTemplateName);
231
            $indexDef->addTag('fos_elastica.index_template', array(
232
                'name' => $name,
233
            ));
234
235
            if (isset($indexTemplate['client'])) {
236
                $client = $this->getClient($indexTemplate['client']);
237
                // TODO: set factory properly
238
                $indexDef->setFactoryService($client);
0 ignored issues
show
Bug introduced by
The method setFactoryService() does not exist on Symfony\Component\Depend...jection\ChildDefinition. Did you maybe mean setFactory()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

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