Completed
Pull Request — master (#1370)
by Mikhail
05:28
created

Configuration::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle 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\RestBundle\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
use Symfony\Component\HttpFoundation\Response;
18
19
/**
20
 * This class contains the configuration information for the bundle.
21
 *
22
 * This information is solely responsible for how the different configuration
23
 * sections are normalized, and merged.
24
 *
25
 * @author Lukas Kahwe Smith <[email protected]>
26
 *
27
 * @internal
28
 */
29
final class Configuration implements ConfigurationInterface
30
{
31
    /**
32
     * Default debug mode value.
33
     *
34
     * @var bool
35
     */
36
    private $debug;
37
38
    /**
39
     * @param bool $debug
40
     */
41 54
    public function __construct($debug)
42
    {
43 54
        $this->debug = (bool) $debug;
44 54
    }
45
46
    /**
47
     * Generates the configuration tree.
48
     *
49
     * @return TreeBuilder
50
     */
51 54
    public function getConfigTreeBuilder()
52
    {
53 54
        $treeBuilder = new TreeBuilder();
54 54
        $rootNode = $treeBuilder->root('fos_rest', 'array');
55
56
        $rootNode
57 54
            ->children()
58 54
                ->scalarNode('disable_csrf_role')->defaultNull()->end()
59 54
                ->arrayNode('access_denied_listener')
60 54
                    ->canBeEnabled()
61 54
                    ->beforeNormalization()
62 View Code Duplication
                        ->ifArray()->then(function ($v) { if (!empty($v) && empty($v['formats'])) {
0 ignored issues
show
Duplication introduced by
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...
63
     unset($v['enabled']);
64
     $v = ['enabled' => true, 'formats' => $v];
65
 }
66
67 54
return $v; })
68 54
                    ->end()
69 54
                    ->fixXmlConfig('format', 'formats')
70 54
                    ->children()
71 54
                        ->scalarNode('service')->defaultNull()->end()
72 54
                        ->arrayNode('formats')
73 54
                            ->useAttributeAsKey('name')
74 54
                            ->prototype('boolean')->end()
75 54
                        ->end()
76 54
                    ->end()
77 54
                ->end()
78 54
                ->scalarNode('unauthorized_challenge')->defaultNull()->end()
79 54
                ->arrayNode('param_fetcher_listener')
80 54
                    ->beforeNormalization()
81 54
                        ->ifString()
82 View Code Duplication
                        ->then(function ($v) { return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v]; })
0 ignored issues
show
Duplication introduced by
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...
83 54
                    ->end()
84 54
                    ->canBeEnabled()
85 54
                    ->children()
86 54
                        ->booleanNode('enabled')->defaultFalse()->end()
87 54
                        ->booleanNode('force')->defaultFalse()->end()
88 54
                        ->scalarNode('service')->defaultNull()->end()
89 54
                    ->end()
90 54
                ->end()
91 54
                ->scalarNode('cache_dir')->cannotBeEmpty()->defaultValue('%kernel.cache_dir%/fos_rest')->end()
92 54
                ->arrayNode('allowed_methods_listener')
93 54
                    ->canBeEnabled()
94 54
                    ->children()
95 54
                        ->scalarNode('service')->defaultNull()->end()
96 54
                    ->end()
97 54
                ->end()
98 54
                ->arrayNode('routing_loader')
99 54
                    ->addDefaultsIfNotSet()
100 54
                    ->children()
101 54
                        ->scalarNode('default_format')->defaultNull()->end()
102 54
                        ->scalarNode('include_format')->defaultTrue()->end()
103 54
                    ->end()
104 54
                ->end()
105 54
                ->arrayNode('body_converter')
106 54
                    ->addDefaultsIfNotSet()
107 54
                    ->children()
108 54
                        ->scalarNode('enabled')->defaultFalse()->end()
109 54
                        ->scalarNode('validate')->defaultFalse()->end()
110 54
                        ->scalarNode('validation_errors_argument')->defaultValue('validationErrors')->end()
111 54
                    ->end()
112 54
                ->end()
113 54
                ->arrayNode('service')
114 54
                    ->addDefaultsIfNotSet()
115 54
                    ->children()
116 54
                        ->scalarNode('router')->defaultValue('router')->end()
117 54
                        ->scalarNode('templating')->defaultValue('templating')->end()
118 54
                        ->scalarNode('serializer')->defaultNull()->end()
119 54
                        ->scalarNode('view_handler')->defaultValue('fos_rest.view_handler.default')->end()
120 54
                        ->scalarNode('inflector')->defaultValue('fos_rest.inflector.doctrine')->end()
121 54
                        ->scalarNode('validator')->defaultValue('validator')->end()
122 54
                    ->end()
123 54
                ->end()
124 54
                ->arrayNode('serializer')
125 54
                    ->addDefaultsIfNotSet()
126 54
                    ->children()
127 54
                        ->scalarNode('version')->defaultNull()->end()
128 54
                        ->arrayNode('groups')
129 54
                            ->prototype('scalar')->end()
130 54
                        ->end()
131 54
                        ->booleanNode('serialize_null')->defaultFalse()->end()
132 54
                    ->end()
133 54
                ->end()
134 54
                ->arrayNode('zone')
135 54
                    ->cannotBeOverwritten()
136 54
                    ->prototype('array')
137 54
                    ->fixXmlConfig('ip')
138 54
                    ->children()
139 54
                        ->scalarNode('path')
140 54
                            ->defaultNull()
141 54
                            ->info('use the urldecoded format')
142 54
                            ->example('^/path to resource/')
143 54
                        ->end()
144 54
                        ->scalarNode('host')->defaultNull()->end()
145 54
                        ->arrayNode('methods')
146
                            ->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
147 54
                            ->prototype('scalar')->end()
148 54
                        ->end()
149 54
                        ->arrayNode('ips')
150
                            ->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end()
151 54
                            ->prototype('scalar')->end()
152 54
                        ->end()
153 54
                    ->end()
154 54
                ->end()
155 54
            ->end()
156 54
        ->end();
157
158 54
        $this->addViewSection($rootNode);
159 54
        $this->addExceptionSection($rootNode);
160 54
        $this->addBodyListenerSection($rootNode);
161 54
        $this->addFormatListenerSection($rootNode);
162 54
        $this->addVersioningSection($rootNode);
163
164 54
        return $treeBuilder;
165
    }
166
167 54
    private function addViewSection(ArrayNodeDefinition $rootNode)
168
    {
169
        $rootNode
170 54
            ->children()
171 54
                ->arrayNode('view')
172 54
                    ->fixXmlConfig('format', 'formats')
173 54
                    ->fixXmlConfig('mime_type', 'mime_types')
174 54
                    ->fixXmlConfig('templating_format', 'templating_formats')
175 54
                    ->fixXmlConfig('force_redirect', 'force_redirects')
176 54
                    ->addDefaultsIfNotSet()
177 54
                    ->children()
178 54
                        ->scalarNode('default_engine')->defaultValue('twig')->end()
179 54
                        ->arrayNode('force_redirects')
180 54
                            ->useAttributeAsKey('name')
181 54
                            ->defaultValue(['html' => true])
182 54
                            ->prototype('boolean')->end()
183 54
                        ->end()
184 54
                        ->arrayNode('mime_types')
185 54
                            ->canBeEnabled()
186 54
                            ->beforeNormalization()
187 View Code Duplication
                                ->ifArray()->then(function ($v) {
0 ignored issues
show
Duplication introduced by
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...
188 1
                                    if (!empty($v) && empty($v['formats'])) {
189 1
                                        unset($v['enabled']);
190 1
                                        $v = ['enabled' => true, 'formats' => $v];
191 1
                                    }
192
193 1
                                    return $v;
194 54
                                })
195 54
                            ->end()
196 54
                            ->fixXmlConfig('format', 'formats')
197 54
                            ->children()
198 54
                                ->scalarNode('service')->defaultNull()->end()
199 54
                                ->arrayNode('formats')
200 54
                                    ->useAttributeAsKey('name')
201 54
                                    ->prototype('variable')->end()
202 54
                                ->end()
203 54
                            ->end()
204 54
                        ->end()
205 54
                        ->arrayNode('formats')
206 54
                            ->useAttributeAsKey('name')
207 54
                            ->defaultValue(['json' => true, 'xml' => true])
208 54
                            ->prototype('boolean')->end()
209 54
                        ->end()
210 54
                        ->arrayNode('templating_formats')
211 54
                            ->useAttributeAsKey('name')
212 54
                            ->defaultValue(['html' => true])
213 54
                            ->prototype('boolean')->end()
214 54
                        ->end()
215 54
                        ->arrayNode('view_response_listener')
216 54
                            ->beforeNormalization()
217 54
                                ->ifString()
218 View Code Duplication
                                ->then(function ($v) { return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v]; })
0 ignored issues
show
Duplication introduced by
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...
219 54
                            ->end()
220 54
                            ->canBeEnabled()
221 54
                            ->children()
222 54
                                ->booleanNode('enabled')->defaultFalse()->end()
223 54
                                ->booleanNode('force')->defaultFalse()->end()
224 54
                                ->scalarNode('service')->defaultNull()->end()
225 54
                            ->end()
226 54
                        ->end()
227 54
                        ->scalarNode('failed_validation')->defaultValue(Response::HTTP_BAD_REQUEST)->end()
228 54
                        ->scalarNode('empty_content')->defaultValue(Response::HTTP_NO_CONTENT)->end()
229 54
                        ->booleanNode('serialize_null')->defaultFalse()->end()
230 54
                        ->arrayNode('jsonp_handler')
231 54
                            ->canBeUnset()
232 54
                            ->children()
233 54
                                ->scalarNode('callback_param')->defaultValue('callback')->end()
234 54
                                ->scalarNode('mime_type')->defaultValue('application/javascript+jsonp')->end()
235 54
                            ->end()
236 54
                        ->end()
237 54
                    ->end()
238 54
                ->end()
239 54
            ->end();
240 54
    }
241
242 54
    private function addBodyListenerSection(ArrayNodeDefinition $rootNode)
243
    {
244
        $rootNode
245 54
            ->children()
246 54
                ->arrayNode('body_listener')
247 54
                    ->fixXmlConfig('decoder', 'decoders')
248 54
                    ->addDefaultsIfNotSet()
249 54
                    ->canBeUnset()
250 54
                    ->canBeDisabled()
251 54
                    ->children()
252 54
                        ->scalarNode('service')->defaultNull()->end()
253 54
                        ->scalarNode('default_format')->defaultNull()->end()
254 54
                        ->booleanNode('throw_exception_on_unsupported_content_type')
255 54
                            ->defaultFalse()
256 54
                        ->end()
257 54
                        ->arrayNode('decoders')
258 54
                            ->useAttributeAsKey('name')
259 54
                            ->defaultValue(['json' => 'fos_rest.decoder.json', 'xml' => 'fos_rest.decoder.xml'])
260 54
                            ->prototype('scalar')->end()
261 54
                        ->end()
262 54
                        ->arrayNode('array_normalizer')
263 54
                            ->addDefaultsIfNotSet()
264 54
                            ->beforeNormalization()
265
                                ->ifString()->then(function ($v) { return ['service' => $v]; })
266 54
                            ->end()
267 54
                            ->children()
268 54
                                ->scalarNode('service')->defaultNull()->end()
269 54
                                ->booleanNode('forms')->defaultFalse()->end()
270 54
                            ->end()
271 54
                        ->end()
272 54
                    ->end()
273 54
                ->end()
274 54
            ->end();
275 54
    }
276
277 54
    private function addFormatListenerSection(ArrayNodeDefinition $rootNode)
278
    {
279
        $rootNode
280 54
            ->children()
281 54
                ->arrayNode('format_listener')
282 54
                    ->fixXmlConfig('rule', 'rules')
283 54
                    ->addDefaultsIfNotSet()
284 54
                    ->canBeUnset()
285 54
                    ->beforeNormalization()
286
                        ->ifTrue(function ($v) {
287
                            // check if we got an assoc array in rules
288 7
                            return isset($v['rules'])
289 7
                                && is_array($v['rules'])
290 7
                                && array_keys($v['rules']) !== range(0, count($v['rules']) - 1);
291 54
                        })
292
                        ->then(function ($v) {
293 1
                            $v['rules'] = [$v['rules']];
294
295 1
                            return $v;
296 54
                        })
297 54
                    ->end()
298 54
                    ->canBeEnabled()
299 54
                    ->validate()
300
                        ->ifTrue(function ($v) { return empty($v['rules']) && !empty($v['media_type']['enabled']); })
301 54
                        ->thenInvalid('To enable the "media_type" setting, a "rules" setting must also needs to be defined for the "format_listener"')
302 54
                    ->end()
303 54
                    ->children()
304 54
                        ->scalarNode('service')->defaultNull()->end()
305 54
                        ->arrayNode('rules')
306 54
                            ->cannotBeOverwritten()
307 54
                            ->prototype('array')
308 54
                                ->fixXmlConfig('priority', 'priorities')
309 54
                                ->fixXmlConfig('attribute', 'attributes')
310 54
                                ->children()
311 54
                                    ->scalarNode('path')->defaultNull()->info('URL path info')->end()
312 54
                                    ->scalarNode('host')->defaultNull()->info('URL host name')->end()
313 54
                                    ->variableNode('methods')->defaultNull()->info('Method for URL')->end()
314 54
                                    ->arrayNode('attributes')
315 54
                                        ->useAttributeAsKey('name')
316 54
                                        ->prototype('variable')->end()
317 54
                                    ->end()
318 54
                                    ->booleanNode('stop')->defaultFalse()->end()
319 54
                                    ->booleanNode('prefer_extension')->defaultTrue()->end()
320 54
                                    ->scalarNode('fallback_format')->defaultValue('html')->end()
321 54
                                    ->arrayNode('priorities')
322
                                        ->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
323 54
                                        ->prototype('scalar')->end()
324 54
                                    ->end()
325 54
                                ->end()
326 54
                            ->end()
327 54
                        ->end()
328 54
                    ->end()
329 54
                ->end()
330 54
            ->end();
331 54
    }
332
333 54
    private function addVersioningSection(ArrayNodeDefinition $rootNode)
334
    {
335
        $rootNode
336 54
        ->children()
337 54
            ->arrayNode('versioning')
338 54
                ->canBeEnabled()
339 54
                ->children()
340 54
                    ->scalarNode('default_version')->defaultNull()->end()
341 54
                    ->arrayNode('resolvers')
342 54
                        ->addDefaultsIfNotSet()
343 54
                        ->children()
344 54
                            ->arrayNode('query')
345 54
                                ->canBeDisabled()
346 54
                                ->children()
347 54
                                    ->scalarNode('parameter_name')->defaultValue('version')->end()
348 54
                                ->end()
349 54
                            ->end()
350 54
                            ->arrayNode('custom_header')
351 54
                                ->canBeDisabled()
352 54
                                ->children()
353 54
                                    ->scalarNode('header_name')->defaultValue('X-Accept-Version')->end()
354 54
                                ->end()
355 54
                            ->end()
356 54
                            ->arrayNode('media_type')
357 54
                                ->canBeDisabled()
358 54
                                ->children()
359 54
                                    ->scalarNode('regex')->defaultValue('/(v|version)=(?P<version>[0-9\.]+)/')->end()
360 54
                                ->end()
361 54
                            ->end()
362 54
                        ->end()
363 54
                    ->end()
364 54
                    ->arrayNode('guessing_order')
365 54
                        ->defaultValue(['query', 'custom_header', 'media_type'])
366 54
                        ->validate()
367
                            ->ifTrue(function ($v) {
368 1
                                foreach ($v as $resolver) {
369 1
                                    if (!in_array($resolver, ['query', 'custom_header', 'media_type'])) {
370
                                        return true;
371
                                    }
372 1
                                }
373 54
                            })
374 54
                            ->thenInvalid('Versioning guessing order can only contain "query", "custom_header", "media_type".')
375 54
                        ->end()
376 54
                        ->prototype('scalar')->end()
377 54
                    ->end()
378 54
                ->end()
379 54
            ->end()
380 54
        ->end();
381 54
    }
382
383 54
    private function addExceptionSection(ArrayNodeDefinition $rootNode)
384
    {
385
        $rootNode
386 54
            ->children()
387 54
                ->arrayNode('exception')
388 54
                    ->fixXmlConfig('code', 'codes')
389 54
                    ->fixXmlConfig('message', 'messages')
390 54
                    ->addDefaultsIfNotSet()
391 54
                    ->canBeEnabled()
392 54
                    ->children()
393 54
                        ->scalarNode('exception_controller')->defaultNull()->end()
394 54
                        ->arrayNode('codes')
395 54
                            ->useAttributeAsKey('name')
396 54
                            ->validate()
397
                                ->ifTrue(function ($v) { return 0 !== count(array_filter($v, function ($i) { return !defined('Symfony\Component\HttpFoundation\Response::'.$i) && !is_int($i); })); })
398 54
                                ->thenInvalid('Invalid HTTP code in fos_rest.exception.codes, see Symfony\Component\HttpFoundation\Response for all valid codes.')
399 54
                            ->end()
400 54
                            ->prototype('scalar')->end()
401 54
                        ->end()
402 54
                        ->arrayNode('messages')
403 54
                            ->useAttributeAsKey('name')
404 54
                            ->prototype('boolean')->end()
405 54
                        ->end()
406 54
                        ->booleanNode('debug')
407 54
                            ->defaultValue($this->debug)
408 54
                        ->end()
409 54
                    ->end()
410 54
                ->end()
411 54
            ->end();
412 54
    }
413
}
414