Completed
Push — master ( 212f0a...214901 )
by Lukas Kahwe
23s queued 10s
created

src/DependencyInjection/FOSElasticaExtension.php (2 issues)

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 <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 21
    public function load(array $configs, ContainerBuilder $container)
58
    {
59 21
        $configuration = $this->getConfiguration($configs, $container);
60 21
        $config = $this->processConfiguration($configuration, $configs);
61
62 21
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
63
64 21
        if (empty($config['clients']) || empty($config['indexes'])) {
65
            // No Clients or indexes are defined
66
            return;
67
        }
68
69 21
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener', 'commands'] as $basename) {
70 21
            $loader->load(sprintf('%s.xml', $basename));
71
        }
72
73 21
        if (empty($config['default_client'])) {
74 21
            $keys = array_keys($config['clients']);
75 21
            $config['default_client'] = reset($keys);
76
        }
77
78 21
        if (empty($config['default_index'])) {
79 21
            $keys = array_keys($config['indexes']);
80 21
            $config['default_index'] = reset($keys);
81
        }
82
83 21
        if (isset($config['serializer'])) {
84 1
            $loader->load('serializer.xml');
85
86 1
            $this->loadSerializer($config['serializer'], $container);
87
        }
88
89 21
        $this->loadClients($config['clients'], $container);
90 21
        $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
91 21
        $container->getAlias('fos_elastica.client')->setPublic(true);
92 21
        $container->setAlias(ElasticaClient::class, new Alias('fos_elastica.client', false));
93 21
        $container->setAlias(Client::class, 'fos_elastica.client');
94 21
        $container->getAlias(Client::class)->setPublic(false);
95
96 21
        $this->loadIndexes($config['indexes'], $container);
97 21
        $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
98 21
        $container->getAlias('fos_elastica.index')->setPublic(true);
99 21
        $container->setParameter('fos_elastica.default_index', $config['default_index']);
100
101 21
        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 21
        $this->loadIndexTemplates($config['index_templates'], $container);
110
111 21
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
112
        $container
113 21
            ->getDefinition('fos_elastica.config_source.template_container')
114 21
            ->replaceArgument(0, $this->indexTemplateConfigs);
115
116 21
        $this->loadIndexManager($container);
117 21
        $this->loadIndexTemplateManager($container);
118
119 21
        $this->createDefaultManagerAlias($config['default_manager'], $container);
120 21
    }
121
122
    /**
123
     * @param array            $config
124
     * @param ContainerBuilder $container
125
     *
126
     * @return Configuration
127
     */
128 21
    public function getConfiguration(array $config, ContainerBuilder $container)
129
    {
130 21
        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 21
    private function loadClients(array $clients, ContainerBuilder $container)
142
    {
143 21
        foreach ($clients as $name => $clientConfig) {
144 21
            $clientId = sprintf('fos_elastica.client.%s', $name);
145
146 21
            $clientDef = new ChildDefinition('fos_elastica.client_prototype');
147 21
            $clientDef->replaceArgument(0, $clientConfig);
148 21
            $clientDef->replaceArgument(1, null);
149
150 21
            $logger = $clientConfig['connections'][0]['logger'];
151 21
            if (false !== $logger) {
152 21
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
153
            }
154
155 21
            $clientDef->addTag('fos_elastica.client');
156
157 21
            $container->setDefinition($clientId, $clientDef);
158
159 21
            $this->clients[$name] = [
160 21
                'id' => $clientId,
161 21
                'reference' => new Reference($clientId),
162
            ];
163
        }
164 21
    }
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 21
    private function loadIndexes(array $indexes, ContainerBuilder $container)
177
    {
178 21
        $indexableCallbacks = [];
179
180 21
        foreach ($indexes as $name => $index) {
181 21
            $indexId = sprintf('fos_elastica.index.%s', $name);
182 21
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
183
184 21
            $indexDef = new ChildDefinition('fos_elastica.index_prototype');
185 21
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
186 21
            $indexDef->replaceArgument(0, $indexName);
187 21
            $indexDef->addTag('fos_elastica.index', [
188 21
                'name' => $name,
189
            ]);
190
191 21 View Code Duplication
            if (isset($index['client'])) {
192 2
                $client = $this->getClient($index['client']);
193
194 2
                $indexDef->setFactory([$client, 'getIndex']);
195
            }
196
197 21
            $container->setDefinition($indexId, $indexDef);
198 21
            $reference = new Reference($indexId);
199
200 21
            $this->indexConfigs[$name] = [
201 21
                'elasticsearch_name' => $indexName,
202 21
                'reference' => $reference,
203 21
                'name' => $name,
204 21
                'settings' => $index['settings'],
205 21
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
206 21
                'use_alias' => $index['use_alias'],
207
            ];
208
209 21
            if ($index['finder']) {
210
                $this->loadIndexFinder($container, $name, $reference);
211
            }
212
213 21
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
214
        }
215
216 21
        $indexable = $container->getDefinition('fos_elastica.indexable');
217 21
        $indexable->replaceArgument(0, $indexableCallbacks);
218 21
    }
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 21
    private function loadIndexTemplates(array $indexTemplates, ContainerBuilder $container)
231
    {
232 21
        $indexableCallbacks = array();
233 21
        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 21
        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 21
    }
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, $name, Reference $index)
283
    {
284
        /* Note: transformer services may conflict with "collection.index", if
285
         * an index and type names were "collection" and an index, respectively.
286
         */
287
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
288
        $transformerDef = new ChildDefinition('fos_elastica.elastica_to_model_transformer.collection');
289
        $container->setDefinition($transformerId, $transformerDef);
290
291
        $finderId = sprintf('fos_elastica.finder.%s', $name);
292
        $finderDef = new ChildDefinition('fos_elastica.finder');
293
        $finderDef->replaceArgument(0, $index);
294
        $finderDef->replaceArgument(1, new Reference($transformerId));
295
296
        $container->setDefinition($finderId, $finderDef);
297
    }
298
299
    /**
300
     * Loads the configured types.
301
     *
302
     * @param array            $types
303
     * @param ContainerBuilder $container
304
     * @param array            $indexConfig
305
     * @param array            $indexableCallbacks
306
     */
307 21
    private function loadTypes(array $types, ContainerBuilder $container, array &$indexConfig, array &$indexableCallbacks)
308
    {
309 21
        foreach ($types as $name => $type) {
310 21
            $indexName = $indexConfig['name'];
311
312 21
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
313 21
            $typeDef = new ChildDefinition('fos_elastica.type_prototype');
314 21
            $typeDef->setFactory([$indexConfig['reference'], 'getType']);
315 21
            $typeDef->replaceArgument(0, $name);
316
317 21
            $container->setDefinition($typeId, $typeDef);
318
319
            $typeConfig = [
320 21
                'name' => $name,
321
                'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch
322
                'config' => [],
323
            ];
324
325
            foreach ([
326 21
                'dynamic_templates',
327
                'properties',
328
                '_all',
329
                '_id',
330
                '_parent',
331
                '_routing',
332
                '_source',
333
            ] as $field) {
334 21
                if (isset($type[$field])) {
335 21
                    $typeConfig['mapping'][$field] = $type[$field];
336
                }
337
            }
338
339
            foreach ([
340 21
                'persistence',
341
                'serializer',
342
                'analyzer',
343
                'search_analyzer',
344
                'dynamic',
345
                'date_detection',
346
                'dynamic_date_formats',
347
                'numeric_detection',
348
            ] as $field) {
349 21
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
350 21
                    $type[$field] :
351 21
                    null;
352
            }
353
354 21
            $indexConfig['types'][$name] = $typeConfig;
355
356 21
            if (isset($type['persistence'])) {
357 15
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
358
359 15
                $typeConfig['persistence'] = $type['persistence'];
360
            }
361
362 21
            if (isset($type['_parent'])) {
363
                // _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence`
364 6
                unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']);
365
            }
366
367 21
            if (isset($type['indexable_callback'])) {
368 4
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $this->buildCallback($type['indexable_callback'], $name);
369
            }
370
371 21
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
372 1
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
373 1
                $typeSerializerDef = new ChildDefinition('fos_elastica.serializer_callback_prototype');
374
375 1
                if (isset($type['serializer']['groups'])) {
376 1
                    $typeSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]);
377
                }
378
379 1
                if (isset($type['serializer']['serialize_null'])) {
380 1
                    $typeSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]);
381
                }
382
383 1
                if (isset($type['serializer']['version'])) {
384 1
                    $typeSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]);
385
                }
386
387 1
                $typeDef->addMethodCall('setSerializer', [[new Reference($typeSerializerId), 'serialize']]);
388 1
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
389
            }
390
        }
391 21
    }
392
393 4
    private function buildCallback($indexCallback, $typeName)
394
    {
395 4
        if (is_array($indexCallback)) {
396 4
            if (!isset($indexCallback[0])) {
397
                throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName));
398
            }
399
400 4
            $classOrServiceRef = $this->transformServiceReference($indexCallback[0]);
401 4
            if ($classOrServiceRef instanceof Reference && !isset($indexCallback[1])) {
402
                return $classOrServiceRef; // __invoke
403
            }
404
405 4
            if (!isset($indexCallback[1])) {
406
                throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName));
407
            }
408
409 4
            return [$classOrServiceRef, $indexCallback[1]];
410
        }
411
412 4
        if (is_string($indexCallback)) {
413 4
            return $this->transformServiceReference($indexCallback);
414
        }
415
416
        throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName));
417
    }
418
419 4
    private function transformServiceReference($classOrService)
420
    {
421 4
        return 0 === strpos($classOrService, '@') ? new Reference(substr($classOrService, 1)) : $classOrService;
422
    }
423
424
    /**
425
     * Loads the optional provider and finder for a type.
426
     *
427
     * @param array            $typeConfig
428
     * @param ContainerBuilder $container
429
     * @param Reference        $typeRef
430
     * @param string           $indexName
431
     * @param string           $typeName
432
     */
433 15
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
434
    {
435 15
        if (isset($typeConfig['driver'])) {
436 15
            $this->loadDriver($container, $typeConfig['driver']);
437
        }
438
439 15
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
440 15
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
441 15
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
442
443 15
        if (isset($typeConfig['provider'])) {
444 15
            $this->loadTypePagerProvider($typeConfig, $container, $indexName, $typeName);
445
        }
446 15
        if (isset($typeConfig['finder'])) {
447 15
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
448
        }
449 15
        if (isset($typeConfig['listener']) && $typeConfig['listener']['enabled']) {
450 14
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
451
        }
452 15
    }
453
454
    /**
455
     * Creates and loads an ElasticaToModelTransformer.
456
     *
457
     * @param array            $typeConfig
458
     * @param ContainerBuilder $container
459
     * @param string           $indexName
460
     * @param string           $typeName
461
     *
462
     * @return string
463
     */
464 15
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
465
    {
466 15
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
467 1
            return $typeConfig['elastica_to_model_transformer']['service'];
468
        }
469
470
        /* Note: transformer services may conflict with "prototype.driver", if
471
         * the index and type names were "prototype" and a driver, respectively.
472
         */
473 14
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
474 14
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
475 14
        $serviceDef = new ChildDefinition($abstractId);
476 14
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['type' => $typeName, 'index' => $indexName]);
477
478 14
        $serviceDef->replaceArgument(1, $typeConfig['model']);
479 14
        $serviceDef->replaceArgument(2, array_merge($typeConfig['elastica_to_model_transformer'], [
480 14
            'identifier' => $typeConfig['identifier'],
481
        ]));
482 14
        $container->setDefinition($serviceId, $serviceDef);
483
484 14
        return $serviceId;
485
    }
486
487
    /**
488
     * Creates and loads a ModelToElasticaTransformer for an index/type.
489
     *
490
     * @param array            $typeConfig
491
     * @param ContainerBuilder $container
492
     * @param string           $indexName
493
     * @param string           $typeName
494
     *
495
     * @return string
496
     */
497 15
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
498
    {
499 15
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
500
            return $typeConfig['model_to_elastica_transformer']['service'];
501
        }
502
503 15
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
504 1
            'fos_elastica.model_to_elastica_identifier_transformer' :
505 15
            'fos_elastica.model_to_elastica_transformer';
506
507 15
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
508 15
        $serviceDef = new ChildDefinition($abstractId);
509 15
        $serviceDef->replaceArgument(0, [
510 15
            'identifier' => $typeConfig['identifier'],
511 15
            'index' => $indexName,
512
        ]);
513 15
        $container->setDefinition($serviceId, $serviceDef);
514
515 15
        return $serviceId;
516
    }
517
518
    /**
519
     * Creates and loads an object persister for a type.
520
     *
521
     * @param array            $typeConfig
522
     * @param Reference        $typeRef
523
     * @param ContainerBuilder $container
524
     * @param string           $indexName
525
     * @param string           $typeName
526
     * @param string           $transformerId
527
     *
528
     * @return string
529
     */
530 15
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
531
    {
532 15
        if (isset($typeConfig['persister']['service'])) {
533 1
            return $typeConfig['persister']['service'];
534
        }
535
536
        $arguments = [
537 14
            $typeRef,
538 14
            new Reference($transformerId),
539 14
            $typeConfig['model'],
540
        ];
541
542 14
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
543 1
            $abstractId = 'fos_elastica.object_serializer_persister';
544 1
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
545 1
            $arguments[] = [new Reference($callbackId), 'serialize'];
546
        } else {
547 13
            $abstractId = 'fos_elastica.object_persister';
548 13
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
549 13
            $argument = $mapping['properties'];
550 13
            if (isset($mapping['_parent'])) {
551 1
                $argument['_parent'] = $mapping['_parent'];
552
            }
553 13
            $arguments[] = $argument;
554
        }
555
556 14
        $arguments[] = array_intersect_key($typeConfig['persister'], array_flip(['refresh']));
557
558 14
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
559 14
        $serviceDef = new ChildDefinition($abstractId);
560 14
        foreach ($arguments as $i => $argument) {
561 14
            $serviceDef->replaceArgument($i, $argument);
562
        }
563
564 14
        $serviceDef->addTag('fos_elastica.persister', ['index' => $indexName, 'type' => $typeName]);
565
566 14
        $container->setDefinition($serviceId, $serviceDef);
567
568 14
        return $serviceId;
569
    }
570
571
    /**
572
     * Loads a pager provider for a type.
573
     *
574
     * @param array            $typeConfig
575
     * @param ContainerBuilder $container
576
     * @param string           $indexName
577
     * @param string           $typeName
578
     *
579
     * @return string
580
     */
581 15
    private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
582
    {
583 15
        if (isset($typeConfig['provider']['service'])) {
584
            return $typeConfig['provider']['service'];
585
        }
586
587 15
        $baseConfig = $typeConfig['provider'];
588 15
        unset($baseConfig['service']);
589
590 15
        $driver = $typeConfig['driver'];
591
592 15
        switch ($driver) {
593 15
            case 'orm':
594 14
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
595 14
                $providerDef->replaceArgument(2, $typeConfig['model']);
596 14
                $providerDef->replaceArgument(3, $baseConfig);
597
598 14
                break;
599 1 View Code Duplication
            case 'mongodb':
600
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
601
                $providerDef->replaceArgument(2, $typeConfig['model']);
602
                $providerDef->replaceArgument(3, $baseConfig);
603
604
                break;
605 1 View Code Duplication
            case 'phpcr':
606 1
                $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver);
607 1
                $providerDef->replaceArgument(2, $typeConfig['model']);
608 1
                $providerDef->replaceArgument(3, $baseConfig);
609
610 1
                break;
611
            default:
612
                throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver));
613
        }
614
615
        /* Note: provider services may conflict with "prototype.driver", if the
616
         * index and type names were "prototype" and a driver, respectively.
617
         */
618 15
        $providerId = sprintf('fos_elastica.pager_provider.%s.%s', $indexName, $typeName);
619 15
        $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName, 'type' => $typeName]);
620
621 15
        $container->setDefinition($providerId, $providerDef);
622
623 15
        return $providerId;
624
    }
625
626
    /**
627
     * Loads doctrine listeners to handle indexing of new or updated objects.
628
     *
629
     * @param array            $typeConfig
630
     * @param ContainerBuilder $container
631
     * @param string           $objectPersisterId
632
     * @param string           $indexName
633
     * @param string           $typeName
634
     *
635
     * @return string
636
     */
637 14
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
638
    {
639 14
        if (isset($typeConfig['listener']['service'])) {
640
            return $typeConfig['listener']['service'];
641
        }
642
643
        /* Note: listener services may conflict with "prototype.driver", if the
644
         * index and type names were "prototype" and a driver, respectively.
645
         */
646 14
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
647 14
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
648 14
        $listenerDef = new ChildDefinition($abstractListenerId);
649 14
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
650 14
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
651
            new Reference($typeConfig['listener']['logger']) :
652 14
            null
653
        );
654
        $listenerConfig = [
655 14
            'identifier' => $typeConfig['identifier'],
656 14
            'indexName' => $indexName,
657 14
            'typeName' => $typeName,
658
        ];
659
660 14
        $tagName = null;
661 14
        switch ($typeConfig['driver']) {
662 14
            case 'orm':
663 13
                $tagName = 'doctrine.event_listener';
664 13
                break;
665 1
            case 'phpcr':
666 1
                $tagName = 'doctrine_phpcr.event_listener';
667 1
                break;
668
            case 'mongodb':
669
                $tagName = 'doctrine_mongodb.odm.event_listener';
670
                break;
671
        }
672
673 14
        if ($typeConfig['listener']['defer']) {
674
            $listenerDef->setPublic(true);
675
            $listenerDef->addTag(
676
                'kernel.event_listener',
677
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
678
            );
679
            $listenerDef->addTag(
680
                'kernel.event_listener',
681
                ['event' => 'console.terminate', 'method' => 'onTerminate']
682
            );
683
            $listenerConfig['defer'] = true;
684
        }
685
686 14
        $listenerDef->replaceArgument(2, $listenerConfig);
687
688 14
        if (null !== $tagName) {
689 14
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
690 14
                $listenerDef->addTag($tagName, ['event' => $event]);
691
            }
692
        }
693
694 14
        $container->setDefinition($listenerId, $listenerDef);
695
696 14
        return $listenerId;
697
    }
698
699
    /**
700
     * Map Elastica to Doctrine events for the current driver.
701
     */
702 14
    private function getDoctrineEvents(array $typeConfig)
703
    {
704 14
        switch ($typeConfig['driver']) {
705 14
            case 'orm':
706 13
                $eventsClass = '\Doctrine\ORM\Events';
707 13
                break;
708 1
            case 'phpcr':
709 1
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
710 1
                break;
711
            case 'mongodb':
712
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
713
                break;
714
            default:
715
                throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
716
        }
717
718 14
        $events = [];
719
        $eventMapping = [
720 14
            'insert' => [constant($eventsClass.'::postPersist')],
721 14
            'update' => [constant($eventsClass.'::postUpdate')],
722 14
            'delete' => [constant($eventsClass.'::preRemove')],
723 14
            'flush' => [constant($eventsClass.'::postFlush')],
724
        ];
725
726 14
        foreach ($eventMapping as $event => $doctrineEvents) {
727 14
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
728 14
                $events = array_merge($events, $doctrineEvents);
729
            }
730
        }
731
732 14
        return $events;
733
    }
734
735
    /**
736
     * Loads a Type specific Finder.
737
     *
738
     * @param array            $typeConfig
739
     * @param ContainerBuilder $container
740
     * @param string           $elasticaToModelId
741
     * @param Reference        $typeRef
742
     * @param string           $indexName
743
     * @param string           $typeName
744
     *
745
     * @return string
746
     */
747 15
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
748
    {
749 15
        if (isset($typeConfig['finder']['service'])) {
750
            $finderId = $typeConfig['finder']['service'];
751
        } else {
752 15
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
753 15
            $finderDef = new ChildDefinition('fos_elastica.finder');
754 15
            $finderDef->replaceArgument(0, $typeRef);
755 15
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
756 15
            $container->setDefinition($finderId, $finderDef);
757
        }
758
759 15
        $indexTypeName = "$indexName/$typeName";
760 15
        $arguments = [$indexTypeName, new Reference($finderId)];
761 15
        if (isset($typeConfig['repository'])) {
762 4
            $arguments[] = $typeConfig['repository'];
763
        }
764
765 15
        $container->getDefinition('fos_elastica.repository_manager')
766 15
            ->addMethodCall('addType', $arguments);
767
768 15
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
769 15
        $container->getDefinition($managerId)
770 15
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]);
771
772 15
        return $finderId;
773
    }
774
775
    /**
776
     * Loads the index manager.
777
     *
778
     * @param ContainerBuilder $container
779
     **/
780 View Code Duplication
    private function loadIndexManager(ContainerBuilder $container)
781
    {
782 21
        $indexRefs = array_map(function ($index) {
783 21
            return $index['reference'];
784 21
        }, $this->indexConfigs);
785
786 21
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
787 21
        $managerDef->replaceArgument(0, $indexRefs);
788 21
    }
789
790
    /**
791
     * Load index template manager
792
     *
793
     * @param ContainerBuilder $container
794
     *
795
     * @return void
796
     */
797 View Code Duplication
    private function loadIndexTemplateManager(ContainerBuilder $container)
798
    {
799 21
        $indexTemplateRefs = array_map(function ($index) {
800 6
            return $index['reference'];
801 21
        }, $this->indexTemplateConfigs);
802
803 21
        $managerDef = $container->getDefinition('fos_elastica.index_template_manager');
804 21
        $managerDef->replaceArgument(0, $indexTemplateRefs);
805 21
    }
806
807
    /**
808
     * Makes sure a specific driver has been loaded.
809
     *
810
     * @param ContainerBuilder $container
811
     * @param string           $driver
812
     */
813 15
    private function loadDriver(ContainerBuilder $container, $driver)
814
    {
815 15
        if (in_array($driver, $this->loadedDrivers)) {
816 6
            return;
817
        }
818
819 15
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
820 15
        $loader->load($driver.'.xml');
821 15
        $this->loadedDrivers[] = $driver;
822 15
    }
823
824
    /**
825
     * Loads and configures the serializer prototype.
826
     *
827
     * @param array            $config
828
     * @param ContainerBuilder $container
829
     */
830 1
    private function loadSerializer($config, ContainerBuilder $container)
831
    {
832 1
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
833
834 1
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
835 1
        $serializer->setClass($config['callback_class']);
836
837 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...
838
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
839
        }
840 1
    }
841
842
    /**
843
     * Creates a default manager alias for defined default manager or the first loaded driver.
844
     *
845
     * @param string           $defaultManager
846
     * @param ContainerBuilder $container
847
     */
848 21
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
849
    {
850 21
        if (0 == count($this->loadedDrivers)) {
851 6
            return;
852
        }
853
854 15
        if (count($this->loadedDrivers) > 1
855 15
            && in_array($defaultManager, $this->loadedDrivers)
856
        ) {
857
            $defaultManagerService = $defaultManager;
858
        } else {
859 15
            $defaultManagerService = $this->loadedDrivers[0];
860
        }
861
862 15
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
863 15
        $container->getAlias('fos_elastica.manager')->setPublic(true);
864 15
        $container->setAlias(RepositoryManagerInterface::class, 'fos_elastica.manager');
865 15
        $container->getAlias(RepositoryManagerInterface::class)->setPublic(false);
866 15
    }
867
868
    /**
869
     * Returns a reference to a client given its configured name.
870
     *
871
     * @param string $clientName
872
     *
873
     * @return Reference
874
     *
875
     * @throws \InvalidArgumentException
876
     */
877 8
    private function getClient($clientName)
878
    {
879 8
        if (!array_key_exists($clientName, $this->clients)) {
880
            throw new \InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
881
        }
882
883 8
        return $this->clients[$clientName]['reference'];
884
    }
885
}
886