Completed
Pull Request — master (#1569)
by
unknown
03:52
created

loadElasticaToModelTransformer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 12
cts 12
cp 1
rs 9.568
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 2
1
<?php
2
3
/*
4
 * This file is part of the FOSElasticaBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\ElasticaBundle\DependencyInjection;
13
14
use Elastica\Client as ElasticaClient;
15
use FOS\ElasticaBundle\Elastica\Client;
16
use FOS\ElasticaBundle\Manager\RepositoryManagerInterface;
17
use Symfony\Component\Config\FileLocator;
18
use Symfony\Component\DependencyInjection\Alias;
19
use Symfony\Component\DependencyInjection\ChildDefinition;
20
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
21
use Symfony\Component\DependencyInjection\ContainerBuilder;
22
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
23
use Symfony\Component\DependencyInjection\Reference;
24
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
25
26
class FOSElasticaExtension extends Extension
27
{
28
    /**
29
     * Definition of elastica clients as configured by this extension.
30
     *
31
     * @var array
32
     */
33
    private $clients = [];
34
35
    /**
36
     * An array of indexes as configured by the extension.
37
     *
38
     * @var array
39
     */
40
    private $indexConfigs = [];
41
42
    /**
43
     * An array of index templates as configured by the extension.
44
     *
45
     * @var array
46
     */
47
    private $indexTemplateConfigs = array();
48
49
    /**
50
     * 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 25
    public function load(array $configs, ContainerBuilder $container)
58
    {
59 25
        $configuration = $this->getConfiguration($configs, $container);
60 25
        $config = $this->processConfiguration($configuration, $configs);
61
62 25
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
63
64 25
        if (empty($config['clients']) || empty($config['indexes'])) {
65
            // No Clients or indexes are defined
66
            return;
67
        }
68
69 25
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener', 'commands'] as $basename) {
70 25
            $loader->load(sprintf('%s.xml', $basename));
71
        }
72
73 25
        if (empty($config['default_client'])) {
74 25
            $keys = array_keys($config['clients']);
75 25
            $config['default_client'] = reset($keys);
76
        }
77
78 25
        if (empty($config['default_index'])) {
79 25
            $keys = array_keys($config['indexes']);
80 25
            $config['default_index'] = reset($keys);
81
        }
82
83 25
        if (isset($config['serializer'])) {
84 3
            $loader->load('serializer.xml');
85
86 3
            $this->loadSerializer($config['serializer'], $container);
87
        }
88
89 25
        $this->loadClients($config['clients'], $container);
90 25
        $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
91 25
        $container->getAlias('fos_elastica.client')->setPublic(true);
92 25
        $container->setAlias(ElasticaClient::class, new Alias('fos_elastica.client', false));
93 25
        $container->setAlias(Client::class, 'fos_elastica.client');
94 25
        $container->getAlias(Client::class)->setPublic(false);
95
96 25
        $this->loadIndexes($config['indexes'], $container);
97 10
        $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
98 10
        $container->getAlias('fos_elastica.index')->setPublic(true);
99 10
        $container->setParameter('fos_elastica.default_index', $config['default_index']);
100
101 10
        if ($usedIndexNames = \array_intersect_key($config['indexes'], $config['index_templates'])) {
102
            throw new \DomainException(
103
                \sprintf(
104
                    'Index names "%s" are already in use and can not be used for index templates names',
105
                    \implode('","', \array_keys($usedIndexNames))
106
                )
107
            );
108
        }
109 10
        $this->loadIndexTemplates($config['index_templates'], $container);
110
111 10
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
112
        $container
113 10
            ->getDefinition('fos_elastica.config_source.template_container')
114 10
            ->replaceArgument(0, $this->indexTemplateConfigs);
115
116 10
        $this->loadIndexManager($container);
117 10
        $this->loadIndexTemplateManager($container);
118
119 10
        $this->createDefaultManagerAlias($config['default_manager'], $container);
120 10
    }
121
122
    /**
123
     * @param array            $config
124
     * @param ContainerBuilder $container
125
     *
126
     * @return Configuration
127
     */
128 25
    public function getConfiguration(array $config, ContainerBuilder $container)
129
    {
130 25
        return new Configuration($container->getParameter('kernel.debug'));
131
    }
132
133
    /**
134
     * Loads the configured clients.
135
     *
136
     * @param array            $clients   An array of clients configurations
137
     * @param ContainerBuilder $container A ContainerBuilder instance
138
     *
139
     * @return array
140
     */
141 25
    private function loadClients(array $clients, ContainerBuilder $container)
142
    {
143 25
        foreach ($clients as $name => $clientConfig) {
144 25
            $clientId = sprintf('fos_elastica.client.%s', $name);
145
146 25
            $clientDef = new ChildDefinition('fos_elastica.client_prototype');
147 25
            $clientDef->replaceArgument(0, $clientConfig);
148 25
            $clientDef->replaceArgument(1, null);
149
150 25
            $logger = $clientConfig['connections'][0]['logger'];
151 25
            if (false !== $logger) {
152 25
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
153
            }
154
155 25
            $clientDef->addTag('fos_elastica.client');
156
157 25
            $container->setDefinition($clientId, $clientDef);
158
159 25
            $this->clients[$name] = [
160 25
                'id' => $clientId,
161 25
                'reference' => new Reference($clientId),
162
            ];
163
        }
164 25
    }
165
166
    /**
167
     * Loads the configured indexes.
168
     *
169
     * @param array            $indexes   An array of indexes configurations
170
     * @param ContainerBuilder $container A ContainerBuilder instance
171
     *
172
     * @throws \InvalidArgumentException
173
     *
174
     * @return array
175
     */
176 25
    private function loadIndexes(array $indexes, ContainerBuilder $container)
177
    {
178 25
        $indexableCallbacks = [];
179
180 25
        foreach ($indexes as $name => $index) {
181 25
            $indexId = sprintf('fos_elastica.index.%s', $name);
182 25
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
183
184 25
            $indexDef = new ChildDefinition('fos_elastica.index_prototype');
185 25
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
186 25
            $indexDef->replaceArgument(0, $indexName);
187 25
            $indexDef->addTag('fos_elastica.index', [
188 25
                'name' => $name,
189
            ]);
190
191 25 View Code Duplication
            if (isset($index['client'])) {
192 2
                $client = $this->getClient($index['client']);
193
194 2
                $indexDef->setFactory([$client, 'getIndex']);
195
            }
196
197 25
            $container->setDefinition($indexId, $indexDef);
198 25
            $reference = new Reference($indexId);
199
200 25
            $this->indexConfigs[$name] = [
201 25
                'elasticsearch_name' => $indexName,
202 25
                'reference' => $reference,
203 25
                'name' => $name,
204 25
                'settings' => $index['settings'],
205 25
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
206 25
                'use_alias' => $index['use_alias'],
207
            ];
208
209 25
            if ($index['finder']) {
210
                $this->loadIndexFinder($container, $name, $reference);
211
            }
212
213 25
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
214
        }
215
216 10
        $indexable = $container->getDefinition('fos_elastica.indexable');
217 10
        $indexable->replaceArgument(0, $indexableCallbacks);
218 10
    }
219
220
    /**
221
     * Loads the configured indexes.
222
     *
223
     * @param array            $indexTemplates   An array of indexes configurations
224
     * @param ContainerBuilder $container A ContainerBuilder instance
225
     *
226
     * @throws \InvalidArgumentException
227
     *
228
     * @return void
229
     */
230 10
    private function loadIndexTemplates(array $indexTemplates, ContainerBuilder $container)
231
    {
232 10
        $indexableCallbacks = array();
233 10
        foreach ($indexTemplates as $name => $indexTemplate) {
234 6
            $indexId = sprintf('fos_elastica.index_template.%s', $name);
235 6
            $indexTemplateName = isset($indexTemplate['template_name']) ? $indexTemplate['template_name'] : $name;
236
237 6
            $indexDef = new ChildDefinition('fos_elastica.index_template_prototype');
238 6
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndexTemplate']);
239 6
            $indexDef->replaceArgument(0, $indexTemplateName);
240 6
            $indexDef->addTag('fos_elastica.index_template', array(
241 6
                'name' => $name,
242
            ));
243
244 6 View Code Duplication
            if (isset($indexTemplate['client'])) {
245 6
                $client = $this->getClient($indexTemplate['client']);
246 6
                $indexDef->setFactory([$client, 'getIndexTemplate']);
247
            }
248
249 6
            $container->setDefinition($indexId, $indexDef);
250 6
            $reference = new Reference($indexId);
251
252 6
            $this->indexTemplateConfigs[$name] = array(
253 6
                'elasticsearch_name' => $indexTemplateName,
254 6
                'reference' => $reference,
255 6
                'name' => $name,
256 6
                'settings' => $indexTemplate['settings'],
257 6
                'template' => $indexTemplate['template'],
258
            );
259
260 6
            $this->loadTypes(
261 6
                (array) $indexTemplate['types'],
262
                $container,
263 6
                $this->indexTemplateConfigs[$name],
264
                $indexableCallbacks
265
            );
266
        }
267
268 10
        if ($indexableCallbacks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $indexableCallbacks of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

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