Completed
Pull Request — master (#2229)
by
unknown
02:50
created

FOSRestExtension::loadPaginationConverter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.2559

Importance

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