Completed
Push — master ( fb3acb...928588 )
by Christian
02:51 queued 10s
created

FOSRestExtension::loadException()   B

Complexity

Conditions 7
Paths 21

Size

Total Lines 69

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 41
CRAP Score 7.1518

Importance

Changes 0
Metric Value
dl 0
loc 69
ccs 41
cts 48
cp 0.8542
rs 7.743
c 0
b 0
f 0
cc 7
nc 21
nop 3
crap 7.1518

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 FOS\RestBundle\EventListener\ResponseStatusCodeListener;
15
use FOS\RestBundle\View\ViewHandler;
16
use Symfony\Component\Config\FileLocator;
17
use Symfony\Component\DependencyInjection\Alias;
18
use Symfony\Component\DependencyInjection\ChildDefinition;
19
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
20
use Symfony\Component\DependencyInjection\ContainerBuilder;
21
use Symfony\Component\DependencyInjection\ContainerInterface;
22
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
23
use Symfony\Component\DependencyInjection\Reference;
24
use Symfony\Component\Form\Extension\Core\Type\FormType;
25
use Symfony\Component\HttpFoundation\Response;
26
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
27
use Symfony\Component\HttpKernel\EventListener\ErrorListener;
28
use Symfony\Component\HttpKernel\EventListener\ExceptionListener as LegacyHttpKernelExceptionListener;
29
use Symfony\Component\Validator\Constraint;
30
31
/**
32
 * @internal
33
 */
34
class FOSRestExtension extends Extension
35
{
36
    /**
37
     * {@inheritdoc}
38
     */
39 17
    public function getConfiguration(array $config, ContainerBuilder $container): Configuration
40
    {
41 17
        return new Configuration($container->getParameter('kernel.debug'));
42
    }
43
44 58
    public function load(array $configs, ContainerBuilder $container): void
45
    {
46 58
        $configuration = new Configuration($container->getParameter('kernel.debug'));
47 58
        $config = $this->processConfiguration($configuration, $configs);
48
49 53
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
50 53
        $loader->load('view.xml');
51 53
        $loader->load('request.xml');
52 53
        $loader->load('serializer.xml');
53
54 53
        foreach ($config['service'] as $key => $service) {
55 53
            if ('validator' === $service && empty($config['body_converter']['validate'])) {
56 52
                continue;
57
            }
58
59 53
            if (null !== $service) {
60 53
                if ('view_handler' === $key) {
61 53
                    $container->setAlias('fos_rest.'.$key, new Alias($service, true));
62
                } else {
63 53
                    $container->setAlias('fos_rest.'.$key, $service);
64
                }
65
            }
66
        }
67
68 53
        $this->loadForm($config, $loader, $container);
69 53
        $this->loadException($config, $loader, $container);
70 53
        $this->loadBodyConverter($config, $loader, $container);
71 53
        $this->loadView($config, $loader, $container);
72
73 53
        $this->loadBodyListener($config, $loader, $container);
74 53
        $this->loadFormatListener($config, $loader, $container);
75 53
        $this->loadVersioning($config, $loader, $container);
76 53
        $this->loadParamFetcherListener($config, $loader, $container);
77 53
        $this->loadAllowedMethodsListener($config, $loader, $container);
78 53
        $this->loadAccessDeniedListener($config, $loader, $container);
79 53
        $this->loadZoneMatcherListener($config, $loader, $container);
80
81
        // Needs RequestBodyParamConverter and View Handler loaded.
82 53
        $this->loadSerializer($config, $container);
83 53
    }
84
85 53
    private function loadForm(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
86
    {
87 53
        if (!empty($config['disable_csrf_role'])) {
88
            $loader->load('forms.xml');
89
90
            $definition = $container->getDefinition('fos_rest.form.extension.csrf_disable');
91
            $definition->replaceArgument(1, $config['disable_csrf_role']);
92
            $definition->addTag('form.type_extension', ['extended_type' => FormType::class]);
93
        }
94 53
    }
95
96 53
    private function loadAccessDeniedListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
97
    {
98 53
        if ($config['access_denied_listener']['enabled'] && !empty($config['access_denied_listener']['formats'])) {
99
            $loader->load('access_denied_listener.xml');
100
101
            $service = $container->getDefinition('fos_rest.access_denied_listener');
102
103
            if (!empty($config['access_denied_listener']['service'])) {
104
                $service->clearTag('kernel.event_subscriber');
105
            }
106
107
            $service->replaceArgument(0, $config['access_denied_listener']['formats']);
108
            $service->replaceArgument(1, $config['unauthorized_challenge']);
109
        }
110 53
    }
111
112 53
    private function loadAllowedMethodsListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
113
    {
114 53
        if ($config['allowed_methods_listener']['enabled']) {
115 1
            if (!empty($config['allowed_methods_listener']['service'])) {
116
                $service = $container->getDefinition('fos_rest.allowed_methods_listener');
117
                $service->clearTag('kernel.event_listener');
118
            }
119
120 1
            $loader->load('allowed_methods_listener.xml');
121
122 1
            $container->getDefinition('fos_rest.allowed_methods_loader')->replaceArgument(1, $config['cache_dir']);
123
        }
124 53
    }
125
126 53
    private function loadBodyListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
127
    {
128 53
        if ($config['body_listener']['enabled']) {
129 52
            $loader->load('body_listener.xml');
130
131 52
            $service = $container->getDefinition('fos_rest.body_listener');
132
133 52
            if (!empty($config['body_listener']['service'])) {
134
                $service->clearTag('kernel.event_listener');
135
            }
136
137 52
            $service->replaceArgument(1, $config['body_listener']['throw_exception_on_unsupported_content_type']);
138 52
            $service->addMethodCall('setDefaultFormat', array($config['body_listener']['default_format']));
139
140 52
            $container->getDefinition('fos_rest.decoder_provider')->replaceArgument(1, $config['body_listener']['decoders']);
141
142 52
            $decoderServicesMap = array();
143
144 52
            foreach ($config['body_listener']['decoders'] as $id) {
145 52
                $decoderServicesMap[$id] = new Reference($id);
146
            }
147
148 52
            $decodersServiceLocator = ServiceLocatorTagPass::register($container, $decoderServicesMap);
149 52
            $container->getDefinition('fos_rest.decoder_provider')->replaceArgument(0, $decodersServiceLocator);
150
151 52
            $arrayNormalizer = $config['body_listener']['array_normalizer'];
152
153 52
            if (null !== $arrayNormalizer['service']) {
154 3
                $bodyListener = $container->getDefinition('fos_rest.body_listener');
155 3
                $bodyListener->addArgument(new Reference($arrayNormalizer['service']));
156 3
                $bodyListener->addArgument($arrayNormalizer['forms']);
157
            }
158
        }
159 53
    }
160
161 53
    private function loadFormatListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
162
    {
163 53
        if ($config['format_listener']['enabled'] && !empty($config['format_listener']['rules'])) {
164 3
            $loader->load('format_listener.xml');
165
166 3
            if (!empty($config['format_listener']['service'])) {
167
                $service = $container->getDefinition('fos_rest.format_listener');
168
                $service->clearTag('kernel.event_listener');
169
            }
170
171 3
            $container->setParameter(
172 3
                'fos_rest.format_listener.rules',
173 3
                $config['format_listener']['rules']
174
            );
175
        }
176 53
    }
177
178 53
    private function loadVersioning(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
179
    {
180 53
        if (!empty($config['versioning']['enabled'])) {
181
            $loader->load('versioning.xml');
182
183
            $versionListener = $container->getDefinition('fos_rest.versioning.listener');
184
            $versionListener->replaceArgument(1, $config['versioning']['default_version']);
185
186
            $resolvers = [];
187
            if ($config['versioning']['resolvers']['query']['enabled']) {
188
                $resolvers['query'] = $container->getDefinition('fos_rest.versioning.query_parameter_resolver');
189
                $resolvers['query']->replaceArgument(0, $config['versioning']['resolvers']['query']['parameter_name']);
190
            }
191
            if ($config['versioning']['resolvers']['custom_header']['enabled']) {
192
                $resolvers['custom_header'] = $container->getDefinition('fos_rest.versioning.header_resolver');
193
                $resolvers['custom_header']->replaceArgument(0, $config['versioning']['resolvers']['custom_header']['header_name']);
194
            }
195
            if ($config['versioning']['resolvers']['media_type']['enabled']) {
196
                $resolvers['media_type'] = $container->getDefinition('fos_rest.versioning.media_type_resolver');
197
                $resolvers['media_type']->replaceArgument(0, $config['versioning']['resolvers']['media_type']['regex']);
198
            }
199
200
            $chainResolver = $container->getDefinition('fos_rest.versioning.chain_resolver');
201
            foreach ($config['versioning']['guessing_order'] as $resolver) {
202
                if (isset($resolvers[$resolver])) {
203
                    $chainResolver->addMethodCall('addResolver', [$resolvers[$resolver]]);
204
                }
205
            }
206
        }
207 53
    }
208
209 53
    private function loadParamFetcherListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
210
    {
211 53
        if ($config['param_fetcher_listener']['enabled']) {
212 3
            if (!class_exists(Constraint::class)) {
213
                throw new \LogicException('Enabling the fos_rest.param_fetcher_listener option when the Symfony Validator component is not installed is not supported. Try installing the symfony/validator package.');
214
            }
215
216 3
            $loader->load('param_fetcher_listener.xml');
217
218 3
            if (!empty($config['param_fetcher_listener']['service'])) {
219
                $service = $container->getDefinition('fos_rest.param_fetcher_listener');
220
                $service->clearTag('kernel.event_listener');
221
            }
222
223 3
            if ($config['param_fetcher_listener']['force']) {
224 1
                $container->getDefinition('fos_rest.param_fetcher_listener')->replaceArgument(1, true);
225
            }
226
        }
227 53
    }
228
229 53
    private function loadBodyConverter(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
230
    {
231 53
        if (!$this->isConfigEnabled($container, $config['body_converter'])) {
232 49
            return;
233
        }
234
235 4
        $loader->load('request_body_param_converter.xml');
236
237 4
        if (!empty($config['body_converter']['validation_errors_argument'])) {
238 4
            $container->getDefinition('fos_rest.converter.request_body')->replaceArgument(4, $config['body_converter']['validation_errors_argument']);
239
        }
240 4
    }
241
242 53
    private function loadView(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
243
    {
244 53
        if (!empty($config['view']['jsonp_handler'])) {
245 1
            $handler = new ChildDefinition($config['service']['view_handler']);
246 1
            $handler->setPublic(true);
247
248 1
            $jsonpHandler = new Reference('fos_rest.view_handler.jsonp');
249 1
            $handler->addMethodCall('registerHandler', ['jsonp', [$jsonpHandler, 'createResponse']]);
250 1
            $container->setDefinition('fos_rest.view_handler', $handler);
251
252 1
            $container->getDefinition('fos_rest.view_handler.jsonp')->replaceArgument(0, $config['view']['jsonp_handler']['callback_param']);
253
254 1
            if (empty($config['view']['mime_types']['jsonp'])) {
255 1
                $config['view']['mime_types']['jsonp'] = $config['view']['jsonp_handler']['mime_type'];
256
            }
257
        }
258
259 53
        if ($config['view']['mime_types']['enabled']) {
260 1
            $loader->load('mime_type_listener.xml');
261
262 1
            if (!empty($config['mime_type_listener']['service'])) {
263
                $service = $container->getDefinition('fos_rest.mime_type_listener');
264
                $service->clearTag('kernel.event_listener');
265
            }
266
267 1
            $container->getDefinition('fos_rest.mime_type_listener')->replaceArgument(0, $config['view']['mime_types']['formats']);
268
        }
269
270 53
        if ($config['view']['view_response_listener']['enabled']) {
271 7
            $loader->load('view_response_listener.xml');
272 7
            $service = $container->getDefinition('fos_rest.view_response_listener');
273
274 7
            if (!empty($config['view_response_listener']['service'])) {
275
                $service->clearTag('kernel.event_listener');
276
            }
277
278 7
            $service->replaceArgument(1, $config['view']['view_response_listener']['force']);
279
        }
280
281 53
        $formats = [];
282 53
        foreach ($config['view']['formats'] as $format => $enabled) {
283 53
            if ($enabled) {
284 53
                $formats[$format] = false;
285
            }
286
        }
287
288 53
        if (!is_numeric($config['view']['failed_validation'])) {
289
            $config['view']['failed_validation'] = constant(sprintf('%s::%s', Response::class, $config['view']['failed_validation']));
290
        }
291
292 53
        if (!is_numeric($config['view']['empty_content'])) {
293
            $config['view']['empty_content'] = constant(sprintf('%s::%s', Response::class, $config['view']['empty_content']));
294
        }
295
296 53
        $defaultViewHandler = $container->getDefinition('fos_rest.view_handler.default');
297 53
        $defaultViewHandler->setFactory([ViewHandler::class, 'create']);
298 53
        $defaultViewHandler->setArguments([
299 53
            new Reference('fos_rest.router'),
300 53
            new Reference('fos_rest.serializer'),
301 53
            new Reference('request_stack'),
302 53
            $formats,
303 53
            $config['view']['failed_validation'],
304 53
            $config['view']['empty_content'],
305 53
            $config['view']['serialize_null'],
306
        ]);
307 53
    }
308
309 53
    private function loadException(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
310
    {
311 53
        if ($config['exception']['enabled']) {
312 53
            $loader->load('exception_listener.xml');
313
314 53
            if ($config['exception']['map_exception_codes']) {
315 1
                $container->register('fos_rest.exception.response_status_code_listener', ResponseStatusCodeListener::class)
316 1
                    ->setArguments([
317 1
                        new Reference('fos_rest.exception.codes_map'),
318
                    ])
319 1
                    ->addTag('kernel.event_subscriber');
320
            }
321
322 53
            if ($config['exception']['exception_listener']) {
323 9
                if (!empty($config['exception']['service'])) {
324
                    $service = $container->getDefinition('fos_rest.exception_listener');
325
                    $service->clearTag('kernel.event_subscriber');
326
                }
327
328 9
                $controller = $config['exception']['exception_controller'] ?? null;
329
330 9
                if (class_exists(ErrorListener::class)) {
331 9
                    $container->register('fos_rest.error_listener', ErrorListener::class)
332 9
                        ->setArguments([
333 9
                            $controller,
334 9
                            new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE),
335 9
                            '%kernel.debug%',
336
                        ])
337 9
                        ->addTag('monolog.logger', ['channel' => 'request']);
338
                } else {
339
                    $container->register('fos_rest.error_listener', LegacyHttpKernelExceptionListener::class)
340
                        ->setArguments([
341
                            $controller,
342
                            new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE),
343
                        ])
344
                        ->addTag('monolog.logger', ['channel' => 'request']);
345
                }
346
347 9
                $container->getDefinition('fos_rest.exception.controller')
348 9
                    ->replaceArgument(2, $config['exception']['debug']);
349
            } else {
350 44
                $container->removeDefinition('fos_rest.exception_listener');
351
            }
352
353 53
            $container->getDefinition('fos_rest.exception.codes_map')
354 53
                ->replaceArgument(0, $config['exception']['codes']);
355 53
            $container->getDefinition('fos_rest.exception.messages_map')
356 53
                ->replaceArgument(0, $config['exception']['messages']);
357
358 53
            $container->getDefinition('fos_rest.serializer.flatten_exception_handler')
359 53
                ->replaceArgument(1, $config['exception']['debug']);
360 53
            $container->getDefinition('fos_rest.serializer.flatten_exception_handler')
361 53
                ->replaceArgument(2, 'rfc7807' === $config['exception']['flatten_exception_format']);
362 53
            $container->getDefinition('fos_rest.serializer.flatten_exception_normalizer')
363 53
                ->replaceArgument(1, $config['exception']['debug']);
364 53
            $container->getDefinition('fos_rest.serializer.flatten_exception_normalizer')
365 53
                ->replaceArgument(2, 'rfc7807' === $config['exception']['flatten_exception_format']);
366
367 53
            if ($config['exception']['serialize_exceptions']) {
368 11
                $container->getDefinition('fos_rest.serializer.exception_normalizer.jms')
369 11
                    ->replaceArgument(1, $config['exception']['debug']);
370 11
                $container->getDefinition('fos_rest.serializer.exception_normalizer.symfony')
371 11
                    ->replaceArgument(1, $config['exception']['debug']);
372
            } else {
373 42
                $container->removeDefinition('fos_rest.serializer.exception_normalizer.jms');
374 42
                $container->removeDefinition('fos_rest.serializer.exception_normalizer.symfony');
375
            }
376
        }
377 53
    }
378
379 53
    private function loadSerializer(array $config, ContainerBuilder $container): void
380
    {
381 53
        $bodyConverter = $container->hasDefinition('fos_rest.converter.request_body') ? $container->getDefinition('fos_rest.converter.request_body') : null;
382 53
        $viewHandler = $container->getDefinition('fos_rest.view_handler.default');
383 53
        $options = array();
384
385 53
        if (!empty($config['serializer']['version'])) {
386
            if ($bodyConverter) {
387
                $bodyConverter->replaceArgument(2, $config['serializer']['version']);
388
            }
389
            $options['exclusionStrategyVersion'] = $config['serializer']['version'];
390
        }
391
392 53
        if (!empty($config['serializer']['groups'])) {
393
            if ($bodyConverter) {
394
                $bodyConverter->replaceArgument(1, $config['serializer']['groups']);
395
            }
396
            $options['exclusionStrategyGroups'] = $config['serializer']['groups'];
397
        }
398
399 53
        $options['serializeNullStrategy'] = $config['serializer']['serialize_null'];
400 53
        $viewHandler->addArgument($options);
401 53
    }
402
403 53
    private function loadZoneMatcherListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
404
    {
405 53
        if (!empty($config['zone'])) {
406 1
            $loader->load('zone_matcher_listener.xml');
407 1
            $zoneMatcherListener = $container->getDefinition('fos_rest.zone_matcher_listener');
408
409 1
            foreach ($config['zone'] as $zone) {
410 1
                $matcher = $this->createZoneRequestMatcher(
411 1
                    $container,
412 1
                    $zone['path'],
413 1
                    $zone['host'],
414 1
                    $zone['methods'],
415 1
                    $zone['ips']
416
                );
417
418 1
                $zoneMatcherListener->addMethodCall('addRequestMatcher', array($matcher));
419
            }
420
        }
421 53
    }
422
423 1
    private function createZoneRequestMatcher(ContainerBuilder $container, ?string $path = null, ?string $host = null, array $methods = array(), array $ips = null): Reference
424
    {
425 1
        if ($methods) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $methods of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
426
            $methods = array_map('strtoupper', (array) $methods);
427
        }
428
429 1
        $serialized = serialize(array($path, $host, $methods, $ips));
430 1
        $id = 'fos_rest.zone_request_matcher.'.md5($serialized).sha1($serialized);
431
432
        // only add arguments that are necessary
433 1
        $arguments = array($path, $host, $methods, $ips);
434 1
        while (count($arguments) > 0 && !end($arguments)) {
435 1
            array_pop($arguments);
436
        }
437
438
        $container
439 1
            ->setDefinition($id, new ChildDefinition('fos_rest.zone_request_matcher'))
440 1
            ->setArguments($arguments)
441
        ;
442
443 1
        return new Reference($id);
444
    }
445
}
446