Completed
Pull Request — master (#1343)
by Dmitry
05:11
created

Configuration::getConfigTreeBuilder()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 2.0002

Importance

Changes 0
Metric Value
dl 0
loc 36
ccs 24
cts 25
cp 0.96
rs 9.344
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.0002
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 34
    public function __construct($debug)
30
    {
31 34
        $this->debug = $debug;
32 34
    }
33
34
    /**
35
     * Generates the configuration tree.
36
     *
37
     * @return TreeBuilder
38
     */
39 34
    public function getConfigTreeBuilder()
40
    {
41 34
        $treeBuilder = new TreeBuilder('fos_elastica');
42
43 34
        if (method_exists($treeBuilder, 'getRootNode')) {
44 34
            $rootNode = $treeBuilder->getRootNode();
45
        } else {
46
            // BC layer for symfony/config 4.1 and older
47
            $rootNode = $treeBuilder->root('fos_elastica');
48
        }
49
50 34
        $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 34
        $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 34
        $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 34
            ->children()
56 34
                ->scalarNode('default_client')
57 34
                    ->info('Defaults to the first client defined')
58 34
                ->end()
59 34
                ->scalarNode('default_index')
60 34
                    ->info('Defaults to the first index defined')
61 34
                ->end()
62 34
                ->scalarNode('default_manager')->defaultValue('orm')->end()
63 34
                ->arrayNode('serializer')
64 34
                    ->treatNullLike([])
65 34
                    ->children()
66 34
                        ->scalarNode('callback_class')->defaultValue('FOS\ElasticaBundle\Serializer\Callback')->end()
67 34
                        ->scalarNode('serializer')->defaultValue('serializer')->end()
68 34
                    ->end()
69 34
                ->end()
70 34
            ->end()
71
        ;
72
73 34
        return $treeBuilder;
74
    }
75
76
    /**
77
     * Returns the array node used for "dynamic_templates".
78
     */
79 34
    public function getDynamicTemplateNode()
80
    {
81 34
        $node = $this->createTreeBuilderNode('dynamic_templates');
82
83
        $node
84 34
            ->prototype('array')
85 34
                ->prototype('array')
86 34
                    ->children()
87 34
                        ->scalarNode('match')->end()
88 34
                        ->scalarNode('unmatch')->end()
89 34
                        ->scalarNode('match_mapping_type')->end()
90 34
                        ->scalarNode('path_match')->end()
91 34
                        ->scalarNode('path_unmatch')->end()
92 34
                        ->scalarNode('match_pattern')->end()
93 34
                        ->arrayNode('mapping')
94 34
                            ->prototype('variable')
95 34
                                ->treatNullLike([])
96 34
                            ->end()
97 34
                        ->end()
98 34
                    ->end()
99 34
                ->end()
100 34
            ->end()
101
        ;
102
103 34
        return $node;
104
    }
105
106
    /**
107
     * Returns the array node used for "types".
108
     */
109 34
    protected function getTypesNode()
110
    {
111 34
        $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 34
            ->useAttributeAsKey('name')
115 34
            ->prototype('array')
116 34
                ->treatNullLike([])
117 34
                ->beforeNormalization()
118 34
                ->ifNull()
119 34
                    ->thenEmptyArray()
120 34
                ->end()
121
                // Support multiple dynamic_template formats to match the old bundle style
122
                // and the way ElasticSearch expects them
123 34
                ->beforeNormalization()
124 34
                ->ifTrue(function ($v) {
125 25
                    return isset($v['dynamic_templates']);
126 34
                })
127 34
                ->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 34
                })
141 34
                ->end()
142 34
                ->children()
143 34
                    ->booleanNode('date_detection')->end()
144 34
                    ->arrayNode('dynamic_date_formats')->prototype('scalar')->end()->end()
145 34
                    ->scalarNode('analyzer')->end()
146 34
                    ->booleanNode('numeric_detection')->end()
147 34
                    ->scalarNode('dynamic')->end()
148 34
                    ->variableNode('indexable_callback')->end()
149 34
                    ->append($this->getPersistenceNode())
150 34
                    ->append($this->getSerializerNode())
151 34
                ->end()
152 34
                ->append($this->getIdNode())
153 34
                ->append($this->getPropertiesNode())
154 34
                ->append($this->getDynamicTemplateNode())
155 34
                ->append($this->getSourceNode())
156 34
                ->append($this->getRoutingNode())
157 34
                ->append($this->getParentNode())
158 34
                ->append($this->getAllNode())
159 34
            ->end()
160
        ;
161
162 34
        return $node;
163
    }
164
165
    /**
166
     * Returns the array node used for "properties".
167
     */
168 34
    protected function getPropertiesNode()
169
    {
170 34
        $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 34
            ->useAttributeAsKey('name')
174 34
            ->prototype('variable')
175 34
                ->treatNullLike([]);
176
177 34
        return $node;
178
    }
179
180
    /**
181
     * Returns the array node used for "_id".
182
     */
183 34
    protected function getIdNode()
184
    {
185 34
        $node = $this->createTreeBuilderNode('_id');
186
187
        $node
188 34
            ->children()
189 34
            ->scalarNode('path')->end()
190 34
            ->end()
191
        ;
192
193 34
        return $node;
194
    }
195
196
    /**
197
     * Returns the array node used for "_source".
198
     */
199 34
    protected function getSourceNode()
200
    {
201 34
        $node = $this->createTreeBuilderNode('_source');
202
203
        $node
204 34
            ->children()
205 34
                ->arrayNode('excludes')
206 34
                    ->useAttributeAsKey('name')
207 34
                    ->prototype('scalar')->end()
208 34
                ->end()
209 34
                ->arrayNode('includes')
210 34
                    ->useAttributeAsKey('name')
211 34
                    ->prototype('scalar')->end()
212 34
                ->end()
213 34
                ->scalarNode('compress')->end()
214 34
                ->scalarNode('compress_threshold')->end()
215 34
                ->scalarNode('enabled')->defaultTrue()->end()
216 34
            ->end()
217
        ;
218
219 34
        return $node;
220
    }
221
222
    /**
223
     * Returns the array node used for "_routing".
224
     */
225 34
    protected function getRoutingNode()
226
    {
227 34
        $node = $this->createTreeBuilderNode('_routing');
228
229
        $node
230 34
            ->children()
231 34
                ->scalarNode('required')->end()
232 34
                ->scalarNode('path')->end()
233 34
            ->end()
234
        ;
235
236 34
        return $node;
237
    }
238
239
    /**
240
     * Returns the array node used for "_parent".
241
     */
242 34
    protected function getParentNode()
243
    {
244 34
        $node = $this->createTreeBuilderNode('_parent');
245
246
        $node
247 34
            ->children()
248 34
                ->scalarNode('type')->end()
249 34
                ->scalarNode('property')->defaultValue(null)->end()
250 34
                ->scalarNode('identifier')->defaultValue('id')->end()
251 34
            ->end()
252
        ;
253
254 34
        return $node;
255
    }
256
257
    /**
258
     * Returns the array node used for "_all".
259
     */
260 34
    protected function getAllNode()
261
    {
262 34
        $node = $this->createTreeBuilderNode('_all');
263
264
        $node
265 34
            ->children()
266 34
            ->scalarNode('enabled')->defaultValue(true)->end()
267 34
            ->scalarNode('analyzer')->end()
268 34
            ->end()
269
        ;
270
271 34
        return $node;
272
    }
273
274
    /**
275
     * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
276
     */
277 34
    protected function getPersistenceNode()
278
    {
279 34
        $node = $this->createTreeBuilderNode('persistence');
280
281
        $node
282 34
            ->validate()
283 34
                ->ifTrue(function ($v) {
284 17
                    return isset($v['driver']) && 'orm' !== $v['driver'] && !empty($v['elastica_to_model_transformer']['hints']);
285 34
                })
286 34
                    ->thenInvalid('Hints are only supported by the "orm" driver')
287 34
            ->end()
288 34
            ->children()
289 34
                ->scalarNode('driver')
290 34
                    ->defaultValue('orm')
291 34
                    ->validate()
292 34
                    ->ifNotInArray(self::SUPPORTED_DRIVERS)
293 34
                        ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode(self::SUPPORTED_DRIVERS))
294 34
                    ->end()
295 34
                ->end()
296 34
                ->scalarNode('model')->defaultValue(null)->end()
297 34
                ->scalarNode('repository')->end()
298 34
                ->scalarNode('identifier')->defaultValue('id')->end()
299 34
                ->arrayNode('provider')
300 34
                    ->addDefaultsIfNotSet()
301 34
                    ->children()
302 34
                        ->scalarNode('batch_size')->defaultValue(100)->end()
303 34
                        ->scalarNode('clear_object_manager')->defaultTrue()->end()
304 34
                        ->scalarNode('debug_logging')
305 34
                            ->defaultValue($this->debug)
306 34
                            ->treatNullLike(true)
307 34
                        ->end()
308 34
                        ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
309 34
                        ->scalarNode('service')->end()
310 34
                    ->end()
311 34
                ->end()
312 34
                ->arrayNode('listener')
313 34
                    ->addDefaultsIfNotSet()
314 34
                    ->children()
315 34
                        ->booleanNode('enabled')->defaultTrue()->end()
316 34
                        ->scalarNode('insert')->defaultTrue()->end()
317 34
                        ->scalarNode('update')->defaultTrue()->end()
318 34
                        ->scalarNode('delete')->defaultTrue()->end()
319 34
                        ->scalarNode('flush')->defaultTrue()->end()
320 34
                        ->booleanNode('defer')->defaultFalse()->end()
321 34
                        ->scalarNode('logger')
322 34
                            ->defaultFalse()
323 34
                            ->treatNullLike('fos_elastica.logger')
324 34
                            ->treatTrueLike('fos_elastica.logger')
325 34
                        ->end()
326 34
                        ->scalarNode('service')->end()
327 34
                    ->end()
328 34
                ->end()
329 34
                ->arrayNode('finder')
330 34
                    ->addDefaultsIfNotSet()
331 34
                    ->children()
332 34
                        ->scalarNode('service')->end()
333 34
                    ->end()
334 34
                ->end()
335 34
                ->arrayNode('elastica_to_model_transformer')
336 34
                    ->addDefaultsIfNotSet()
337 34
                    ->children()
338 34
                        ->arrayNode('hints')
339 34
                            ->prototype('array')
340 34
                                ->children()
341 34
                                    ->scalarNode('name')->end()
342 34
                                    ->scalarNode('value')->end()
343 34
                                ->end()
344 34
                            ->end()
345 34
                        ->end()
346 34
                        ->booleanNode('hydrate')->defaultTrue()->end()
347 34
                        ->booleanNode('ignore_missing')
348 34
                            ->defaultFalse()
349 34
                            ->info('Silently ignore results returned from Elasticsearch without corresponding persistent object.')
350 34
                        ->end()
351 34
                        ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
352 34
                        ->scalarNode('service')->end()
353 34
                    ->end()
354 34
                ->end()
355 34
                ->arrayNode('model_to_elastica_transformer')
356 34
                    ->addDefaultsIfNotSet()
357 34
                    ->children()
358 34
                        ->scalarNode('service')->end()
359 34
                    ->end()
360 34
                ->end()
361 34
                ->arrayNode('persister')
362 34
                    ->addDefaultsIfNotSet()
363 34
                    ->children()
364 34
                        ->enumNode('refresh')
365 34
                            ->treatTrueLike('true')
366 34
                            ->treatFalseLike('false')
367 34
                            ->values(['true', 'wait_for', 'false'])
368 34
                        ->end()
369 34
                        ->scalarNode('service')->end()
370 34
                    ->end()
371 34
                ->end()
372 34
            ->end();
373
374 34
        return $node;
375
    }
376
377
    /**
378
     * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
379
     */
380 34
    protected function getSerializerNode()
381
    {
382 34
        $node = $this->createTreeBuilderNode('serializer');
383
384
        $node
385 34
            ->addDefaultsIfNotSet()
386 34
            ->children()
387 34
                ->arrayNode('groups')
388 34
                    ->treatNullLike([])
389 34
                    ->prototype('scalar')->end()
390 34
                ->end()
391 34
                ->scalarNode('version')->end()
392 34
                ->booleanNode('serialize_null')
393 34
                    ->defaultFalse()
394 34
                ->end()
395 34
            ->end();
396
397 34
        return $node;
398
    }
399
400
    /**
401
     * Adds the configuration for the "clients" key.
402
     */
403 34
    private function addClientsSection(ArrayNodeDefinition $rootNode)
404
    {
405
        $rootNode
406 34
            ->fixXmlConfig('client')
407 34
            ->children()
408 34
                ->arrayNode('clients')
409 34
                    ->useAttributeAsKey('id')
410 34
                    ->prototype('array')
411 34
                        ->performNoDeepMerging()
412
                        // Elastica names its properties with camel case, support both
413 34
                        ->beforeNormalization()
414 34
                        ->ifTrue(function ($v) {
415 32
                            return isset($v['connection_strategy']);
416 34
                        })
417 34
                        ->then(function ($v) {
418 5
                            $v['connectionStrategy'] = $v['connection_strategy'];
419 5
                            unset($v['connection_strategy']);
420
421 5
                            return $v;
422 34
                        })
423 34
                        ->end()
424
                        // If there is no connections array key defined, assume a single connection.
425 34
                        ->beforeNormalization()
426 34
                        ->ifTrue(function ($v) {
427 32
                            return is_array($v) && !array_key_exists('connections', $v);
428 34
                        })
429 34
                        ->then(function ($v) {
430
                            return [
431 32
                                'connections' => [$v],
432
                            ];
433 34
                        })
434 34
                        ->end()
435 34
                        ->children()
436 34
                            ->arrayNode('connections')
437 34
                                ->requiresAtLeastOneElement()
438 34
                                ->prototype('array')
439 34
                                    ->fixXmlConfig('header')
440 34
                                    ->children()
441 34
                                        ->scalarNode('url')
442 34
                                            ->validate()
443 34
                                                ->ifTrue(function ($url) {
444 19
                                                    return $url && '/' !== substr($url, -1);
445 34
                                                })
446 34
                                                ->then(function ($url) {
447 19
                                                    return $url.'/';
448 34
                                                })
449 34
                                            ->end()
450 34
                                        ->end()
451 34
                                        ->scalarNode('username')->end()
452 34
                                        ->scalarNode('password')->end()
453 34
                                        ->scalarNode('host')->end()
454 34
                                        ->scalarNode('port')->end()
455 34
                                        ->scalarNode('proxy')->end()
456 34
                                        ->scalarNode('aws_access_key_id')->end()
457 34
                                        ->scalarNode('aws_secret_access_key')->end()
458 34
                                        ->scalarNode('aws_region')->end()
459 34
                                        ->scalarNode('aws_session_token')->end()
460 34
                                        ->booleanNode('ssl')->defaultValue(false)->end()
461 34
                                        ->scalarNode('logger')
462 34
                                            ->defaultValue($this->debug ? 'fos_elastica.logger' : false)
463 34
                                            ->treatNullLike('fos_elastica.logger')
464 34
                                            ->treatTrueLike('fos_elastica.logger')
465 34
                                        ->end()
466 34
                                        ->booleanNode('compression')->defaultValue(false)->end()
467 34
                                        ->arrayNode('headers')
468 34
                                            ->normalizeKeys(false)
469 34
                                            ->useAttributeAsKey('name')
470 34
                                            ->prototype('scalar')->end()
471 34
                                        ->end()
472 34
                                        ->arrayNode('curl')
473 34
                                            ->useAttributeAsKey(CURLOPT_SSL_VERIFYPEER)
474 34
                                            ->prototype('boolean')->end()
475 34
                                        ->end()
476 34
                                        ->scalarNode('transport')->end()
477 34
                                        ->scalarNode('timeout')->end()
478 34
                                        ->scalarNode('connectTimeout')->end()
479 34
                                        ->scalarNode('retryOnConflict')
480 34
                                            ->defaultValue(0)
481 34
                                        ->end()
482 34
                                    ->end()
483 34
                                ->end()
484 34
                            ->end()
485 34
                            ->scalarNode('timeout')->end()
486 34
                            ->scalarNode('connectTimeout')->end()
487 34
                            ->scalarNode('headers')->end()
488 34
                            ->scalarNode('connectionStrategy')->defaultValue('Simple')->end()
489 34
                        ->end()
490 34
                    ->end()
491 34
                ->end()
492 34
            ->end()
493
        ;
494 34
    }
495
496
    /**
497
     * Adds the configuration for the "indexes" key.
498
     */
499 34
    private function addIndexesSection(ArrayNodeDefinition $rootNode)
500
    {
501
        $rootNode
502 34
            ->fixXmlConfig('index')
503 34
            ->children()
504 34
                ->arrayNode('indexes')
505 34
                    ->useAttributeAsKey('name')
506 34
                    ->prototype('array')
507 34
                        ->children()
508 34
                            ->scalarNode('index_name')
509 34
                                ->info('Defaults to the name of the index, but can be modified if the index name is different in ElasticSearch')
510 34
                            ->end()
511 34
                            ->booleanNode('use_alias')->defaultValue(false)->end()
512 34
                            ->scalarNode('client')->end()
513 34
                            ->scalarNode('finder')
514 34
                                ->treatNullLike(true)
515 34
                                ->defaultFalse()
516 34
                            ->end()
517 34
                            ->arrayNode('type_prototype')
518 34
                                ->children()
519 34
                                    ->scalarNode('analyzer')->end()
520 34
                                    ->append($this->getPersistenceNode())
521 34
                                    ->append($this->getSerializerNode())
522 34
                                ->end()
523 34
                            ->end()
524 34
                            ->variableNode('settings')->defaultValue([])->end()
525 34
                        ->end()
526 34
                        ->append($this->getTypesNode())
527 34
                    ->end()
528 34
                ->end()
529 34
            ->end()
530
        ;
531 34
    }
532
533
    /**
534
     * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
535
     */
536 34
    private function createTreeBuilderNode($name)
537
    {
538 34
        $builder = new TreeBuilder($name);
539
540 34
        if (method_exists($builder, 'getRootNode')) {
541 34
            $node = $builder->getRootNode();
542
        } else {
543
            // BC layer for symfony/config 4.1 and older
544
            $node = $builder->root($name);
545
        }
546
547 34
        return $node;
548
    }
549
550
    /**
551
     * Adds the configuration for the "index_templates" key.
552
     *
553
     * @param ArrayNodeDefinition $rootNode
554
     *
555
     * @return void
556
     */
557 34
    private function addIndexTemplatesSection(ArrayNodeDefinition $rootNode)
558
    {
559
        $rootNode
560 34
            ->fixXmlConfig('index_template')
561 34
            ->children()
562 34
                ->arrayNode('index_templates')
563 34
                    ->useAttributeAsKey('name')
564 34
                    ->prototype('array')
565 34
                        ->children()
566 34
                            ->scalarNode('template_name')
567 34
                                ->info('Defaults to the name of the index template, but can be modified if the index name is different in ElasticSearch')
568 34
                            ->end()
569 34
                            ->scalarNode('template')->isRequired()->end()
570 34
                            ->scalarNode('client')->end()
571 34
                            ->variableNode('settings')->defaultValue([])->end()
572 34
                        ->end()
573 34
                        ->append($this->getTypesNode())
574 34
                    ->end()
575 34
                ->end()
576 34
            ->end()
577
        ;
578 34
    }
579
}
580