Completed
Push — master ( cc21e8...5c80a5 )
by Simonas
65:42
created

DependencyInjection/Configuration.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
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 ONGR\FilterManagerBundle\DependencyInjection;
13
14
use ONGR\ElasticsearchDSL\Aggregation\TermsAggregation;
15
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
16
use Symfony\Component\Config\Definition\Builder\ParentNodeDefinitionInterface;
17
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
18
use Symfony\Component\Config\Definition\ConfigurationInterface;
19
20
/**
21
 * This is the class that validates and merges configuration from app/config files.
22
 */
23
class Configuration implements ConfigurationInterface
24
{
25
    /**
26
     * {@inheritdoc}
27
     */
28
    public function getConfigTreeBuilder()
29
    {
30
        $treeBuilder = new TreeBuilder();
31
        $rootNode = $treeBuilder->root('ongr_filter_manager');
32
33
        $this->addManagersSection($rootNode);
34
        $this->addFiltersSection($rootNode);
35
        $this->addCacheSection($rootNode);
36
37
        return $treeBuilder;
38
    }
39
40
    /**
41
     * @param ArrayNodeDefinition $rootNode
42
     */
43
    private function addManagersSection(ArrayNodeDefinition $rootNode)
44
    {
45
        $rootNode
46
            ->children()
47
                ->arrayNode('managers')
48
                    ->requiresAtLeastOneElement()
49
                    ->useAttributeAsKey('name')
50
                    ->prototype('array')
51
                        ->children()
52
                            ->scalarNode('name')
53
                                ->info('Filter manager name')
54
                            ->end()
55
                            ->arrayNode('filters')
56
                                ->info('Filter names to include in manager.')
57
                                ->prototype('scalar')->end()
58
                            ->end()
59
                            ->scalarNode('repository')
60
                                ->isRequired()
61
                                ->info('ElasticsearchBundle repository used for fetching data.')
62
                            ->end()
63
                        ->end()
64
                    ->end()
65
                ->end()
66
            ->end();
67
    }
68
69
    /**
70
     * @param ArrayNodeDefinition $rootNode
71
     */
72
    private function addFiltersSection(ArrayNodeDefinition $rootNode)
73
    {
74
        $rootNode
75
            ->children()
76
                ->arrayNode('filters')
77
                    ->validate()
78
                        ->ifTrue(
79
                            function ($v) {
80
                                $v = array_filter($v);
81
82
                                return empty($v);
83
                            }
84
                        )
85
                        ->thenInvalid('At least single filter must be configured.')
86
                    ->end()
87
                    ->children()
88
                        ->append($this->buildFilterTree('choice'))
89
                        ->append($this->buildFilterTree('dynamic_aggregate'))
90
                        ->append($this->buildFilterTree('multi_dynamic_aggregate'))
91
                        ->append($this->buildFilterTree('multi_choice'))
92
                        ->append($this->buildFilterTree('match'))
93
                        ->append($this->buildFilterTree('fuzzy'))
94
                        ->append($this->buildFilterTree('sort'))
95
                        ->append($this->buildFilterTree('pager'))
96
                        ->append($this->buildFilterTree('range'))
97
                        ->append($this->buildFilterTree('date_range'))
98
                        ->append($this->buildFilterTree('field_value'))
99
                        ->append($this->buildFilterTree('document_value'))
100
                    ->end()
101
                ->end()
102
            ->end();
103
    }
104
105
    /**
106
     * @param ArrayNodeDefinition $rootNode
107
     */
108
    private function addCacheSection(ArrayNodeDefinition $rootNode)
109
    {
110
        $rootNode
111
            ->children()
112
                ->arrayNode('cache')
113
                    ->addDefaultsIfNotSet()
114
                    ->children()
115
                        ->scalarNode('engine')
116
                            ->info('Caching engine service name.')
117
                            ->defaultValue('es.cache_engine')
118
                        ->end()
119
                        ->arrayNode('exclude')
120
                            ->info('Array of filter names to exclude from caching.')
121
                            ->prototype('scalar')->end()
122
                        ->end()
123
                        ->integerNode('life_time')
124
                            ->info('Cached search life time.')
125
                            ->defaultValue(10800)
126
                        ->end()
127
                    ->end()
128
                ->end()
129
            ->end();
130
    }
131
    
132
    /**
133
     * Builds filter config tree for given filter name.
134
     *
135
     * @param string $filterName
136
     *
137
     * @return ArrayNodeDefinition
138
     */
139
    private function buildFilterTree($filterName)
140
    {
141
        $filter = new ArrayNodeDefinition($filterName);
142
143
        /** @var ParentNodeDefinitionInterface $node */
144
        $node = $filter
145
            ->requiresAtLeastOneElement()
146
            ->useAttributeAsKey('name')
147
            ->prototype('array')
148
                ->children()
149
                    ->scalarNode('name')->end()
150
                    ->arrayNode('relations')
151
                        ->children()
152
                            ->append($this->buildRelationsTree('search'))
153
                            ->append($this->buildRelationsTree('reset'))
154
                        ->end()
155
                    ->end()
156
                    ->scalarNode('field')
157
                        ->info('Document field name.')
158
                    ->end()
159
                    ->arrayNode('tags')
160
                        ->info('Filter tags that will be passed to view data.')
161
                        ->prototype('scalar')->end()
162
                    ->end()
163
                ->end();
164
165
        if ($filterName != 'field_value') {
166
            $node
167
                ->children()
168
                    ->scalarNode('request_field')
169
                        ->info('URL parameter name.')
170
                        ->isRequired()
171
                    ->end()
172
                ->end();
173
        }
174
175
        switch ($filterName) {
176
            case 'choice':
177 View Code Duplication
            case 'multi_choice':
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
178
                $node
179
                    ->children()
180
                        ->integerNode('size')
181
                            ->info('Result size to return.')
182
                        ->end()
183
                        ->booleanNode('show_zero_choices')->defaultFalse()->end()
184
                        ->arrayNode('sort')
185
                        ->children()
186
                            ->enumNode('type')
187
                                ->values(['_term', '_count'])
188
                                ->defaultValue('_term')
189
                            ->end()
190
                            ->enumNode('order')
191
                                ->values(['asc', 'desc'])
192
                                ->defaultValue('asc')
193
                            ->end()
194
                            ->arrayNode('priorities')->prototype('scalar')->end()
195
                            ->end()
196
                        ->end()
197
                    ->end();
198
                break;
199
            case 'dynamic_aggregate':
200 View Code Duplication
            case 'multi_dynamic_aggregate':
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
                $node
202
                    ->children()
203
                        ->scalarNode('name_field')
204
                            ->info('Name of the field to provide the aggregated values from.')
205
                        ->end()
206
                        ->booleanNode('show_zero_choices')->defaultFalse()->end()
207
                        ->arrayNode('sort')
208
                        ->children()
209
                            ->enumNode('type')
210
                                ->values(['_term', '_count'])
211
                                ->defaultValue('_term')
212
                            ->end()
213
                            ->enumNode('order')
214
                                ->values(['asc', 'desc'])
215
                                ->defaultValue('asc')
216
                            ->end()
217
                            ->arrayNode('priorities')->prototype('scalar')->end()
218
                            ->end()
219
                        ->end()
220
                    ->end();
221
                break;
222
            case 'match':
223
                $node
224
                    ->children()
225
                        ->scalarNode('operator')
226
                            ->info('The operator flag.')
227
                        ->end()
228
                        ->scalarNode('fuzziness')
229
                            ->info('The maximum edit distance.')
230
                        ->end()
231
                    ->end();
232
                break;
233
            case 'fuzzy':
234
                $node
235
                    ->children()
236
                        ->scalarNode('fuzziness')
237
                            ->info('The maximum edit distance.')
238
                        ->end()
239
                        ->integerNode('prefix_length')
240
                            ->info(
241
                                'The number of initial characters which will not be “fuzzified”.
242
                                This helps to reduce the number of terms which must be examined.'
243
                            )
244
                        ->end()
245
                        ->integerNode('max_expansions')
246
                            ->info('The maximum number of terms that the fuzzy query will expand to.')
247
                        ->end()
248
                    ->end();
249
                break;
250
            case 'sort':
251
                $node
252
                    ->children()
253
                        ->arrayNode('choices')
254
                            ->prototype('array')
255
                                ->beforeNormalization()
256
                                    ->always(
257
                                        function ($v) {
258
                                            if (empty($v['fields']) && !empty($v['field'])) {
259
                                                $field = ['field' => $v['field']];
260
                                                if (array_key_exists('order', $v)) {
261
                                                    $field['order'] = $v['order'];
262
                                                }
263
                                                if (array_key_exists('mode', $v)) {
264
                                                    $field['mode'] = $v['mode'];
265
                                                }
266
                                                $v['fields'][] = $field;
267
                                            }
268
269
                                            if (empty($v['label'])) {
270
                                                $v['label'] = $v['fields'][0]['field'];
271
                                            }
272
273
                                            return $v;
274
                                        }
275
                                    )
276
                                ->end()
277
                                ->addDefaultsIfNotSet()
278
                                ->children()
279
                                    ->scalarNode('label')->end()
280
                                    ->scalarNode('field')->end()
281
                                    ->scalarNode('order')->defaultValue('asc')->end()
282
                                    ->scalarNode('mode')->defaultNull()->end()
283
                                    ->scalarNode('key')->info('Custom parameter value')->end()
284
                                    ->booleanNode('default')->defaultFalse()->end()
285
                                    ->arrayNode('fields')
286
                                        ->isRequired()
287
                                        ->requiresAtLeastOneElement()
288
                                        ->prototype('array')
289
                                        ->children()
290
                                            ->scalarNode('field')->isRequired()->end()
291
                                            ->scalarNode('order')->defaultValue('asc')->end()
292
                                            ->scalarNode('mode')->defaultNull()->end()
293
                                        ->end()
294
                                    ->end()
295
                                ->end()
296
                            ->end()
297
                        ->end()
298
                    ->end();
299
                break;
300
            case 'pager':
301
                $node
302
                    ->children()
303
                        ->integerNode('count_per_page')
304
                            ->info('Item count per page')
305
                            ->defaultValue(10)
306
                        ->end()
307
                        ->integerNode('max_pages')
308
                            ->info('Max pages displayed in pager at once.')
309
                            ->defaultValue(8)
310
                        ->end()
311
                    ->end();
312
                break;
313
            case 'range':
314
            case 'date_range':
315
                $node
316
                    ->children()
317
                        ->booleanNode('inclusive')
318
                            ->info('Whether filter should match range ends.')
319
                            ->defaultFalse()
320
                        ->end()
321
                    ->end();
322
                break;
323
            case 'field_value':
324
                $node
325
                    ->children()
326
                        ->scalarNode('value')
327
                            ->info('Value which will be used for filtering.')
328
                            ->isRequired()
329
                    ->end();
330
                break;
331
            case 'document_value':
332
                $node
333
                    ->children()
334
                        ->scalarNode('document_field')
335
                            ->info('Field name from document object to pass to the filter.')
336
                            ->isRequired()
337
                    ->end();
338
                break;
339
            default:
340
                // Default config is enough.
341
                break;
342
        }
343
344
        return $filter;
345
    }
346
347
    /**
348
     * Builds relations config tree for given relation name.
349
     *
350
     * @param string $relationType
351
     *
352
     * @return ArrayNodeDefinition
353
     */
354
    private function buildRelationsTree($relationType)
355
    {
356
        $filter = new ArrayNodeDefinition($relationType);
357
358
        $filter
359
            ->validate()
360
                ->ifTrue(
361
                    function ($v) {
362
                        return empty($v['include']) && empty($v['exclude']);
363
                    }
364
                )
365
                ->thenInvalid('Relation must have "include" or "exclude" fields specified.')
366
            ->end()
367
            ->validate()
368
                ->ifTrue(
369
                    function ($v) {
370
                        return !empty($v['include']) && !empty($v['exclude']);
371
                    }
372
                )
373
                ->thenInvalid('Relation must have only "include" or "exclude" fields specified.')
374
            ->end()
375
            ->children()
376
                ->arrayNode('include')
377
                    ->beforeNormalization()
378
                        ->ifString()
379
                        ->then(
380
                            function ($v) {
381
                                return [$v];
382
                            }
383
                        )->end()
384
                    ->prototype('scalar')->end()
385
                ->end()
386
                ->arrayNode('exclude')
387
                    ->beforeNormalization()
388
                        ->ifString()
389
                        ->then(
390
                            function ($v) {
391
                                return [$v];
392
                            }
393
                        )
394
                    ->end()
395
                    ->prototype('scalar')->end()
396
                ->end()
397
            ->end();
398
399
        return $filter;
400
    }
401
}
402