Completed
Pull Request — 2.x (#2228)
by
unknown
04:19
created

Configuration::addExceptionSection()   C

Complexity

Conditions 9
Paths 1

Size

Total Lines 104

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 81
CRAP Score 9.0001

Importance

Changes 0
Metric Value
dl 0
loc 104
ccs 81
cts 82
cp 0.9878
rs 6.4444
c 0
b 0
f 0
cc 9
nc 1
nop 1
crap 9.0001

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
    /**
35
     * Default debug mode value.
36
     *
37
     * @var bool
38
     */
39
    private $debug;
40
41 85
    public function __construct(bool $debug)
42
    {
43 85
        $this->debug = $debug;
44 85
    }
45
46 84
    public function getConfigTreeBuilder(): TreeBuilder
47
    {
48 84
        $treeBuilder = new TreeBuilder('fos_rest');
49
50 84
        if (method_exists($treeBuilder, 'getRootNode')) {
51 84
            $rootNode = $treeBuilder->getRootNode();
52
        } else {
53
            $rootNode = $treeBuilder->root('fos_rest');
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Config...der\TreeBuilder::root() has been deprecated with message: since Symfony 4.3, pass the root name to the constructor instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
54
        }
55
56
        $rootNode
57 84
            ->children()
58 84
                ->scalarNode('disable_csrf_role')->defaultNull()->end()
59 84
                ->arrayNode('access_denied_listener')
60 84
                    ->canBeEnabled()
61 84
                    ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
62 84
                    ->beforeNormalization()
63 View Code Duplication
                        ->ifArray()->then(function ($v) {
64
                            if (!empty($v) && empty($v['formats'])) {
65
                                unset($v['enabled']);
66
                                $v = ['enabled' => true, 'formats' => $v];
67
                            }
68
69
                            return $v;
70 84
                        })
71 84
                    ->end()
72 84
                    ->fixXmlConfig('format', 'formats')
73 84
                    ->children()
74 84
                        ->scalarNode('service')->defaultNull()->end()
75 84
                        ->arrayNode('formats')
76 84
                            ->useAttributeAsKey('name')
77 84
                            ->prototype('boolean')->end()
78 84
                        ->end()
79 84
                    ->end()
80 84
                ->end()
81 84
                ->scalarNode('unauthorized_challenge')->defaultNull()->end()
82 84
                ->arrayNode('param_fetcher_listener')
83 84
                    ->beforeNormalization()
84 84
                        ->ifString()
85 View Code Duplication
                        ->then(function ($v) {
86 1
                            return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
87 84
                        })
88 84
                    ->end()
89 84
                    ->canBeEnabled()
90 84
                    ->children()
91 84
                        ->booleanNode('force')->defaultFalse()->end()
92 84
                        ->scalarNode('service')->defaultNull()->end()
93 84
                    ->end()
94 84
                ->end()
95 84
                ->scalarNode('cache_dir')->cannotBeEmpty()->defaultValue('%kernel.cache_dir%/fos_rest')->end()
96 84
                ->arrayNode('allowed_methods_listener')
97 84
                    ->canBeEnabled()
98 84
                    ->children()
99 84
                        ->scalarNode('service')->defaultNull()->end()
100 84
                    ->end()
101 84
                ->end()
102 84
                ->arrayNode('routing_loader')
103 84
                    ->addDefaultsIfNotSet()
104 84
                    ->beforeNormalization()
105
                        ->ifTrue(function ($v) { return isset($v['enabled']) && false !== $v['enabled']; })
106
                        ->then(function ($v) {
107
                            @trigger_error('Enabling the route generation feature is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
108
109
                            return $v;
110 84
                        })
111 84
                    ->end()
112 84
                    ->beforeNormalization()
113
                        ->ifTrue(function ($v) { return is_bool($v); })
114
                        ->then(function ($v) {
115
                            return [
116 66
                                'enabled' => $v,
117
                            ];
118 84
                        })
119 84
                    ->end()
120 84
                    ->children()
121 84
                        ->booleanNode('enabled')
122
                            ->defaultValue(function () {
123 7
                                @trigger_error('Enabling the route generation feature is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
124
125 7
                                return true;
126 84
                            })
127 84
                        ->end()
128 84
                        ->scalarNode('default_format')->defaultNull()->end()
129 84
                        ->scalarNode('prefix_methods')->defaultTrue()->end()
130 84
                        ->scalarNode('include_format')->defaultTrue()->end()
131 84
                    ->end()
132 84
                ->end()
133 84
                ->arrayNode('body_converter')
134 84
                    ->canBeEnabled()
135 84
                    ->children()
136 84
                        ->scalarNode('validate')
137 84
                            ->defaultFalse()
138 84
                            ->beforeNormalization()
139 84
                                ->ifTrue()
140
                                ->then(function ($value) {
141 3
                                    if (!class_exists(OptionsResolver::class)) {
142
                                        throw new InvalidConfigurationException("'body_converter.validate: true' requires OptionsResolver component installation ( composer require symfony/options-resolver )");
143
                                    }
144
145 3
                                    return $value;
146 84
                                })
147 84
                            ->end()
148 84
                        ->end()
149 84
                        ->scalarNode('validation_errors_argument')->defaultValue('validationErrors')->end()
150 84
                    ->end()
151 84
                ->end()
152 84
                ->arrayNode('service')
153 84
                    ->addDefaultsIfNotSet()
154 84
                    ->children()
155 84
                        ->scalarNode('router')->defaultValue('router')->setDeprecated('The "%path%.%node%" configuration key has been deprecated in FOSRestBundle 2.8.')->end()
156 84
                        ->scalarNode('templating')
157 84
                            ->defaultValue('templating')
158 84
                            ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
159 84
                        ->end()
160 84
                        ->scalarNode('serializer')->defaultNull()->end()
161 84
                        ->scalarNode('view_handler')->defaultValue('fos_rest.view_handler.default')->end()
162 84
                        ->scalarNode('inflector')
163 84
                            ->defaultValue('fos_rest.inflector.doctrine')
164 84
                            ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
165 84
                        ->end()
166 84
                        ->scalarNode('validator')->defaultValue('validator')->end()
167 84
                    ->end()
168 84
                ->end()
169 84
                ->arrayNode('serializer')
170 84
                    ->addDefaultsIfNotSet()
171 84
                    ->children()
172 84
                        ->scalarNode('version')->defaultNull()->end()
173 84
                        ->arrayNode('groups')
174 84
                            ->prototype('scalar')->end()
175 84
                        ->end()
176 84
                        ->booleanNode('serialize_null')->defaultFalse()->end()
177 84
                    ->end()
178 84
                ->end()
179 84
                ->arrayNode('zone')
180 84
                    ->cannotBeOverwritten()
181 84
                    ->prototype('array')
182 84
                    ->fixXmlConfig('ip')
183 84
                    ->children()
184 84
                        ->scalarNode('path')
185 84
                            ->defaultNull()
186 84
                            ->info('use the urldecoded format')
187 84
                            ->example('^/path to resource/')
188 84
                        ->end()
189 84
                        ->scalarNode('host')->defaultNull()->end()
190 84
                        ->arrayNode('methods')
191
                            ->beforeNormalization()->ifString()->then(function ($v) {
192
                                return preg_split('/\s*,\s*/', $v);
193 84
                            })->end()
194 84
                            ->prototype('scalar')->end()
195 84
                        ->end()
196 84
                        ->arrayNode('ips')
197
                            ->beforeNormalization()->ifString()->then(function ($v) {
198 1
                                return array($v);
199 84
                            })->end()
200 84
                            ->prototype('scalar')->end()
201 84
                        ->end()
202 84
                    ->end()
203 84
                ->end()
204 84
            ->end()
205 84
        ->end();
206
207 84
        $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...
208 84
        $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...
209 84
        $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...
210 84
        $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...
211 84
        $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...
212
213 84
        return $treeBuilder;
214
    }
215
216 84
    private function addViewSection(ArrayNodeDefinition $rootNode)
217
    {
218
        $rootNode
219 84
            ->children()
220 84
                ->arrayNode('view')
221 84
                    ->fixXmlConfig('format', 'formats')
222 84
                    ->fixXmlConfig('mime_type', 'mime_types')
223 84
                    ->fixXmlConfig('templating_format', 'templating_formats')
224 84
                    ->fixXmlConfig('force_redirect', 'force_redirects')
225 84
                    ->addDefaultsIfNotSet()
226 84
                    ->children()
227 84
                        ->scalarNode('default_engine')
228 84
                            ->setDeprecated('The "%path%.%node%" option has been deprecated in FOSRestBundle 2.8.')
229 84
                            ->defaultValue('twig')
230 84
                        ->end()
231 84
                        ->arrayNode('force_redirects')
232 84
                            ->setDeprecated('The "%path%.%node%" option has been deprecated in FOSRestBundle 2.8.')
233 84
                            ->useAttributeAsKey('name')
234 84
                            ->defaultValue(['html' => true])
235 84
                            ->prototype('boolean')->end()
236 84
                        ->end()
237 84
                        ->arrayNode('mime_types')
238 84
                            ->canBeEnabled()
239 84
                            ->beforeNormalization()
240 View Code Duplication
                                ->ifArray()->then(function ($v) {
241 1
                                    if (!empty($v) && empty($v['formats'])) {
242 1
                                        unset($v['enabled']);
243 1
                                        $v = ['enabled' => true, 'formats' => $v];
244
                                    }
245
246 1
                                    return $v;
247 84
                                })
248 84
                            ->end()
249 84
                            ->fixXmlConfig('format', 'formats')
250 84
                            ->children()
251 84
                                ->scalarNode('service')->defaultNull()->end()
252 84
                                ->arrayNode('formats')
253 84
                                    ->useAttributeAsKey('name')
254 84
                                    ->prototype('array')
255 84
                                        ->beforeNormalization()
256 84
                                            ->ifString()
257
                                            ->then(function ($v) { return array($v); })
258 84
                                        ->end()
259 84
                                        ->prototype('scalar')->end()
260 84
                                    ->end()
261 84
                                ->end()
262 84
                            ->end()
263 84
                        ->end()
264 84
                        ->arrayNode('formats')
265 84
                            ->useAttributeAsKey('name')
266 84
                            ->defaultValue(['json' => true, 'xml' => true])
267 84
                            ->prototype('boolean')->end()
268 84
                        ->end()
269 84
                        ->arrayNode('templating_formats')
270 84
                            ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in FOSRestBundle 2.8.')
271 84
                            ->useAttributeAsKey('name')
272 84
                            ->defaultValue(['html' => true])
273 84
                            ->prototype('boolean')->end()
274 84
                        ->end()
275 84
                        ->arrayNode('view_response_listener')
276 84
                            ->beforeNormalization()
277 84
                                ->ifString()
278 View Code Duplication
                                ->then(function ($v) {
279 9
                                    return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
280 84
                                })
281 84
                            ->end()
282 84
                            ->canBeEnabled()
283 84
                            ->children()
284 84
                                ->booleanNode('force')->defaultFalse()->end()
285 84
                                ->scalarNode('service')->defaultNull()->end()
286 84
                            ->end()
287 84
                        ->end()
288 84
                        ->scalarNode('failed_validation')->defaultValue(Response::HTTP_BAD_REQUEST)->end()
289 84
                        ->scalarNode('empty_content')->defaultValue(Response::HTTP_NO_CONTENT)->end()
290 84
                        ->booleanNode('serialize_null')->defaultFalse()->end()
291 84
                        ->arrayNode('jsonp_handler')
292 84
                            ->canBeUnset()
293 84
                            ->children()
294 84
                                ->scalarNode('callback_param')->defaultValue('callback')->end()
295 84
                                ->scalarNode('mime_type')->defaultValue('application/javascript+jsonp')->end()
296 84
                            ->end()
297 84
                        ->end()
298 84
                    ->end()
299 84
                ->end()
300 84
            ->end();
301 84
    }
302
303 84
    private function addBodyListenerSection(ArrayNodeDefinition $rootNode)
304
    {
305 84
        $decodersDefaultValue = ['json' => 'fos_rest.decoder.json'];
306 84
        if (class_exists(XmlEncoder::class)) {
307 84
            $decodersDefaultValue['xml'] = 'fos_rest.decoder.xml';
308
        }
309
        $rootNode
310 84
            ->children()
311 84
                ->arrayNode('body_listener')
312 84
                    ->fixXmlConfig('decoder', 'decoders')
313 84
                    ->addDefaultsIfNotSet()
314 84
                    ->canBeUnset()
315 84
                    ->treatFalseLike(['enabled' => false])
316 84
                    ->treatTrueLike(['enabled' => true])
317 84
                    ->treatNullLike(['enabled' => true])
318 84
                    ->children()
319 84
                        ->booleanNode('enabled')
320
                            ->defaultValue(function () {
321 7
                                @trigger_error('The body_listener config has been enabled by default and will be disabled by default in FOSRestBundle 3.0. Please enable or disable it explicitly.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
322
323 7
                                return true;
324 84
                            })
325 84
                        ->end()
326 84
                        ->scalarNode('service')->defaultNull()->end()
327 84
                        ->scalarNode('default_format')->defaultNull()->end()
328 84
                        ->booleanNode('throw_exception_on_unsupported_content_type')
329 84
                            ->defaultFalse()
330 84
                        ->end()
331 84
                        ->arrayNode('decoders')
332 84
                            ->useAttributeAsKey('name')
333 84
                            ->defaultValue($decodersDefaultValue)
334 84
                            ->prototype('scalar')->end()
335 84
                        ->end()
336 84
                        ->arrayNode('array_normalizer')
337 84
                            ->addDefaultsIfNotSet()
338 84
                            ->beforeNormalization()
339
                                ->ifString()->then(function ($v) {
340 1
                                    return ['service' => $v];
341 84
                                })
342 84
                            ->end()
343 84
                            ->children()
344 84
                                ->scalarNode('service')->defaultNull()->end()
345 84
                                ->booleanNode('forms')->defaultFalse()->end()
346 84
                            ->end()
347 84
                        ->end()
348 84
                    ->end()
349 84
                ->end()
350 84
            ->end();
351 84
    }
352
353 84
    private function addFormatListenerSection(ArrayNodeDefinition $rootNode)
354
    {
355
        $rootNode
356 84
            ->children()
357 84
                ->arrayNode('format_listener')
358 84
                    ->fixXmlConfig('rule', 'rules')
359 84
                    ->addDefaultsIfNotSet()
360 84
                    ->canBeUnset()
361 84
                    ->beforeNormalization()
362
                        ->ifTrue(function ($v) {
363
                            // check if we got an assoc array in rules
364 9
                            return isset($v['rules'])
365 9
                                && is_array($v['rules'])
366 9
                                && array_keys($v['rules']) !== range(0, count($v['rules']) - 1);
367 84
                        })
368
                        ->then(function ($v) {
369 1
                            $v['rules'] = [$v['rules']];
370
371 1
                            return $v;
372 84
                        })
373 84
                    ->end()
374 84
                    ->canBeEnabled()
375 84
                    ->children()
376 84
                        ->scalarNode('service')->defaultNull()->end()
377 84
                        ->arrayNode('rules')
378 84
                            ->performNoDeepMerging()
379 84
                            ->prototype('array')
380 84
                                ->fixXmlConfig('priority', 'priorities')
381 84
                                ->fixXmlConfig('attribute', 'attributes')
382 84
                                ->children()
383 84
                                    ->scalarNode('path')->defaultNull()->info('URL path info')->end()
384 84
                                    ->scalarNode('host')->defaultNull()->info('URL host name')->end()
385 84
                                    ->variableNode('methods')->defaultNull()->info('Method for URL')->end()
386 84
                                    ->arrayNode('attributes')
387 84
                                        ->useAttributeAsKey('name')
388 84
                                        ->prototype('variable')->end()
389 84
                                    ->end()
390 84
                                    ->booleanNode('stop')->defaultFalse()->end()
391 84
                                    ->booleanNode('prefer_extension')->defaultTrue()->end()
392 84
                                    ->scalarNode('fallback_format')->defaultValue('html')->end()
393 84
                                    ->arrayNode('priorities')
394
                                        ->beforeNormalization()->ifString()->then(function ($v) {
395
                                            return preg_split('/\s*,\s*/', $v);
396 84
                                        })->end()
397 84
                                        ->prototype('scalar')->end()
398 84
                                    ->end()
399 84
                                ->end()
400 84
                            ->end()
401 84
                        ->end()
402 84
                    ->end()
403 84
                ->end()
404 84
            ->end();
405 84
    }
406
407 84
    private function addVersioningSection(ArrayNodeDefinition $rootNode)
408
    {
409
        $rootNode
410 84
        ->children()
411 84
            ->arrayNode('versioning')
412 84
                ->canBeEnabled()
413 84
                ->children()
414 84
                    ->scalarNode('default_version')->defaultNull()->end()
415 84
                    ->arrayNode('resolvers')
416 84
                        ->addDefaultsIfNotSet()
417 84
                        ->children()
418 84
                            ->arrayNode('query')
419 84
                                ->canBeDisabled()
420 84
                                ->children()
421 84
                                    ->scalarNode('parameter_name')->defaultValue('version')->end()
422 84
                                ->end()
423 84
                            ->end()
424 84
                            ->arrayNode('custom_header')
425 84
                                ->canBeDisabled()
426 84
                                ->children()
427 84
                                    ->scalarNode('header_name')->defaultValue('X-Accept-Version')->end()
428 84
                                ->end()
429 84
                            ->end()
430 84
                            ->arrayNode('media_type')
431 84
                                ->canBeDisabled()
432 84
                                ->children()
433 84
                                    ->scalarNode('regex')->defaultValue('/(v|version)=(?P<version>[0-9\.]+)/')->end()
434 84
                                ->end()
435 84
                            ->end()
436 84
                        ->end()
437 84
                    ->end()
438 84
                    ->arrayNode('guessing_order')
439 84
                        ->defaultValue(['query', 'custom_header', 'media_type'])
440 84
                        ->validate()
441
                            ->ifTrue(function ($v) {
442
                                foreach ($v as $resolver) {
443
                                    if (!in_array($resolver, ['query', 'custom_header', 'media_type'])) {
444
                                        return true;
445
                                    }
446
                                }
447 84
                            })
448 84
                            ->thenInvalid('Versioning guessing order can only contain "query", "custom_header", "media_type".')
449 84
                        ->end()
450 84
                        ->prototype('scalar')->end()
451 84
                    ->end()
452 84
                ->end()
453 84
            ->end()
454 84
        ->end();
455 84
    }
456
457 84
    private function addExceptionSection(ArrayNodeDefinition $rootNode)
458
    {
459
        $rootNode
460 84
            ->children()
461 84
                ->arrayNode('exception')
462 84
                    ->fixXmlConfig('code', 'codes')
463 84
                    ->fixXmlConfig('message', 'messages')
464 84
                    ->addDefaultsIfNotSet()
465 84
                    ->canBeEnabled()
466 84
                    ->validate()
467 84
                      ->always()
468
                      ->then(function ($v) {
469 68
                          if (!$v['enabled']) {
470
                            return $v;
471
                          }
472
473 68
                          if ($v['exception_listener']) {
474 11
                              @trigger_error('Enabling the "fos_rest.exception.exception_listener" option is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
475
                          }
476 68
                          if ($v['serialize_exceptions']) {
477 14
                              @trigger_error('Enabling the "fos_rest.exception.serialize_exceptions" option is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
478
                          }
479
480 68
                          return $v;
481 84
                      })
482 84
                    ->end()
483 84
                    ->children()
484 84
                        ->booleanNode('map_exception_codes')
485 84
                            ->defaultFalse()
486 84
                            ->info('Enables an event listener that maps exception codes to response status codes based on the map configured with the "fos_rest.exception.codes" option.')
487 84
                        ->end()
488 84
                        ->booleanNode('exception_listener')
489 84
                            ->defaultTrue()
490 84
                        ->end()
491 84
                        ->scalarNode('exception_controller')
492 84
                            ->defaultNull()
493 84
                            ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
494 84
                        ->end()
495 84
                        ->booleanNode('serialize_exceptions')
496 84
                            ->defaultTrue()
497 84
                        ->end()
498 84
                        ->enumNode('flatten_exception_format')
499 84
                            ->defaultValue('legacy')
500 84
                            ->values(['legacy', 'rfc7807'])
501 84
                        ->end()
502 84
                        ->scalarNode('service')
503 84
                            ->defaultNull()
504 84
                            ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
505 84
                        ->end()
506 84
                        ->booleanNode('serializer_error_renderer')->defaultValue(false)->end()
507 84
                        ->arrayNode('codes')
508 84
                            ->useAttributeAsKey('name')
509 84
                            ->beforeNormalization()
510 84
                                ->ifArray()
511
                                ->then(function (array $items) {
512 13
                                    foreach ($items as &$item) {
513 13
                                        if (is_int($item)) {
514 3
                                            continue;
515
                                        }
516
517 10
                                        if (!defined(sprintf('%s::%s', Response::class, $item))) {
518 9
                                            throw new InvalidConfigurationException(sprintf('Invalid HTTP code in fos_rest.exception.codes, see %s for all valid codes.', Response::class));
519
                                        }
520
521 1
                                        $item = constant(sprintf('%s::%s', Response::class, $item));
522
                                    }
523
524 4
                                    return $items;
525 84
                                })
526 84
                            ->end()
527 84
                            ->prototype('integer')->end()
528
529 84
                            ->validate()
530 84
                            ->ifArray()
531
                                ->then(function (array $items) {
532 4
                                    foreach ($items as $class => $code) {
533 4
                                        $this->testExceptionExists($class);
534
                                    }
535
536 3
                                    return $items;
537 84
                                })
538 84
                            ->end()
539 84
                        ->end()
540 84
                        ->arrayNode('messages')
541 84
                            ->useAttributeAsKey('name')
542 84
                            ->prototype('boolean')->end()
543 84
                            ->validate()
544 84
                                ->ifArray()
545
                                ->then(function (array $items) {
546 12
                                    foreach ($items as $class => $nomatter) {
547 12
                                        $this->testExceptionExists($class);
548
                                    }
549
550 11
                                    return $items;
551 84
                                })
552 84
                            ->end()
553 84
                        ->end()
554 84
                        ->booleanNode('debug')
555 84
                            ->defaultValue($this->debug)
556 84
                        ->end()
557 84
                    ->end()
558 84
                ->end()
559 84
            ->end();
560 84
    }
561
562 16
    private function testExceptionExists(string $throwable)
563
    {
564 16
        if (!is_subclass_of($throwable, \Throwable::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Throwable::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
565 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.', $throwable, \Throwable::class));
566
        }
567 14
    }
568
}
569