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