Issues (44)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/DependencyInjection/FOSElasticaExtension.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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