Completed
Pull Request — master (#1325)
by Maksim
02:21
created

loadTypePersistenceIntegration()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 6.0131

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 13
cts 14
cp 0.9286
rs 8.5125
c 0
b 0
f 0
cc 6
eloc 14
nc 18
nop 5
crap 6.0131
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 Symfony\Component\Config\FileLocator;
15
use Pagerfanta\Pagerfanta;
16
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\DefinitionDecorator;
19
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
22
23
class FOSElasticaExtension extends Extension
24
{
25
    /**
26
     * Definition of elastica clients as configured by this extension.
27
     *
28
     * @var array
29
     */
30
    private $clients = [];
31
32
    /**
33
     * An array of indexes as configured by the extension.
34
     *
35
     * @var array
36
     */
37
    private $indexConfigs = [];
38
39
    /**
40
     * If we've encountered a type mapped to a specific persistence driver, it will be loaded
41
     * here.
42
     *
43
     * @var array
44
     */
45
    private $loadedDrivers = [];
46
47 12
    public function load(array $configs, ContainerBuilder $container)
48
    {
49 12
        $configuration = $this->getConfiguration($configs, $container);
50 12
        $config = $this->processConfiguration($configuration, $configs);
51
52 12
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
53
54 12
        if (empty($config['clients']) || empty($config['indexes'])) {
55
            // No Clients or indexes are defined
56
            return;
57
        }
58
59 12
        foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener'] as $basename) {
60 12
            $loader->load(sprintf('%s.xml', $basename));
61
        }
62
63 12
        if (empty($config['default_client'])) {
64 12
            $keys = array_keys($config['clients']);
65 12
            $config['default_client'] = reset($keys);
66
        }
67
68 12
        if (empty($config['default_index'])) {
69 12
            $keys = array_keys($config['indexes']);
70 12
            $config['default_index'] = reset($keys);
71
        }
72
73 12
        if (isset($config['serializer'])) {
74 1
            $loader->load('serializer.xml');
75
76 1
            $this->loadSerializer($config['serializer'], $container);
77
        }
78
79 12
        $this->loadClients($config['clients'], $container);
80 12
        $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
81
82 12
        $this->loadIndexes($config['indexes'], $container);
83 12
        $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
84 12
        $container->setParameter('fos_elastica.default_index', $config['default_index']);
85
86 12
        $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
87
88 12
        $this->loadIndexManager($container);
89
90 12
        $this->createDefaultManagerAlias($config['default_manager'], $container);
91 12
    }
92
93
    /**
94
     * @param array            $config
95
     * @param ContainerBuilder $container
96
     *
97
     * @return Configuration
98
     */
99 12
    public function getConfiguration(array $config, ContainerBuilder $container)
100
    {
101 12
        return new Configuration($container->getParameter('kernel.debug'));
102
    }
103
104
    /**
105
     * Loads the configured clients.
106
     *
107
     * @param array            $clients   An array of clients configurations
108
     * @param ContainerBuilder $container A ContainerBuilder instance
109
     *
110
     * @return array
111
     */
112 12
    private function loadClients(array $clients, ContainerBuilder $container)
113
    {
114 12
        foreach ($clients as $name => $clientConfig) {
115 12
            $clientId = sprintf('fos_elastica.client.%s', $name);
116
117 12
            $clientDef = new DefinitionDecorator('fos_elastica.client_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
118 12
            $clientDef->replaceArgument(0, $clientConfig);
119
120 12
            $logger = $clientConfig['connections'][0]['logger'];
121 12
            if (false !== $logger) {
122 12
                $clientDef->addMethodCall('setLogger', [new Reference($logger)]);
123
            }
124
125 12
            $clientDef->addTag('fos_elastica.client');
126
127 12
            $container->setDefinition($clientId, $clientDef);
128
129 12
            $this->clients[$name] = [
130 12
                'id' => $clientId,
131 12
                'reference' => new Reference($clientId),
132
            ];
133
        }
134 12
    }
135
136
    /**
137
     * Loads the configured indexes.
138
     *
139
     * @param array            $indexes   An array of indexes configurations
140
     * @param ContainerBuilder $container A ContainerBuilder instance
141
     *
142
     * @throws \InvalidArgumentException
143
     *
144
     * @return array
145
     */
146 12
    private function loadIndexes(array $indexes, ContainerBuilder $container)
147
    {
148 12
        $indexableCallbacks = [];
149
150 12
        foreach ($indexes as $name => $index) {
151 12
            $indexId = sprintf('fos_elastica.index.%s', $name);
152 12
            $indexName = isset($index['index_name']) ? $index['index_name'] : $name;
153
154 12
            $indexDef = new DefinitionDecorator('fos_elastica.index_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
155 12
            $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']);
156 12
            $indexDef->replaceArgument(0, $indexName);
157 12
            $indexDef->addTag('fos_elastica.index', [
158 12
                'name' => $name,
159
            ]);
160
161 12
            if (isset($index['client'])) {
162 2
                $client = $this->getClient($index['client']);
163
164 2
                $indexDef->setFactory([$client, 'getIndex']);
165
            }
166
167 12
            $container->setDefinition($indexId, $indexDef);
168 12
            $reference = new Reference($indexId);
169
170 12
            $this->indexConfigs[$name] = [
171 12
                'elasticsearch_name' => $indexName,
172 12
                'reference' => $reference,
173 12
                'name' => $name,
174 12
                'settings' => $index['settings'],
175 12
                'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [],
176 12
                'use_alias' => $index['use_alias'],
177
            ];
178
179 12
            if ($index['finder']) {
180
                $this->loadIndexFinder($container, $name, $reference);
181
            }
182
183 12
            $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
184
        }
185
186 12
        $indexable = $container->getDefinition('fos_elastica.indexable');
187 12
        $indexable->replaceArgument(0, $indexableCallbacks);
188 12
    }
189
190
    /**
191
     * Loads the configured index finders.
192
     *
193
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
194
     * @param string                                                  $name      The index name
195
     * @param Reference                                               $index     Reference to the related index
196
     *
197
     * @return string
198
     */
199
    private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
200
    {
201
        /* Note: transformer services may conflict with "collection.index", if
202
         * an index and type names were "collection" and an index, respectively.
203
         */
204
        $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name);
205
        $transformerDef = new DefinitionDecorator('fos_elastica.elastica_to_model_transformer.collection');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
206
        $container->setDefinition($transformerId, $transformerDef);
207
208
        $finderId = sprintf('fos_elastica.finder.%s', $name);
209
        $finderDef = new DefinitionDecorator('fos_elastica.finder');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
210
        $finderDef->replaceArgument(0, $index);
211
        $finderDef->replaceArgument(1, new Reference($transformerId));
212
213
        $container->setDefinition($finderId, $finderDef);
214
    }
215
216
    /**
217
     * Loads the configured types.
218
     *
219
     * @param array            $types
220
     * @param ContainerBuilder $container
221
     * @param array            $indexConfig
222
     * @param array            $indexableCallbacks
223
     */
224 12
    private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
225
    {
226 12
        foreach ($types as $name => $type) {
227 12
            $indexName = $indexConfig['name'];
228
229 12
            $typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
230 12
            $typeDef = new DefinitionDecorator('fos_elastica.type_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
231 12
            $typeDef->setFactory([$indexConfig['reference'], 'getType']);
232 12
            $typeDef->replaceArgument(0, $name);
233
234 12
            $container->setDefinition($typeId, $typeDef);
235
236
            $typeConfig = [
237 12
                'name' => $name,
238
                'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch
239
                'config' => [],
240
            ];
241
242
            foreach ([
243 12
                'dynamic_templates',
244
                'properties',
245
                '_all',
246
                '_id',
247
                '_parent',
248
                '_routing',
249
                '_source',
250
            ] as $field) {
251 12
                if (isset($type[$field])) {
252 12
                    $typeConfig['mapping'][$field] = $type[$field];
253
                }
254
            }
255
256
            foreach ([
257 12
                'persistence',
258
                'serializer',
259
                'analyzer',
260
                'search_analyzer',
261
                'dynamic',
262
                'date_detection',
263
                'dynamic_date_formats',
264
                'numeric_detection',
265
            ] as $field) {
266 12
                $typeConfig['config'][$field] = array_key_exists($field, $type) ?
267 12
                    $type[$field] :
268 12
                    null;
269
            }
270
271 12
            $this->indexConfigs[$indexName]['types'][$name] = $typeConfig;
272
273 12
            if (isset($type['persistence'])) {
274 11
                $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
275
276 11
                $typeConfig['persistence'] = $type['persistence'];
277
            }
278
279 12
            if (isset($type['_parent'])) {
280
                // _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence`
281 2
                unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']);
282
            }
283
284 12
            if (isset($type['indexable_callback'])) {
285 1
                $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback'];
286
            }
287
288 12
            if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
289 1
                $typeSerializerId = sprintf('%s.serializer.callback', $typeId);
290 1
                $typeSerializerDef = new DefinitionDecorator('fos_elastica.serializer_callback_prototype');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
291
292 1
                if (isset($type['serializer']['groups'])) {
293 1
                    $typeSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]);
294
                }
295
296 1
                if (isset($type['serializer']['serialize_null'])) {
297 1
                    $typeSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]);
298
                }
299
300 1
                if (isset($type['serializer']['version'])) {
301 1
                    $typeSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]);
302
                }
303
304 1
                $typeDef->addMethodCall('setSerializer', [[new Reference($typeSerializerId), 'serialize']]);
305 12
                $container->setDefinition($typeSerializerId, $typeSerializerDef);
306
            }
307
        }
308 12
    }
309
310
    /**
311
     * Loads the optional provider and finder for a type.
312
     *
313
     * @param array            $typeConfig
314
     * @param ContainerBuilder $container
315
     * @param Reference        $typeRef
316
     * @param string           $indexName
317
     * @param string           $typeName
318
     */
319 11
    private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
320
    {
321 11
        if (isset($typeConfig['driver'])) {
322 11
            $this->loadDriver($container, $typeConfig['driver']);
323
        }
324
325 11
        $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
326 11
        $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
327 11
        $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
328
329 11
        if (isset($typeConfig['provider'])) {
330 11
            if (!class_exists(Pagerfanta::class)) {
331
                throw new \InvalidArgumentException('A pager provider needs "pagerfanta/pagerfanta:^1"  to be installed.');
332 11
            }
333 6
334
            $this->loadTypePagerProvider($typeConfig, $container, $indexName, $typeName);
335
        }
336
        if (isset($typeConfig['finder'])) {
337 6
            $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
338
        }
339
        if (isset($typeConfig['listener'])) {
340 11
            $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
341 11
        }
342
    }
343 11
344 11
    /**
345
     * Creates and loads an ElasticaToModelTransformer.
346 11
     *
347
     * @param array            $typeConfig
348
     * @param ContainerBuilder $container
349
     * @param string           $indexName
350
     * @param string           $typeName
351
     *
352
     * @return string
353
     */
354
    private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
355
    {
356
        if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
357
            return $typeConfig['elastica_to_model_transformer']['service'];
358 11
        }
359
360 11
        /* Note: transformer services may conflict with "prototype.driver", if
361 1
         * the index and type names were "prototype" and a driver, respectively.
362
         */
363
        $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
364
        $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
365
        $serviceDef = new DefinitionDecorator($abstractId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
366
        $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['type' => $typeName, 'index' => $indexName]);
367 10
368 10
        // Doctrine has a mandatory service as first argument
369 10
        $argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
370 10
371
        $serviceDef->replaceArgument($argPos, $typeConfig['model']);
372
        $serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], [
373 10
            'identifier' => $typeConfig['identifier'],
374
        ]));
375 10
        $container->setDefinition($serviceId, $serviceDef);
376 10
377 10
        return $serviceId;
378
    }
379 10
380
    /**
381 10
     * Creates and loads a ModelToElasticaTransformer for an index/type.
382
     *
383
     * @param array            $typeConfig
384
     * @param ContainerBuilder $container
385
     * @param string           $indexName
386
     * @param string           $typeName
387
     *
388
     * @return string
389
     */
390
    private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
391
    {
392
        if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
393
            return $typeConfig['model_to_elastica_transformer']['service'];
394 11
        }
395
396 11
        $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
397
            'fos_elastica.model_to_elastica_identifier_transformer' :
398
            'fos_elastica.model_to_elastica_transformer';
399
400 11
        $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
401 1
        $serviceDef = new DefinitionDecorator($abstractId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
402 11
        $serviceDef->replaceArgument(0, [
403
            'identifier' => $typeConfig['identifier'],
404 11
        ]);
405 11
        $container->setDefinition($serviceId, $serviceDef);
406 11
407 11
        return $serviceId;
408
    }
409 11
410
    /**
411 11
     * Creates and loads an object persister for a type.
412
     *
413
     * @param array            $typeConfig
414
     * @param Reference        $typeRef
415
     * @param ContainerBuilder $container
416
     * @param string           $indexName
417
     * @param string           $typeName
418
     * @param string           $transformerId
419
     *
420
     * @return string
421
     */
422
    private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
423
    {
424
        if (isset($typeConfig['persister']['service'])) {
425
            return $typeConfig['persister']['service'];
426 11
        }
427
428 11
        $arguments = [
429 1
            $typeRef,
430
            new Reference($transformerId),
431
            $typeConfig['model'],
432
        ];
433 10
434 10
        if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
435 10
            $abstractId = 'fos_elastica.object_serializer_persister';
436
            $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
437
            $arguments[] = [new Reference($callbackId), 'serialize'];
438 10
        } else {
439 1
            $abstractId = 'fos_elastica.object_persister';
440 1
            $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
441 1
            $argument = $mapping['properties'];
442
            if (isset($mapping['_parent'])) {
443 9
                $argument['_parent'] = $mapping['_parent'];
444 9
            }
445 9
            $arguments[] = $argument;
446 9
        }
447 1
448
        $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
449 9
        $serviceDef = new DefinitionDecorator($abstractId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
450
        foreach ($arguments as $i => $argument) {
451
            $serviceDef->replaceArgument($i, $argument);
452 10
        }
453 10
454 10
        $serviceDef->addTag('fos_elastica.persister', ['index' => $indexName, 'type' => $typeName]);
455 10
456
        $container->setDefinition($serviceId, $serviceDef);
457
458 10
        return $serviceId;
459
    }
460 10
461
    /**
462 10
     * Loads a pager provider for a type.
463
     *
464
     * @param array            $typeConfig
465
     * @param ContainerBuilder $container
466
     * @param string           $indexName
467
     * @param string           $typeName
468
     *
469
     * @return string
470
     */
471
    private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
472
    {
473
        if (isset($typeConfig['provider']['service'])) {
474
            return $typeConfig['provider']['service'];
475
        }
476 11
477
        $baseConfig = $typeConfig['provider'];
478 11
        unset($baseConfig['service']);
479
480
        $driver = $typeConfig['driver'];
481
482
        switch ($driver) {
483
            case 'orm':
484
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
485 11
                $providerDef->replaceArgument(2, $typeConfig['model']);
486 11
                $providerDef->replaceArgument(3, $baseConfig);
487 11
488 11
                break;
489 11 View Code Duplication
            case 'mongodb':
490
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
491 11
                $providerDef->replaceArgument(2, $typeConfig['model']);
492 11
                $providerDef->replaceArgument(3, $baseConfig);
493 11
494
                break;
495 11 View Code Duplication
            case 'phpcr':
496
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
497 11
                $providerDef->replaceArgument(2, $typeConfig['model']);
498
                $providerDef->replaceArgument(3, $baseConfig);
499
500
                break;
501 View Code Duplication
            case 'propel':
502
                $providerDef = new DefinitionDecorator('fos_elastica.pager_provider.prototype.'.$driver);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
503
                $providerDef->replaceArgument(0, $typeConfig['model']);
504
                $providerDef->replaceArgument(1, $baseConfig);
505
506
                break;
507
            default:
508
                throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver));
509
        }
510 6
511
        /* Note: provider services may conflict with "prototype.driver", if the
512
         * index and type names were "prototype" and a driver, respectively.
513
         */
514
        $providerId = sprintf('fos_elastica.pager_provider.%s.%s', $indexName, $typeName);
515
        $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName, 'type' => $typeName]);
516
517 6
        $container->setDefinition($providerId, $providerDef);
518 6
519
        return $providerId;
520 6
    }
521
522
    /**
523 6
     * Loads doctrine listeners to handle indexing of new or updated objects.
524 2
     *
525 2
     * @param array            $typeConfig
526 2
     * @param ContainerBuilder $container
527
     * @param string           $objectPersisterId
528 2
     * @param string           $indexName
529 4
     * @param string           $typeName
530
     *
531
     * @return string
532
     */
533
    private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
534
    {
535 4
        if (isset($typeConfig['listener']['service'])) {
536 1
            return $typeConfig['listener']['service'];
537 1
        }
538 1
539
        /* Note: listener services may conflict with "prototype.driver", if the
540 1
         * index and type names were "prototype" and a driver, respectively.
541 3
         */
542 3
        $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']);
543 3
        $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
544 3
        $listenerDef = new DefinitionDecorator($abstractListenerId);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
545
        $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
546 3
        $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
547
            new Reference($typeConfig['listener']['logger']) :
548
            null
549
        );
550
        $listenerConfig = [
551
            'identifier' => $typeConfig['identifier'],
552
            'indexName' => $indexName,
553
            'typeName' => $typeName,
554 6
        ];
555 6
556
        $tagName = null;
557 6
        switch ($typeConfig['driver']) {
558
            case 'orm':
559 6
                $tagName = 'doctrine.event_listener';
560
                break;
561
            case 'phpcr':
562
                $tagName = 'doctrine_phpcr.event_listener';
563
                break;
564
            case 'mongodb':
565
                $tagName = 'doctrine_mongodb.odm.event_listener';
566
                break;
567
        }
568
569
        if ($typeConfig['listener']['defer']) {
570
            $listenerDef->setPublic(true);
571
            $listenerDef->addTag(
572
                'kernel.event_listener',
573 11
                ['event' => 'kernel.terminate', 'method' => 'onTerminate']
574
            );
575 11
            $listenerDef->addTag(
576
                'kernel.event_listener',
577
                ['event' => 'console.terminate', 'method' => 'onTerminate']
578
            );
579
            $listenerConfig['defer'] = true;
580
        }
581
582 11
        $listenerDef->replaceArgument(2, $listenerConfig);
583 11
584 11
        if (null !== $tagName) {
585 11
            foreach ($this->getDoctrineEvents($typeConfig) as $event) {
586 11
                $listenerDef->addTag($tagName, ['event' => $event]);
587
            }
588 11
        }
589
590
        $container->setDefinition($listenerId, $listenerDef);
591 11
592 11
        return $listenerId;
593 11
    }
594
595
    /**
596 11
     * Map Elastica to Doctrine events for the current driver.
597 11
     */
598 11
    private function getDoctrineEvents(array $typeConfig)
599 7
    {
600 7
        switch ($typeConfig['driver']) {
601 4
            case 'orm':
602 1
                $eventsClass = '\Doctrine\ORM\Events';
603 1
                break;
604 3
            case 'phpcr':
605
                $eventsClass = '\Doctrine\ODM\PHPCR\Event';
606
                break;
607
            case 'mongodb':
608
                $eventsClass = '\Doctrine\ODM\MongoDB\Events';
609 11
                break;
610
            default:
611
                throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
612
        }
613
614
        $events = [];
615
        $eventMapping = [
616
            'insert' => [constant($eventsClass.'::postPersist')],
617
            'update' => [constant($eventsClass.'::postUpdate')],
618
            'delete' => [constant($eventsClass.'::preRemove')],
619
            'flush' => [constant($eventsClass.'::postFlush')],
620
        ];
621
622 11
        foreach ($eventMapping as $event => $doctrineEvents) {
623
            if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
624 11
                $events = array_merge($events, $doctrineEvents);
625 8
            }
626 8
        }
627
628
        return $events;
629
    }
630 11
631
    /**
632 11
     * Loads a Type specific Finder.
633
     *
634
     * @param array            $typeConfig
635
     * @param ContainerBuilder $container
636
     * @param string           $elasticaToModelId
637
     * @param Reference        $typeRef
638 8
     * @param string           $indexName
639
     * @param string           $typeName
640 8
     *
641 8
     * @return string
642 7
     */
643 7
    private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
644 1
    {
645 1
        if (isset($typeConfig['finder']['service'])) {
646 1
            $finderId = $typeConfig['finder']['service'];
647
        } else {
648
            $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
649
            $finderDef = new DefinitionDecorator('fos_elastica.finder');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
650
            $finderDef->replaceArgument(0, $typeRef);
651
            $finderDef->replaceArgument(1, new Reference($elasticaToModelId));
652
            $container->setDefinition($finderId, $finderDef);
653
        }
654 8
655
        $indexTypeName = "$indexName/$typeName";
656 8
        $arguments = [$indexTypeName, new Reference($finderId)];
657 8
        if (isset($typeConfig['repository'])) {
658 8
            $arguments[] = $typeConfig['repository'];
659 8
        }
660
661
        $container->getDefinition('fos_elastica.repository_manager')
662 8
            ->addMethodCall('addType', $arguments);
663 8
664 8
        $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']);
665
        $container->getDefinition($managerId)
666
            ->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]);
667
668 8
        return $finderId;
669
    }
670
671
    /**
672
     * Loads the index manager.
673
     *
674
     * @param ContainerBuilder $container
675
     **/
676
    private function loadIndexManager(ContainerBuilder $container)
677
    {
678
        $indexRefs = array_map(function ($index) {
679
            return $index['reference'];
680
        }, $this->indexConfigs);
681
682
        $managerDef = $container->getDefinition('fos_elastica.index_manager');
683 11
        $managerDef->replaceArgument(0, $indexRefs);
684
    }
685 11
686
    /**
687
     * Makes sure a specific driver has been loaded.
688 11
     *
689 11
     * @param ContainerBuilder $container
690 11
     * @param string           $driver
691 11
     */
692 11
    private function loadDriver(ContainerBuilder $container, $driver)
693
    {
694
        if (in_array($driver, $this->loadedDrivers)) {
695 11
            return;
696 11
        }
697 11
698 1
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
699
        $loader->load($driver.'.xml');
700
        $this->loadedDrivers[] = $driver;
701 11
    }
702 11
703
    /**
704 11
     * Loads and configures the serializer prototype.
705 11
     *
706 11
     * @param array            $config
707
     * @param ContainerBuilder $container
708 11
     */
709
    private function loadSerializer($config, ContainerBuilder $container)
710
    {
711
        $container->setAlias('fos_elastica.serializer', $config['serializer']);
712
713
        $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
714
        $serializer->setClass($config['callback_class']);
715
716
        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...
717
            $serializer->addMethodCall('setContainer', [new Reference('service_container')]);
718 12
        }
719 12
    }
720 12
721
    /**
722 12
     * Creates a default manager alias for defined default manager or the first loaded driver.
723 12
     *
724 12
     * @param string           $defaultManager
725
     * @param ContainerBuilder $container
726
     */
727
    private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
728
    {
729
        if (0 == count($this->loadedDrivers)) {
730
            return;
731
        }
732 11
733
        if (count($this->loadedDrivers) > 1
734 11
            && in_array($defaultManager, $this->loadedDrivers)
735 3
        ) {
736
            $defaultManagerService = $defaultManager;
737
        } else {
738 11
            $defaultManagerService = $this->loadedDrivers[0];
739 11
        }
740 11
741 11
        $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
742
    }
743
744
    /**
745
     * Returns a reference to a client given its configured name.
746
     *
747
     * @param string $clientName
748
     *
749 1
     * @return Reference
750
     *
751 1
     * @throws \InvalidArgumentException
752
     */
753 1
    private function getClient($clientName)
754 1
    {
755
        if (!array_key_exists($clientName, $this->clients)) {
756 1
            throw new \InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
757
        }
758
759 1
        return $this->clients[$clientName]['reference'];
760
    }
761
}
762