Completed
Push — master ( 957717...7a0390 )
by Christian
02:31 queued 11s
created

Configuration::addViewSection()   B

Complexity

Conditions 3
Paths 1

Size

Total Lines 85

Duplication

Lines 11
Ratio 12.94 %

Code Coverage

Tests 73
CRAP Score 3.0012

Importance

Changes 0
Metric Value
dl 11
loc 85
ccs 73
cts 77
cp 0.9481
rs 8.3272
c 0
b 0
f 0
cc 3
nc 1
nop 1
crap 3.0012

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Config\Definition\Exception\InvalidConfigurationException;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\OptionsResolver\OptionsResolver;
20
use Symfony\Component\Serializer\Encoder\XmlEncoder;
21
22
/**
23
 * This class contains the configuration information for the bundle.
24
 *
25
 * This information is solely responsible for how the different configuration
26
 * sections are normalized, and merged.
27
 *
28
 * @author Lukas Kahwe Smith <[email protected]>
29
 *
30
 * @internal
31
 */
32
final class Configuration implements ConfigurationInterface
33
{
34
    private $debug;
35
36 24
    public function __construct(bool $debug)
37
    {
38 24
        $this->debug = $debug;
39 24
    }
40
41 23
    public function getConfigTreeBuilder(): TreeBuilder
42
    {
43 23
        $treeBuilder = new TreeBuilder('fos_rest');
44
45 23
        $rootNode = $treeBuilder->getRootNode();
46
47
        $rootNode
48 23
            ->children()
49 23
                ->scalarNode('disable_csrf_role')->defaultNull()->end()
50 23
                ->arrayNode('access_denied_listener')
51 23
                    ->canBeEnabled()
52 23
                    ->beforeNormalization()
53 View Code Duplication
                        ->ifArray()->then(function ($v) {
54
                            if (!empty($v) && empty($v['formats'])) {
55
                                unset($v['enabled']);
56
                                $v = ['enabled' => true, 'formats' => $v];
57
                            }
58
59
                            return $v;
60 23
                        })
61 23
                    ->end()
62 23
                    ->fixXmlConfig('format', 'formats')
63 23
                    ->children()
64 23
                        ->scalarNode('service')->defaultNull()->end()
65 23
                        ->arrayNode('formats')
66 23
                            ->useAttributeAsKey('name')
67 23
                            ->prototype('boolean')->end()
68 23
                        ->end()
69 23
                    ->end()
70 23
                ->end()
71 23
                ->scalarNode('unauthorized_challenge')->defaultNull()->end()
72 23
                ->arrayNode('param_fetcher_listener')
73 23
                    ->beforeNormalization()
74 23
                        ->ifString()
75 View Code Duplication
                        ->then(function ($v) {
76
                            return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
77 23
                        })
78 23
                    ->end()
79 23
                    ->canBeEnabled()
80 23
                    ->children()
81 23
                        ->booleanNode('force')->defaultFalse()->end()
82 23
                        ->scalarNode('service')->defaultNull()->end()
83 23
                    ->end()
84 23
                ->end()
85 23
                ->scalarNode('cache_dir')->cannotBeEmpty()->defaultValue('%kernel.cache_dir%/fos_rest')->end()
86 23
                ->arrayNode('allowed_methods_listener')
87 23
                    ->canBeEnabled()
88 23
                    ->children()
89 23
                        ->scalarNode('service')->defaultNull()->end()
90 23
                    ->end()
91 23
                ->end()
92 23
                ->arrayNode('routing_loader')
93 23
                    ->addDefaultsIfNotSet()
94 23
                    ->children()
95 23
                        ->booleanNode('parse_controller_name')
96 23
                            ->defaultValue(false)
97 23
                        ->end()
98 23
                        ->scalarNode('default_format')->defaultNull()->end()
99 23
                        ->scalarNode('prefix_methods')->defaultTrue()->end()
100 23
                        ->scalarNode('include_format')->defaultTrue()->end()
101 23
                    ->end()
102 23
                ->end()
103 23
                ->arrayNode('body_converter')
104 23
                    ->canBeEnabled()
105 23
                    ->children()
106 23
                        ->scalarNode('validate')
107 23
                            ->defaultFalse()
108 23
                            ->beforeNormalization()
109 23
                                ->ifTrue()
110
                                ->then(function ($value) {
111
                                    if (!class_exists(OptionsResolver::class)) {
112
                                        throw new InvalidConfigurationException("'body_converter.validate: true' requires OptionsResolver component installation ( composer require symfony/options-resolver )");
113
                                    }
114
115
                                    return $value;
116 23
                                })
117 23
                            ->end()
118 23
                        ->end()
119 23
                        ->scalarNode('validation_errors_argument')->defaultValue('validationErrors')->end()
120 23
                    ->end()
121 23
                ->end()
122 23
                ->arrayNode('service')
123 23
                    ->addDefaultsIfNotSet()
124 23
                    ->children()
125 23
                        ->scalarNode('router')->defaultValue('router')->end()
126 23
                        ->scalarNode('templating')
127 23
                            ->defaultNull()
128 23
                            ->validate()
129 23
                                ->ifString()
130 23
                                ->thenInvalid('only null is supported')
131 23
                            ->end()
132 23
                        ->end()
133 23
                        ->scalarNode('serializer')->defaultNull()->end()
134 23
                        ->scalarNode('view_handler')->defaultValue('fos_rest.view_handler.default')->end()
135 23
                        ->scalarNode('inflector')->defaultValue('fos_rest.inflector.doctrine')->end()
136 23
                        ->scalarNode('validator')->defaultValue('validator')->end()
137 23
                    ->end()
138 23
                ->end()
139 23
                ->arrayNode('serializer')
140 23
                    ->addDefaultsIfNotSet()
141 23
                    ->children()
142 23
                        ->scalarNode('version')->defaultNull()->end()
143 23
                        ->arrayNode('groups')
144 23
                            ->prototype('scalar')->end()
145 23
                        ->end()
146 23
                        ->booleanNode('serialize_null')->defaultFalse()->end()
147 23
                    ->end()
148 23
                ->end()
149 23
                ->arrayNode('zone')
150 23
                    ->cannotBeOverwritten()
151 23
                    ->prototype('array')
152 23
                    ->fixXmlConfig('ip')
153 23
                    ->children()
154 23
                        ->scalarNode('path')
155 23
                            ->defaultNull()
156 23
                            ->info('use the urldecoded format')
157 23
                            ->example('^/path to resource/')
158 23
                        ->end()
159 23
                        ->scalarNode('host')->defaultNull()->end()
160 23
                        ->arrayNode('methods')
161
                            ->beforeNormalization()->ifString()->then(function ($v) {
162
                                return preg_split('/\s*,\s*/', $v);
163 23
                            })->end()
164 23
                            ->prototype('scalar')->end()
165 23
                        ->end()
166 23
                        ->arrayNode('ips')
167
                            ->beforeNormalization()->ifString()->then(function ($v) {
168
                                return array($v);
169 23
                            })->end()
170 23
                            ->prototype('scalar')->end()
171 23
                        ->end()
172 23
                    ->end()
173 23
                ->end()
174 23
            ->end()
175 23
        ->end();
176
177 23
        $this->addViewSection($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...
178 23
        $this->addExceptionSection($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...
179 23
        $this->addBodyListenerSection($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...
180 23
        $this->addFormatListenerSection($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...
181 23
        $this->addVersioningSection($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...
182
183 23
        return $treeBuilder;
184
    }
185
186 23
    private function addViewSection(ArrayNodeDefinition $rootNode): void
187
    {
188
        $rootNode
189 23
            ->children()
190 23
                ->arrayNode('view')
191 23
                    ->fixXmlConfig('format', 'formats')
192 23
                    ->fixXmlConfig('mime_type', 'mime_types')
193 23
                    ->fixXmlConfig('force_redirect', 'force_redirects')
194 23
                    ->addDefaultsIfNotSet()
195 23
                    ->children()
196 23
                        ->scalarNode('default_engine')
197 23
                            ->defaultNull()
198 23
                            ->validate()
199 23
                                ->ifString()
200 23
                                ->thenInvalid('only null is supported')
201 23
                            ->end()
202 23
                        ->end()
203 23
                        ->arrayNode('force_redirects')
204 23
                            ->useAttributeAsKey('name')
205 23
                            ->defaultValue([])
206 23
                            ->validate()
207
                                ->ifTrue(function ($v) { return [] !== $v; })
208 23
                                ->thenInvalid('only the empty array is supported')
209 23
                            ->end()
210 23
                            ->prototype('boolean')->end()
211 23
                        ->end()
212 23
                        ->arrayNode('mime_types')
213 23
                            ->canBeEnabled()
214 23
                            ->beforeNormalization()
215 View Code Duplication
                                ->ifArray()->then(function ($v) {
216
                                    if (!empty($v) && empty($v['formats'])) {
217
                                        unset($v['enabled']);
218
                                        $v = ['enabled' => true, 'formats' => $v];
219
                                    }
220
221
                                    return $v;
222 23
                                })
223 23
                            ->end()
224 23
                            ->fixXmlConfig('format', 'formats')
225 23
                            ->children()
226 23
                                ->scalarNode('service')->defaultNull()->end()
227 23
                                ->arrayNode('formats')
228 23
                                    ->useAttributeAsKey('name')
229 23
                                    ->prototype('array')
230 23
                                        ->beforeNormalization()
231 23
                                            ->ifString()
232
                                            ->then(function ($v) { return array($v); })
233 23
                                        ->end()
234 23
                                        ->prototype('scalar')->end()
235 23
                                    ->end()
236 23
                                ->end()
237 23
                            ->end()
238 23
                        ->end()
239 23
                        ->arrayNode('formats')
240 23
                            ->useAttributeAsKey('name')
241 23
                            ->defaultValue(['json' => true, 'xml' => true])
242 23
                            ->prototype('boolean')->end()
243 23
                        ->end()
244 23
                        ->arrayNode('view_response_listener')
245 23
                            ->beforeNormalization()
246 23
                                ->ifString()
247 View Code Duplication
                                ->then(function ($v) {
248 1
                                    return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
249 23
                                })
250 23
                            ->end()
251 23
                            ->canBeEnabled()
252 23
                            ->children()
253 23
                                ->booleanNode('force')->defaultFalse()->end()
254 23
                                ->scalarNode('service')->defaultNull()->end()
255 23
                            ->end()
256 23
                        ->end()
257 23
                        ->scalarNode('failed_validation')->defaultValue(Response::HTTP_BAD_REQUEST)->end()
258 23
                        ->scalarNode('empty_content')->defaultValue(Response::HTTP_NO_CONTENT)->end()
259 23
                        ->booleanNode('serialize_null')->defaultFalse()->end()
260 23
                        ->arrayNode('jsonp_handler')
261 23
                            ->canBeUnset()
262 23
                            ->children()
263 23
                                ->scalarNode('callback_param')->defaultValue('callback')->end()
264 23
                                ->scalarNode('mime_type')->defaultValue('application/javascript+jsonp')->end()
265 23
                            ->end()
266 23
                        ->end()
267 23
                    ->end()
268 23
                ->end()
269 23
            ->end();
270 23
    }
271
272 23
    private function addBodyListenerSection(ArrayNodeDefinition $rootNode): void
273
    {
274 23
        $decodersDefaultValue = ['json' => 'fos_rest.decoder.json'];
275 23
        if (class_exists(XmlEncoder::class)) {
276 23
            $decodersDefaultValue['xml'] = 'fos_rest.decoder.xml';
277
        }
278
        $rootNode
279 23
            ->children()
280 23
                ->arrayNode('body_listener')
281 23
                    ->fixXmlConfig('decoder', 'decoders')
282 23
                    ->addDefaultsIfNotSet()
283 23
                    ->canBeUnset()
284 23
                    ->canBeDisabled()
285 23
                    ->children()
286 23
                        ->scalarNode('service')->defaultNull()->end()
287 23
                        ->scalarNode('default_format')->defaultNull()->end()
288 23
                        ->booleanNode('throw_exception_on_unsupported_content_type')
289 23
                            ->defaultFalse()
290 23
                        ->end()
291 23
                        ->arrayNode('decoders')
292 23
                            ->useAttributeAsKey('name')
293 23
                            ->defaultValue($decodersDefaultValue)
294 23
                            ->prototype('scalar')->end()
295 23
                        ->end()
296 23
                        ->arrayNode('array_normalizer')
297 23
                            ->addDefaultsIfNotSet()
298 23
                            ->beforeNormalization()
299
                                ->ifString()->then(function ($v) {
300
                                    return ['service' => $v];
301 23
                                })
302 23
                            ->end()
303 23
                            ->children()
304 23
                                ->scalarNode('service')->defaultNull()->end()
305 23
                                ->booleanNode('forms')->defaultFalse()->end()
306 23
                            ->end()
307 23
                        ->end()
308 23
                    ->end()
309 23
                ->end()
310 23
            ->end();
311 23
    }
312
313 23
    private function addFormatListenerSection(ArrayNodeDefinition $rootNode): void
314
    {
315
        $rootNode
316 23
            ->children()
317 23
                ->arrayNode('format_listener')
318 23
                    ->fixXmlConfig('rule', 'rules')
319 23
                    ->addDefaultsIfNotSet()
320 23
                    ->canBeUnset()
321 23
                    ->beforeNormalization()
322
                        ->ifTrue(function ($v) {
323
                            // check if we got an assoc array in rules
324 3
                            return isset($v['rules'])
325 3
                                && is_array($v['rules'])
326 3
                                && array_keys($v['rules']) !== range(0, count($v['rules']) - 1);
327 23
                        })
328
                        ->then(function ($v) {
329
                            $v['rules'] = [$v['rules']];
330
331
                            return $v;
332 23
                        })
333 23
                    ->end()
334 23
                    ->canBeEnabled()
335 23
                    ->children()
336 23
                        ->scalarNode('service')->defaultNull()->end()
337 23
                        ->arrayNode('rules')
338 23
                            ->performNoDeepMerging()
339 23
                            ->prototype('array')
340 23
                                ->fixXmlConfig('priority', 'priorities')
341 23
                                ->fixXmlConfig('attribute', 'attributes')
342 23
                                ->children()
343 23
                                    ->scalarNode('path')->defaultNull()->info('URL path info')->end()
344 23
                                    ->scalarNode('host')->defaultNull()->info('URL host name')->end()
345 23
                                    ->variableNode('methods')->defaultNull()->info('Method for URL')->end()
346 23
                                    ->arrayNode('attributes')
347 23
                                        ->useAttributeAsKey('name')
348 23
                                        ->prototype('variable')->end()
349 23
                                    ->end()
350 23
                                    ->booleanNode('stop')->defaultFalse()->end()
351 23
                                    ->booleanNode('prefer_extension')->defaultTrue()->end()
352 23
                                    ->scalarNode('fallback_format')->defaultValue('html')->end()
353 23
                                    ->arrayNode('priorities')
354
                                        ->beforeNormalization()->ifString()->then(function ($v) {
355
                                            return preg_split('/\s*,\s*/', $v);
356 23
                                        })->end()
357 23
                                        ->prototype('scalar')->end()
358 23
                                    ->end()
359 23
                                ->end()
360 23
                            ->end()
361 23
                        ->end()
362 23
                    ->end()
363 23
                ->end()
364 23
            ->end();
365 23
    }
366
367 23
    private function addVersioningSection(ArrayNodeDefinition $rootNode): void
368
    {
369
        $rootNode
370 23
        ->children()
371 23
            ->arrayNode('versioning')
372 23
                ->canBeEnabled()
373 23
                ->children()
374 23
                    ->scalarNode('default_version')->defaultNull()->end()
375 23
                    ->arrayNode('resolvers')
376 23
                        ->addDefaultsIfNotSet()
377 23
                        ->children()
378 23
                            ->arrayNode('query')
379 23
                                ->canBeDisabled()
380 23
                                ->children()
381 23
                                    ->scalarNode('parameter_name')->defaultValue('version')->end()
382 23
                                ->end()
383 23
                            ->end()
384 23
                            ->arrayNode('custom_header')
385 23
                                ->canBeDisabled()
386 23
                                ->children()
387 23
                                    ->scalarNode('header_name')->defaultValue('X-Accept-Version')->end()
388 23
                                ->end()
389 23
                            ->end()
390 23
                            ->arrayNode('media_type')
391 23
                                ->canBeDisabled()
392 23
                                ->children()
393 23
                                    ->scalarNode('regex')->defaultValue('/(v|version)=(?P<version>[0-9\.]+)/')->end()
394 23
                                ->end()
395 23
                            ->end()
396 23
                        ->end()
397 23
                    ->end()
398 23
                    ->arrayNode('guessing_order')
399 23
                        ->defaultValue(['query', 'custom_header', 'media_type'])
400 23
                        ->validate()
401
                            ->ifTrue(function ($v) {
402
                                foreach ($v as $resolver) {
403
                                    if (!in_array($resolver, ['query', 'custom_header', 'media_type'])) {
404
                                        return true;
405
                                    }
406
                                }
407 23
                            })
408 23
                            ->thenInvalid('Versioning guessing order can only contain "query", "custom_header", "media_type".')
409 23
                        ->end()
410 23
                        ->prototype('scalar')->end()
411 23
                    ->end()
412 23
                ->end()
413 23
            ->end()
414 23
        ->end();
415 23
    }
416
417 23
    private function addExceptionSection(ArrayNodeDefinition $rootNode): void
418
    {
419
        $rootNode
420 23
            ->children()
421 23
                ->arrayNode('exception')
422 23
                    ->fixXmlConfig('code', 'codes')
423 23
                    ->fixXmlConfig('message', 'messages')
424 23
                    ->addDefaultsIfNotSet()
425 23
                    ->canBeEnabled()
426 23
                    ->children()
427 23
                        ->scalarNode('exception_controller')->defaultValue('fos_rest.exception.controller::showAction')->end()
428 23
                        ->scalarNode('service')->defaultNull()->end()
429 23
                        ->arrayNode('codes')
430 23
                            ->useAttributeAsKey('name')
431 23
                            ->beforeNormalization()
432 23
                                ->ifArray()
433
                                ->then(function (array $items) {
434 12
                                    foreach ($items as &$item) {
435 12
                                        if (is_int($item)) {
436 2
                                            continue;
437
                                        }
438
439 10
                                        if (!defined(sprintf('%s::%s', Response::class, $item))) {
440 9
                                            throw new InvalidConfigurationException(sprintf('Invalid HTTP code in fos_rest.exception.codes, see %s for all valid codes.', Response::class));
441
                                        }
442
443 1
                                        $item = constant(sprintf('%s::%s', Response::class, $item));
444
                                    }
445
446 3
                                    return $items;
447 23
                                })
448 23
                            ->end()
449 23
                            ->prototype('integer')->end()
450
451 23
                            ->validate()
452 23
                            ->ifArray()
453
                                ->then(function (array $items) {
454 3
                                    foreach ($items as $class => $code) {
455 3
                                        $this->testExceptionExists($class);
456
                                    }
457
458 2
                                    return $items;
459 23
                                })
460 23
                            ->end()
461 23
                        ->end()
462 23
                        ->arrayNode('messages')
463 23
                            ->useAttributeAsKey('name')
464 23
                            ->prototype('boolean')->end()
465 23
                            ->validate()
466 23
                                ->ifArray()
467
                                ->then(function (array $items) {
468 1
                                    foreach ($items as $class => $nomatter) {
469 1
                                        $this->testExceptionExists($class);
470
                                    }
471
472
                                    return $items;
473 23
                                })
474 23
                            ->end()
475 23
                        ->end()
476 23
                        ->booleanNode('debug')
477 23
                            ->defaultValue($this->debug)
478 23
                        ->end()
479 23
                    ->end()
480 23
                ->end()
481 23
            ->end();
482 23
    }
483
484 4
    private function testExceptionExists(string $exception): void
485
    {
486 4
        if (!is_subclass_of($exception, \Exception::class) && !is_a($exception, \Exception::class, true)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Exception::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
487 2
            throw new InvalidConfigurationException(sprintf('FOSRestBundle exception mapper: Could not load class "%s" or the class does not extend from "%s". Most probably this is a configuration problem.', $exception, \Exception::class));
488
        }
489 2
    }
490
}
491