Completed
Push — master ( 010fd7...92a758 )
by
unknown
05:33
created

DependencyInjection/FOSRestExtension.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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