Completed
Push — master ( 8b30ba...c06433 )
by Karel
04:39
created

Configuration::addIndexTemplatesSection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 19
cts 19
cp 1
rs 9.568
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
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\Definition\Builder\ArrayNodeDefinition;
15
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
16
use Symfony\Component\Config\Definition\ConfigurationInterface;
17
18
class Configuration implements ConfigurationInterface
19
{
20
    const SUPPORTED_DRIVERS = ['orm', 'mongodb', 'phpcr'];
21
22
    /**
23
     * If the kernel is running in debug mode.
24
     *
25
     * @var bool
26
     */
27
    private $debug;
28
29 35
    public function __construct($debug)
30
    {
31 35
        $this->debug = $debug;
32 35
    }
33
34
    /**
35
     * Generates the configuration tree.
36
     *
37
     * @return TreeBuilder
38
     */
39 35
    public function getConfigTreeBuilder()
40
    {
41 35
        $treeBuilder = new TreeBuilder('fos_elastica');
42
43 35
        if (method_exists($treeBuilder, 'getRootNode')) {
44 35
            $rootNode = $treeBuilder->getRootNode();
45
        } else {
46
            // BC layer for symfony/config 4.1 and older
47
            $rootNode = $treeBuilder->root('fos_elastica');
48
        }
49
50 35
        $this->addClientsSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
51 35
        $this->addIndexesSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
52 35
        $this->addIndexTemplatesSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
53
54
        $rootNode
55 35
            ->children()
56 35
                ->scalarNode('default_client')
57 35
                    ->info('Defaults to the first client defined')
58 35
                ->end()
59 35
                ->scalarNode('default_index')
60 35
                    ->info('Defaults to the first index defined')
61 35
                ->end()
62 35
                ->scalarNode('default_manager')->defaultValue('orm')->end()
63 35
                ->arrayNode('serializer')
64 35
                    ->treatNullLike([])
65 35
                    ->children()
66 35
                        ->scalarNode('callback_class')->defaultValue('FOS\ElasticaBundle\Serializer\Callback')->end()
67 35
                        ->scalarNode('serializer')->defaultValue('serializer')->end()
68 35
                    ->end()
69 35
                ->end()
70 35
            ->end()
71
        ;
72
73 35
        return $treeBuilder;
74
    }
75
76
    /**
77
     * Returns the array node used for "dynamic_templates".
78
     */
79 35
    private function getDynamicTemplateNode()
80
    {
81 35
        $node = $this->createTreeBuilderNode('dynamic_templates');
82
83
        $node
84 35
            ->prototype('array')
85 35
                ->prototype('array')
86 35
                    ->children()
87 35
                        ->scalarNode('match')->end()
88 35
                        ->scalarNode('unmatch')->end()
89 35
                        ->scalarNode('match_mapping_type')->end()
90 35
                        ->scalarNode('path_match')->end()
91 35
                        ->scalarNode('path_unmatch')->end()
92 35
                        ->scalarNode('match_pattern')->end()
93 35
                        ->arrayNode('mapping')
94 35
                            ->prototype('variable')
95 35
                                ->treatNullLike([])
96 35
                            ->end()
97 35
                        ->end()
98 35
                    ->end()
99 35
                ->end()
100 35
            ->end()
101
        ;
102
103 35
        return $node;
104
    }
105
106
    /**
107
     * Returns the array node used for "types".
108
     */
109 35
    private function getTypesNode()
110
    {
111 35
        $node = $this->createTreeBuilderNode('types');
112
113
        $node
0 ignored issues
show
Bug introduced by
The method useAttributeAsKey() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. Did you maybe mean attribute()?

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

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

Loading history...
114 35
            ->useAttributeAsKey('name')
115 35
            ->prototype('array')
116 35
                ->treatNullLike([])
117 35
                ->beforeNormalization()
118 35
                ->ifNull()
119 35
                    ->thenEmptyArray()
120 35
                ->end()
121
                // Support multiple dynamic_template formats to match the old bundle style
122
                // and the way ElasticSearch expects them
123 35
                ->beforeNormalization()
124 35
                ->ifTrue(function ($v) {
125 25
                    return isset($v['dynamic_templates']);
126 35
                })
127 35
                ->then(function ($v) {
128 5
                    $dt = [];
129 5
                    foreach ($v['dynamic_templates'] as $key => $type) {
130 5
                        if (is_int($key)) {
131 5
                            $dt[] = $type;
132
                        } else {
133 5
                            $dt[][$key] = $type;
134
                        }
135
                    }
136
137 5
                    $v['dynamic_templates'] = $dt;
138
139 5
                    return $v;
140 35
                })
141 35
                ->end()
142 35
                ->children()
143 35
                    ->booleanNode('date_detection')->end()
144 35
                    ->arrayNode('dynamic_date_formats')->prototype('scalar')->end()->end()
145 35
                    ->scalarNode('analyzer')->end()
146 35
                    ->booleanNode('numeric_detection')->end()
147 35
                    ->scalarNode('dynamic')->end()
148 35
                    ->variableNode('indexable_callback')->end()
149 35
                    ->append($this->getPersistenceNode())
150 35
                    ->append($this->getSerializerNode())
151 35
                ->end()
152 35
                ->append($this->getIdNode())
153 35
                ->append($this->getPropertiesNode())
154 35
                ->append($this->getDynamicTemplateNode())
155 35
                ->append($this->getSourceNode())
156 35
                ->append($this->getRoutingNode())
157 35
                ->append($this->getParentNode())
158 35
                ->append($this->getAllNode())
159 35
            ->end()
160
        ;
161
162 35
        return $node;
163
    }
164
165
    /**
166
     * Returns the array node used for "properties".
167
     */
168 35
    private function getPropertiesNode()
169
    {
170 35
        $node = $this->createTreeBuilderNode('properties');
171
172
        $node
0 ignored issues
show
Bug introduced by
The method useAttributeAsKey() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. Did you maybe mean attribute()?

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

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

Loading history...
173 35
            ->useAttributeAsKey('name')
174 35
            ->prototype('variable')
175 35
                ->treatNullLike([]);
176
177 35
        return $node;
178
    }
179
180
    /**
181
     * Returns the array node used for "_id".
182
     */
183 35
    private function getIdNode()
184
    {
185 35
        $node = $this->createTreeBuilderNode('_id');
186
187
        $node
188 35
            ->children()
189 35
            ->scalarNode('path')->end()
190 35
            ->end()
191
        ;
192
193 35
        return $node;
194
    }
195
196
    /**
197
     * Returns the array node used for "_source".
198
     */
199 35
    private function getSourceNode()
200
    {
201 35
        $node = $this->createTreeBuilderNode('_source');
202
203
        $node
204 35
            ->children()
205 35
                ->arrayNode('excludes')
206 35
                    ->useAttributeAsKey('name')
207 35
                    ->prototype('scalar')->end()
208 35
                ->end()
209 35
                ->arrayNode('includes')
210 35
                    ->useAttributeAsKey('name')
211 35
                    ->prototype('scalar')->end()
212 35
                ->end()
213 35
                ->scalarNode('compress')->end()
214 35
                ->scalarNode('compress_threshold')->end()
215 35
                ->scalarNode('enabled')->defaultTrue()->end()
216 35
            ->end()
217
        ;
218
219 35
        return $node;
220
    }
221
222
    /**
223
     * Returns the array node used for "_routing".
224
     */
225 35
    private function getRoutingNode()
226
    {
227 35
        $node = $this->createTreeBuilderNode('_routing');
228
229
        $node
230 35
            ->children()
231 35
                ->scalarNode('required')->end()
232 35
                ->scalarNode('path')->end()
233 35
            ->end()
234
        ;
235
236 35
        return $node;
237
    }
238
239
    /**
240
     * Returns the array node used for "_parent".
241
     */
242 35
    private function getParentNode()
243
    {
244 35
        $node = $this->createTreeBuilderNode('_parent');
245
246
        $node
247 35
            ->children()
248 35
                ->scalarNode('type')->end()
249 35
                ->scalarNode('property')->defaultValue(null)->end()
250 35
                ->scalarNode('identifier')->defaultValue('id')->end()
251 35
            ->end()
252
        ;
253
254 35
        return $node;
255
    }
256
257
    /**
258
     * Returns the array node used for "_all".
259
     */
260 35
    private function getAllNode()
261
    {
262 35
        $node = $this->createTreeBuilderNode('_all');
263
264
        $node
265 35
            ->children()
266 35
            ->scalarNode('enabled')->defaultValue(true)->end()
267 35
            ->scalarNode('analyzer')->end()
268 35
            ->end()
269
        ;
270
271 35
        return $node;
272
    }
273
274
    /**
275
     * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
276
     */
277 35
    private function getPersistenceNode()
278
    {
279 35
        $node = $this->createTreeBuilderNode('persistence');
280
281
        $node
282 35
            ->validate()
283 35
                ->ifTrue(function ($v) {
284 17
                    return isset($v['driver']) && 'orm' !== $v['driver'] && !empty($v['elastica_to_model_transformer']['hints']);
285 35
                })
286 35
                    ->thenInvalid('Hints are only supported by the "orm" driver')
287 35
            ->end()
288 35
            ->children()
289 35
                ->scalarNode('driver')
290 35
                    ->defaultValue('orm')
291 35
                    ->validate()
292 35
                    ->ifNotInArray(self::SUPPORTED_DRIVERS)
293 35
                        ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode(self::SUPPORTED_DRIVERS))
294 35
                    ->end()
295 35
                ->end()
296 35
                ->scalarNode('model')->defaultValue(null)->end()
297 35
                ->scalarNode('repository')->end()
298 35
                ->scalarNode('identifier')->defaultValue('id')->end()
299 35
                ->arrayNode('provider')
300 35
                    ->addDefaultsIfNotSet()
301 35
                    ->children()
302 35
                        ->scalarNode('batch_size')->defaultValue(100)->end()
303 35
                        ->scalarNode('clear_object_manager')->defaultTrue()->end()
304 35
                        ->scalarNode('debug_logging')
305 35
                            ->defaultValue($this->debug)
306 35
                            ->treatNullLike(true)
307 35
                        ->end()
308 35
                        ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
309 35
                        ->scalarNode('service')->end()
310 35
                    ->end()
311 35
                ->end()
312 35
                ->arrayNode('listener')
313 35
                    ->addDefaultsIfNotSet()
314 35
                    ->children()
315 35
                        ->booleanNode('enabled')->defaultTrue()->end()
316 35
                        ->scalarNode('insert')->defaultTrue()->end()
317 35
                        ->scalarNode('update')->defaultTrue()->end()
318 35
                        ->scalarNode('delete')->defaultTrue()->end()
319 35
                        ->scalarNode('flush')->defaultTrue()->end()
320 35
                        ->booleanNode('defer')->defaultFalse()->end()
321 35
                        ->scalarNode('logger')
322 35
                            ->defaultFalse()
323 35
                            ->treatNullLike('fos_elastica.logger')
324 35
                            ->treatTrueLike('fos_elastica.logger')
325 35
                        ->end()
326 35
                        ->scalarNode('service')->end()
327 35
                    ->end()
328 35
                ->end()
329 35
                ->arrayNode('finder')
330 35
                    ->addDefaultsIfNotSet()
331 35
                    ->children()
332 35
                        ->scalarNode('service')->end()
333 35
                    ->end()
334 35
                ->end()
335 35
                ->arrayNode('elastica_to_model_transformer')
336 35
                    ->addDefaultsIfNotSet()
337 35
                    ->children()
338 35
                        ->arrayNode('hints')
339 35
                            ->prototype('array')
340 35
                                ->children()
341 35
                                    ->scalarNode('name')->end()
342 35
                                    ->scalarNode('value')->end()
343 35
                                ->end()
344 35
                            ->end()
345 35
                        ->end()
346 35
                        ->booleanNode('hydrate')->defaultTrue()->end()
347 35
                        ->booleanNode('ignore_missing')
348 35
                            ->defaultFalse()
349 35
                            ->info('Silently ignore results returned from Elasticsearch without corresponding persistent object.')
350 35
                        ->end()
351 35
                        ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
352 35
                        ->scalarNode('service')->end()
353 35
                    ->end()
354 35
                ->end()
355 35
                ->arrayNode('model_to_elastica_transformer')
356 35
                    ->addDefaultsIfNotSet()
357 35
                    ->children()
358 35
                        ->scalarNode('service')->end()
359 35
                    ->end()
360 35
                ->end()
361 35
                ->arrayNode('persister')
362 35
                    ->addDefaultsIfNotSet()
363 35
                    ->children()
364 35
                        ->enumNode('refresh')
365 35
                            ->treatTrueLike('true')
366 35
                            ->treatFalseLike('false')
367 35
                            ->values(['true', 'wait_for', 'false'])
368 35
                        ->end()
369 35
                        ->scalarNode('service')->end()
370 35
                    ->end()
371 35
                ->end()
372 35
            ->end();
373
374 35
        return $node;
375
    }
376
377
    /**
378
     * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
379
     */
380 35
    private function getSerializerNode()
381
    {
382 35
        $node = $this->createTreeBuilderNode('serializer');
383
384
        $node
385 35
            ->addDefaultsIfNotSet()
386 35
            ->children()
387 35
                ->arrayNode('groups')
388 35
                    ->treatNullLike([])
389 35
                    ->prototype('scalar')->end()
390 35
                ->end()
391 35
                ->scalarNode('version')->end()
392 35
                ->booleanNode('serialize_null')
393 35
                    ->defaultFalse()
394 35
                ->end()
395 35
            ->end();
396
397 35
        return $node;
398
    }
399
400
    /**
401
     * Adds the configuration for the "clients" key.
402
     */
403 35
    private function addClientsSection(ArrayNodeDefinition $rootNode)
404
    {
405
        $rootNode
406 35
            ->fixXmlConfig('client')
407 35
            ->children()
408 35
                ->arrayNode('clients')
409 35
                    ->useAttributeAsKey('id')
410 35
                    ->prototype('array')
411 35
                        ->performNoDeepMerging()
412
                        // Elastica names its properties with camel case, support both
413 35
                        ->beforeNormalization()
414 35
                        ->ifTrue(function ($v) {
415 33
                            return isset($v['connection_strategy']);
416 35
                        })
417 35
                        ->then(function ($v) {
418 5
                            $v['connectionStrategy'] = $v['connection_strategy'];
419 5
                            unset($v['connection_strategy']);
420
421 5
                            return $v;
422 35
                        })
423 35
                        ->end()
424
                        // If there is no connections array key defined, assume a single connection.
425 35
                        ->beforeNormalization()
426 35
                        ->ifTrue(function ($v) {
427 33
                            return is_array($v) && !array_key_exists('connections', $v);
428 35
                        })
429 35
                        ->then(function ($v) {
430
                            return [
431 33
                                'connections' => [$v],
432
                            ];
433 35
                        })
434 35
                        ->end()
435 35
                        ->children()
436 35
                            ->arrayNode('connections')
437 35
                                ->requiresAtLeastOneElement()
438 35
                                ->prototype('array')
439 35
                                    ->fixXmlConfig('header')
440 35
                                    ->children()
441 35
                                        ->scalarNode('url')
442 35
                                            ->validate()
443 35
                                                ->ifTrue(function ($url) {
444 19
                                                    return $url && '/' !== substr($url, -1);
445 35
                                                })
446 35
                                                ->then(function ($url) {
447 19
                                                    return $url.'/';
448 35
                                                })
449 35
                                            ->end()
450 35
                                        ->end()
451 35
                                        ->scalarNode('username')->end()
452 35
                                        ->scalarNode('password')->end()
453 35
                                        ->scalarNode('host')->end()
454 35
                                        ->scalarNode('port')->end()
455 35
                                        ->scalarNode('proxy')->end()
456 35
                                        ->arrayNode('http_error_codes')
457 35
                                            ->beforeNormalization()
458
                                                ->ifTrue(function ($v) { return !is_array($v); })
459
                                                ->then(function ($v) { return array($v); })
460 35
                                            ->end()
461 35
                                            ->cannotBeEmpty()
462 35
                                            ->defaultValue([400, 403, 404])
463 35
                                            ->prototype('scalar')->end()
464 35
                                        ->end()
465 35
                                        ->scalarNode('aws_access_key_id')->end()
466 35
                                        ->scalarNode('aws_secret_access_key')->end()
467 35
                                        ->scalarNode('aws_region')->end()
468 35
                                        ->scalarNode('aws_session_token')->end()
469 35
                                        ->booleanNode('ssl')->defaultValue(false)->end()
470 35
                                        ->scalarNode('logger')
471 35
                                            ->defaultValue($this->debug ? 'fos_elastica.logger' : false)
472 35
                                            ->treatNullLike('fos_elastica.logger')
473 35
                                            ->treatTrueLike('fos_elastica.logger')
474 35
                                        ->end()
475 35
                                        ->booleanNode('compression')->defaultValue(false)->end()
476 35
                                        ->arrayNode('headers')
477 35
                                            ->normalizeKeys(false)
478 35
                                            ->useAttributeAsKey('name')
479 35
                                            ->prototype('scalar')->end()
480 35
                                        ->end()
481 35
                                        ->arrayNode('curl')
482 35
                                            ->useAttributeAsKey(CURLOPT_SSL_VERIFYPEER)
483 35
                                            ->prototype('boolean')->end()
484 35
                                        ->end()
485 35
                                        ->scalarNode('transport')->end()
486 35
                                        ->scalarNode('timeout')->end()
487 35
                                        ->scalarNode('connectTimeout')->end()
488 35
                                        ->scalarNode('retryOnConflict')
489 35
                                            ->defaultValue(0)
490 35
                                        ->end()
491 35
                                    ->end()
492 35
                                ->end()
493 35
                            ->end()
494 35
                            ->scalarNode('timeout')->end()
495 35
                            ->scalarNode('connectTimeout')->end()
496 35
                            ->scalarNode('headers')->end()
497 35
                            ->scalarNode('connectionStrategy')->defaultValue('Simple')->end()
498 35
                        ->end()
499 35
                    ->end()
500 35
                ->end()
501 35
            ->end()
502
        ;
503 35
    }
504
505
    /**
506
     * Adds the configuration for the "indexes" key.
507
     */
508 35
    private function addIndexesSection(ArrayNodeDefinition $rootNode)
509
    {
510
        $rootNode
511 35
            ->fixXmlConfig('index')
512 35
            ->children()
513 35
                ->arrayNode('indexes')
514 35
                    ->useAttributeAsKey('name')
515 35
                    ->prototype('array')
516 35
                        ->children()
517 35
                            ->scalarNode('index_name')
518 35
                                ->info('Defaults to the name of the index, but can be modified if the index name is different in ElasticSearch')
519 35
                            ->end()
520 35
                            ->booleanNode('use_alias')->defaultValue(false)->end()
521 35
                            ->scalarNode('client')->end()
522 35
                            ->scalarNode('finder')
523 35
                                ->treatNullLike(true)
524 35
                                ->defaultFalse()
525 35
                            ->end()
526 35
                            ->arrayNode('type_prototype')
527 35
                                ->children()
528 35
                                    ->scalarNode('analyzer')->end()
529 35
                                    ->append($this->getPersistenceNode())
530 35
                                    ->append($this->getSerializerNode())
531 35
                                ->end()
532 35
                            ->end()
533 35
                            ->variableNode('settings')->defaultValue([])->end()
534 35
                        ->end()
535 35
                        ->append($this->getTypesNode())
536 35
                    ->end()
537 35
                ->end()
538 35
            ->end()
539
        ;
540 35
    }
541
542
    /**
543
     * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
544
     */
545 35
    private function createTreeBuilderNode($name)
546
    {
547 35
        $builder = new TreeBuilder($name);
548
549 35
        if (method_exists($builder, 'getRootNode')) {
550 35
            $node = $builder->getRootNode();
551
        } else {
552
            // BC layer for symfony/config 4.1 and older
553
            $node = $builder->root($name);
554
        }
555
556 35
        return $node;
557
    }
558
559
    /**
560
     * Adds the configuration for the "index_templates" key.
561
     *
562
     * @param ArrayNodeDefinition $rootNode
563
     *
564
     * @return void
565
     */
566 35
    private function addIndexTemplatesSection(ArrayNodeDefinition $rootNode)
567
    {
568
        $rootNode
569 35
            ->fixXmlConfig('index_template')
570 35
            ->children()
571 35
                ->arrayNode('index_templates')
572 35
                    ->useAttributeAsKey('name')
573 35
                    ->prototype('array')
574 35
                        ->children()
575 35
                            ->scalarNode('template_name')
576 35
                                ->info('Defaults to the name of the index template, but can be modified if the index name is different in ElasticSearch')
577 35
                            ->end()
578 35
                            ->scalarNode('template')->isRequired()->end()
579 35
                            ->scalarNode('client')->end()
580 35
                            ->variableNode('settings')->defaultValue([])->end()
581 35
                        ->end()
582 35
                        ->append($this->getTypesNode())
583 35
                    ->end()
584 35
                ->end()
585 35
            ->end()
586
        ;
587 35
    }
588
}
589