Completed
Pull Request — master (#1636)
by Giovanni
03:11
created

Configuration::createTreeBuilderNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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