Completed
Pull Request — master (#1343)
by Dmitry
08:46
created

Configuration::addIndexTemplatesSection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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