Completed
Push — master ( 0046f1...53b167 )
by
unknown
16:10 queued 06:12
created

FOSRestExtension::loadException()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 3.054

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 18
cts 22
cp 0.8182
rs 9.488
c 0
b 0
f 0
cc 3
nc 3
nop 3
crap 3.054
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\FileLocator;
15
use Symfony\Component\DependencyInjection\Alias;
16
use Symfony\Component\DependencyInjection\ChildDefinition;
17
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
18
use Symfony\Component\DependencyInjection\ContainerBuilder;
19
use Symfony\Component\DependencyInjection\DefinitionDecorator;
20
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
21
use Symfony\Component\DependencyInjection\Reference;
22
use Symfony\Component\Form\AbstractType;
23
use Symfony\Component\Form\Extension\Core\Type\FormType;
24
use Symfony\Component\HttpFoundation\Response;
25
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
26
use Symfony\Component\Validator\Constraint;
27
28
class FOSRestExtension extends Extension
29 1
{
30
    /**
31 1
     * {@inheritdoc}
32
     */
33
    public function getConfiguration(array $config, ContainerBuilder $container)
34
    {
35
        return new Configuration($container->getParameter('kernel.debug'));
36
    }
37
38
    /**
39
     * Loads the services based on your application configuration.
40
     *
41
     * @param array            $configs
42
     * @param ContainerBuilder $container
43 55
     *
44
     * @throws \InvalidArgumentException
45 55
     * @throws \LogicException
46 55
     */
47
    public function load(array $configs, ContainerBuilder $container)
48 50
    {
49 50
        $configuration = new Configuration($container->getParameter('kernel.debug'));
50 50
        $config = $this->processConfiguration($configuration, $configs);
51 50
52 50
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
53
        $loader->load('view.xml');
54 50
        $loader->load('routing.xml');
55 50
        $loader->load('request.xml');
56 50
        $loader->load('serializer.xml');
57
58 50
        $container->getDefinition('fos_rest.routing.loader.controller')->replaceArgument(4, $config['routing_loader']['default_format']);
59 50
        $container->getDefinition('fos_rest.routing.loader.yaml_collection')->replaceArgument(4, $config['routing_loader']['default_format']);
60 50
        $container->getDefinition('fos_rest.routing.loader.xml_collection')->replaceArgument(4, $config['routing_loader']['default_format']);
61
62
        $container->getDefinition('fos_rest.routing.loader.yaml_collection')->replaceArgument(2, $config['routing_loader']['include_format']);
63 50
        $container->getDefinition('fos_rest.routing.loader.xml_collection')->replaceArgument(2, $config['routing_loader']['include_format']);
64 50
        $container->getDefinition('fos_rest.routing.loader.reader.action')->replaceArgument(3, $config['routing_loader']['include_format']);
65
        $container->getDefinition('fos_rest.routing.loader.reader.action')->replaceArgument(5, $config['routing_loader']['prefix_methods']);
66 50
67 50
        foreach ($config['service'] as $key => $service) {
68 50
            if ('validator' === $service && empty($config['body_converter']['validate'])) {
69 50
                continue;
70 50
            }
71
72 50
            if (null !== $service) {
73 50
                if ('view_handler' === $key) {
74 50
                    $container->setAlias('fos_rest.'.$key, new Alias($service, true));
75 50
                } else {
76
                    $container->setAlias('fos_rest.'.$key, $service);
77 50
                }
78 50
            }
79 50
        }
80 50
81 50
        $this->loadForm($config, $loader, $container);
82 50
        $this->loadException($config, $loader, $container);
83 50
        $this->loadBodyConverter($config, $loader, $container);
84
        $this->loadView($config, $loader, $container);
85
86 50
        $this->loadBodyListener($config, $loader, $container);
87 50
        $this->loadFormatListener($config, $loader, $container);
88
        $this->loadVersioning($config, $loader, $container);
89 50
        $this->loadParamFetcherListener($config, $loader, $container);
90
        $this->loadAllowedMethodsListener($config, $loader, $container);
91 50
        $this->loadAccessDeniedListener($config, $loader, $container);
92 1
        $this->loadZoneMatcherListener($config, $loader, $container);
93
94 1
        // Needs RequestBodyParamConverter and View Handler loaded.
95 1
        $this->loadSerializer($config, $container);
96
    }
97
98 1
    private function loadForm(array $config, XmlFileLoader $loader, ContainerBuilder $container)
99
    {
100
        if (!empty($config['disable_csrf_role'])) {
101 1
            $loader->load('forms.xml');
102
103 1
            $definition = $container->getDefinition('fos_rest.form.extension.csrf_disable');
104 50
            $definition->replaceArgument(1, $config['disable_csrf_role']);
105
106 50
            // BC for Symfony < 2.8: the extended_type attribute is used on higher versions
107
            if (!method_exists(AbstractType::class, 'getBlockPrefix')) {
108 50
                $definition->addTag('form.type_extension', ['alias' => 'form']);
109
            } else {
110
                $definition->addTag('form.type_extension', ['extended_type' => FormType::class]);
111
            }
112
        }
113
    }
114
115
    private function loadAccessDeniedListener(array $config, XmlFileLoader $loader, ContainerBuilder $container)
116
    {
117
        if ($config['access_denied_listener']['enabled'] && !empty($config['access_denied_listener']['formats'])) {
118
            $loader->load('access_denied_listener.xml');
119
120 50
            $service = $container->getDefinition('fos_rest.access_denied_listener');
121
122 50
            if (!empty($config['access_denied_listener']['service'])) {
123
                $service->clearTag('kernel.event_subscriber');
124 50
            }
125 2
126
            $service->replaceArgument(0, $config['access_denied_listener']['formats']);
127
            $service->replaceArgument(1, $config['unauthorized_challenge']);
128
        }
129
    }
130 2
131
    private function loadAllowedMethodsListener(array $config, XmlFileLoader $loader, ContainerBuilder $container)
132 2
    {
133 2
        if ($config['allowed_methods_listener']['enabled']) {
134 50
            if (!empty($config['allowed_methods_listener']['service'])) {
135
                $service = $container->getDefinition('fos_rest.allowed_methods_listener');
136 50
                $service->clearTag('kernel.event_listener');
137
            }
138 50
139 49
            $loader->load('allowed_methods_listener.xml');
140
141 49
            $container->getDefinition('fos_rest.allowed_methods_loader')->replaceArgument(1, $config['cache_dir']);
142
        }
143 49
    }
144
145
    private function loadBodyListener(array $config, XmlFileLoader $loader, ContainerBuilder $container)
146
    {
147 49
        if ($config['body_listener']['enabled']) {
148 49
            $loader->load('body_listener.xml');
149
150 49
            $service = $container->getDefinition('fos_rest.body_listener');
151
152 49
            if (!empty($config['body_listener']['service'])) {
153
                $service->clearTag('kernel.event_listener');
154 49
            }
155 3
156 3
            $service->replaceArgument(1, $config['body_listener']['throw_exception_on_unsupported_content_type']);
157 3
            $service->addMethodCall('setDefaultFormat', array($config['body_listener']['default_format']));
158 3
159 49
            $container->getDefinition('fos_rest.decoder_provider')->replaceArgument(1, $config['body_listener']['decoders']);
160 50
161
            if (class_exists(ServiceLocatorTagPass::class)) {
162 50
                $decoderServicesMap = array();
163
164 50
                foreach ($config['body_listener']['decoders'] as $id) {
165 6
                    $decoderServicesMap[$id] = new Reference($id);
166
                }
167 6
168
                $decodersServiceLocator = ServiceLocatorTagPass::register($container, $decoderServicesMap);
169
                $container->getDefinition('fos_rest.decoder_provider')->replaceArgument(0, $decodersServiceLocator);
170
            }
171
172 6
            $arrayNormalizer = $config['body_listener']['array_normalizer'];
173 6
174 6
            if (null !== $arrayNormalizer['service']) {
175 6
                $bodyListener = $container->getDefinition('fos_rest.body_listener');
176 6
                $bodyListener->addArgument(new Reference($arrayNormalizer['service']));
177 50
                $bodyListener->addArgument($arrayNormalizer['forms']);
178
            }
179 50
        }
180
    }
181 50
182 2
    private function loadFormatListener(array $config, XmlFileLoader $loader, ContainerBuilder $container)
183
    {
184 2 View Code Duplication
        if ($config['format_listener']['enabled'] && !empty($config['format_listener']['rules'])) {
185 2
            $loader->load('format_listener.xml');
186
187 2
            if (!empty($config['format_listener']['service'])) {
188 2
                $service = $container->getDefinition('fos_rest.format_listener');
189 2
                $service->clearTag('kernel.event_listener');
190 2
            }
191 2
192 2
            $container->setParameter(
193 2
                'fos_rest.format_listener.rules',
194 2
                $config['format_listener']['rules']
195 2
            );
196 2
        }
197 2
    }
198 2
199 2
    private function loadVersioning(array $config, XmlFileLoader $loader, ContainerBuilder $container)
200
    {
201 2
        if (!empty($config['versioning']['enabled'])) {
202 2
            $loader->load('versioning.xml');
203 2
204 2
            $versionListener = $container->getDefinition('fos_rest.versioning.listener');
205 2
            $versionListener->replaceArgument(1, $config['versioning']['default_version']);
206 2
207 2
            $resolvers = [];
208 50 View Code Duplication
            if ($config['versioning']['resolvers']['query']['enabled']) {
209
                $resolvers['query'] = $container->getDefinition('fos_rest.versioning.query_parameter_resolver');
210 50
                $resolvers['query']->replaceArgument(0, $config['versioning']['resolvers']['query']['parameter_name']);
211
            }
212 50 View Code Duplication
            if ($config['versioning']['resolvers']['custom_header']['enabled']) {
213 4
                $resolvers['custom_header'] = $container->getDefinition('fos_rest.versioning.header_resolver');
214
                $resolvers['custom_header']->replaceArgument(0, $config['versioning']['resolvers']['custom_header']['header_name']);
215 4
            }
216 View Code Duplication
            if ($config['versioning']['resolvers']['media_type']['enabled']) {
217
                $resolvers['media_type'] = $container->getDefinition('fos_rest.versioning.media_type_resolver');
218
                $resolvers['media_type']->replaceArgument(0, $config['versioning']['resolvers']['media_type']['regex']);
219
            }
220 4
221 1
            $chainResolver = $container->getDefinition('fos_rest.versioning.chain_resolver');
222 1
            foreach ($config['versioning']['guessing_order'] as $resolver) {
223 4
                if (isset($resolvers[$resolver])) {
224 50
                    $chainResolver->addMethodCall('addResolver', [$resolvers[$resolver]]);
225
                }
226 50
            }
227
        }
228 50
    }
229
230
    private function loadParamFetcherListener(array $config, XmlFileLoader $loader, ContainerBuilder $container)
231
    {
232 50
        if ($config['param_fetcher_listener']['enabled']) {
233 2
            if (!class_exists(Constraint::class)) {
234
                @trigger_error('Enabling the fos_rest.param_fetcher_listener option when the Symfony Validator component is not installed is deprecated since FOSRestBundle 2.6 and will throw an exception in 3.0. Disable the feature or install the symfony/validator package.', 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...
235 2
            }
236 2
237 2
            $loader->load('param_fetcher_listener.xml');
238 2
239
            if (!empty($config['param_fetcher_listener']['service'])) {
240 50
                $service = $container->getDefinition('fos_rest.param_fetcher_listener');
241 2
                $service->clearTag('kernel.event_listener');
242 2
            }
243 50
244
            if ($config['param_fetcher_listener']['force']) {
245 50
                $container->getDefinition('fos_rest.param_fetcher_listener')->replaceArgument(1, true);
246
            }
247 50
        }
248 1
    }
249 1
250
    private function loadBodyConverter(array $config, XmlFileLoader $loader, ContainerBuilder $container)
251 1
    {
252 1
        if (!$this->isConfigEnabled($container, $config['body_converter'])) {
253 1
            return;
254
        }
255 1
256
        $loader->load('request_body_param_converter.xml');
257 1
258 1
        if (!empty($config['body_converter']['validation_errors_argument'])) {
259 1
            $container->getDefinition('fos_rest.converter.request_body')->replaceArgument(4, $config['body_converter']['validation_errors_argument']);
260 1
        }
261
    }
262 50
263 2
    private function loadView(array $config, XmlFileLoader $loader, ContainerBuilder $container)
264
    {
265 2
        if (!empty($config['view']['jsonp_handler'])) {
266
            $childDefinitionClass = class_exists(ChildDefinition::class) ? ChildDefinition::class : DefinitionDecorator::class;
267
            $handler = new $childDefinitionClass($config['service']['view_handler']);
268
            $handler->setPublic(true);
269
270 2
            $jsonpHandler = new Reference('fos_rest.view_handler.jsonp');
271 2
            $handler->addMethodCall('registerHandler', ['jsonp', [$jsonpHandler, 'createResponse']]);
272
            $container->setDefinition('fos_rest.view_handler', $handler);
273 50
274 8
            $container->getDefinition('fos_rest.view_handler.jsonp')->replaceArgument(0, $config['view']['jsonp_handler']['callback_param']);
275 8
276
            if (empty($config['view']['mime_types']['jsonp'])) {
277 8
                $config['view']['mime_types']['jsonp'] = $config['view']['jsonp_handler']['mime_type'];
278
            }
279
        }
280
281 8 View Code Duplication
        if ($config['view']['mime_types']['enabled']) {
282 8
            $loader->load('mime_type_listener.xml');
283
284 50
            if (!empty($config['mime_type_listener']['service'])) {
285 50
                $service = $container->getDefinition('fos_rest.mime_type_listener');
286 50
                $service->clearTag('kernel.event_listener');
287 50
            }
288 50
289 50
            $container->getDefinition('fos_rest.mime_type_listener')->replaceArgument(0, $config['view']['mime_types']['formats']);
290 50
        }
291 50
292 50 View Code Duplication
        if ($config['view']['view_response_listener']['enabled']) {
293 50
            $loader->load('view_response_listener.xml');
294 50
            $service = $container->getDefinition('fos_rest.view_response_listener');
295
296 50
            if (!empty($config['view_response_listener']['service'])) {
297 50
                $service->clearTag('kernel.event_listener');
298 50
            }
299
300 50
            $service->replaceArgument(1, $config['view']['view_response_listener']['force']);
301 50
        }
302 50
303 50
        $formats = [];
304 50 View Code Duplication
        foreach ($config['view']['formats'] as $format => $enabled) {
305
            if ($enabled) {
306 50
                $formats[$format] = false;
307
            }
308
        }
309 View Code Duplication
        foreach ($config['view']['templating_formats'] as $format => $enabled) {
310 50
            if ($enabled) {
311 50
                $formats[$format] = true;
312 50
            }
313
        }
314 50
315
        $container->getDefinition('fos_rest.routing.loader.yaml_collection')->replaceArgument(3, $formats);
316
        $container->getDefinition('fos_rest.routing.loader.xml_collection')->replaceArgument(3, $formats);
317
        $container->getDefinition('fos_rest.routing.loader.reader.action')->replaceArgument(4, $formats);
318 50
319 50
        foreach ($config['view']['force_redirects'] as $format => $code) {
320 50
            if (true === $code) {
321 50
                $config['view']['force_redirects'][$format] = Response::HTTP_FOUND;
322 50
            }
323
        }
324 50
325 View Code Duplication
        if (!is_numeric($config['view']['failed_validation'])) {
326 50
            $config['view']['failed_validation'] = constant('\Symfony\Component\HttpFoundation\Response::'.$config['view']['failed_validation']);
327 14
        }
328
329 14
        $defaultViewHandler = $container->getDefinition('fos_rest.view_handler.default');
330
        $defaultViewHandler->replaceArgument(4, $formats);
331
        $defaultViewHandler->replaceArgument(5, $config['view']['failed_validation']);
332
333 View Code Duplication
        if (!is_numeric($config['view']['empty_content'])) {
334 14
            $config['view']['empty_content'] = constant('\Symfony\Component\HttpFoundation\Response::'.$config['view']['empty_content']);
335
        }
336 14
337 4
        $defaultViewHandler->replaceArgument(6, $config['view']['empty_content']);
338 4
        $defaultViewHandler->replaceArgument(7, $config['view']['serialize_null']);
339
        $defaultViewHandler->replaceArgument(8, $config['view']['force_redirects']);
340 14
        $defaultViewHandler->replaceArgument(9, $config['view']['default_engine']);
341 14
    }
342 14
343 14
    private function loadException(array $config, XmlFileLoader $loader, ContainerBuilder $container)
344
    {
345 14
        if ($config['exception']['enabled']) {
346 14
            $loader->load('exception_listener.xml');
347 14
348 14
            if (!empty($config['exception']['service'])) {
349 14
                $service = $container->getDefinition('fos_rest.exception_listener');
350 14
                $service->clearTag('kernel.event_subscriber');
351 14
            }
352 50
353
            $controller = $config['exception']['exception_controller'] ?? null;
354 50
355
            $container->getDefinition('fos_rest.exception_listener')->replaceArgument(0, $controller);
356 50
357 50
            $container->getDefinition('fos_rest.exception.codes_map')
358
                ->replaceArgument(0, $config['exception']['codes']);
359 50
            $container->getDefinition('fos_rest.exception.messages_map')
360 1
                ->replaceArgument(0, $config['exception']['messages']);
361
362
            $container->getDefinition('fos_rest.exception.controller')
363 1
                ->replaceArgument(2, $config['exception']['debug']);
364 1
            $container->getDefinition('fos_rest.serializer.exception_normalizer.jms')
365
                ->replaceArgument(1, $config['exception']['debug']);
366 50
            $container->getDefinition('fos_rest.serializer.exception_normalizer.symfony')
367 1
                ->replaceArgument(1, $config['exception']['debug']);
368
        }
369
    }
370 1
371 1
    private function loadSerializer(array $config, ContainerBuilder $container)
372
    {
373 50
        $bodyConverter = $container->hasDefinition('fos_rest.converter.request_body') ? $container->getDefinition('fos_rest.converter.request_body') : null;
374 50
        $viewHandler = $container->getDefinition('fos_rest.view_handler.default');
375
        $options = array();
376 50
377 View Code Duplication
        if (!empty($config['serializer']['version'])) {
378 50
            if ($bodyConverter) {
379 2
                $bodyConverter->replaceArgument(2, $config['serializer']['version']);
380 2
            }
381
            $options['exclusionStrategyVersion'] = $config['serializer']['version'];
382 2
        }
383 2
384 2 View Code Duplication
        if (!empty($config['serializer']['groups'])) {
385 2
            if ($bodyConverter) {
386 2
                $bodyConverter->replaceArgument(1, $config['serializer']['groups']);
387 2
            }
388 2
            $options['exclusionStrategyGroups'] = $config['serializer']['groups'];
389
        }
390 2
391 2
        $options['serializeNullStrategy'] = $config['serializer']['serialize_null'];
392 2
        $viewHandler->addArgument($options);
393 50
    }
394
395 2
    private function loadZoneMatcherListener(array $config, XmlFileLoader $loader, ContainerBuilder $container)
396
    {
397 2
        if (!empty($config['zone'])) {
398
            $loader->load('zone_matcher_listener.xml');
399
            $zoneMatcherListener = $container->getDefinition('fos_rest.zone_matcher_listener');
400
401 2
            foreach ($config['zone'] as $zone) {
402 2
                $matcher = $this->createZoneRequestMatcher($container,
403
                    $zone['path'],
404
                    $zone['host'],
405 2
                    $zone['methods'],
406 2
                    $zone['ips']
407 2
                );
408 2
409
                $zoneMatcherListener->addMethodCall('addRequestMatcher', array($matcher));
410
            }
411 2
        }
412 2
    }
413
414
    private function createZoneRequestMatcher(ContainerBuilder $container, $path = null, $host = null, $methods = array(), $ip = null)
415 2
    {
416
        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...
417
            $methods = array_map('strtoupper', (array) $methods);
418
        }
419
420
        $serialized = serialize(array($path, $host, $methods, $ip));
421
        $id = 'fos_rest.zone_request_matcher.'.md5($serialized).sha1($serialized);
422
423
        // only add arguments that are necessary
424
        $arguments = array($path, $host, $methods, $ip);
425
        while (count($arguments) > 0 && !end($arguments)) {
426
            array_pop($arguments);
427
        }
428
429
        $childDefinitionClass = class_exists(ChildDefinition::class) ? ChildDefinition::class : DefinitionDecorator::class;
430
        $container
431
            ->setDefinition($id, new $childDefinitionClass('fos_rest.zone_request_matcher'))
432
            ->setArguments($arguments)
433
        ;
434
435
        return new Reference($id);
436
    }
437
}
438