Completed
Push — master ( e4df22...3ec143 )
by David
04:03
created

FOSHttpCacheExtension::parseResponseMatcher()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 24
Code Lines 16

Duplication

Lines 12
Ratio 50 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 0
Metric Value
dl 12
loc 24
ccs 13
cts 13
cp 1
rs 8.5125
c 0
b 0
f 0
cc 5
eloc 16
nc 5
nop 2
crap 5
1
<?php
2
3
/*
4
 * This file is part of the FOSHttpCacheBundle 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\HttpCacheBundle\DependencyInjection;
13
14
use FOS\HttpCache\ProxyClient\HttpDispatcher;
15
use FOS\HttpCacheBundle\DependencyInjection\Compiler\HashGeneratorPass;
16
use FOS\HttpCacheBundle\Http\ResponseMatcher\ExpressionResponseMatcher;
17
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
18
use Symfony\Component\Config\FileLocator;
19
use Symfony\Component\DependencyInjection\ChildDefinition;
20
use Symfony\Component\DependencyInjection\ContainerBuilder;
21
use Symfony\Component\DependencyInjection\Definition;
22
use Symfony\Component\DependencyInjection\DefinitionDecorator;
23
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
24
use Symfony\Component\DependencyInjection\Reference;
25
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
26
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
27
28
/**
29
 * {@inheritdoc}
30
 */
31
class FOSHttpCacheExtension extends Extension
32
{
33
    /**
34
     * {@inheritdoc}
35
     */
36 26
    public function getConfiguration(array $config, ContainerBuilder $container)
37
    {
38 26
        return new Configuration($container->getParameter('kernel.debug'));
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44 26
    public function load(array $configs, ContainerBuilder $container)
45
    {
46 26
        $configuration = $this->getConfiguration($configs, $container);
47 26
        $config = $this->processConfiguration($configuration, $configs);
0 ignored issues
show
Bug introduced by
It seems like $configuration defined by $this->getConfiguration($configs, $container) on line 46 can be null; however, Symfony\Component\Depend...:processConfiguration() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
48
49 26
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
50 26
        $loader->load('matcher.xml');
51
52 26
        if ($config['debug']['enabled'] || (!empty($config['cache_control']))) {
53 6
            $debugHeader = $config['debug']['enabled'] ? $config['debug']['header'] : false;
54 6
            $container->setParameter($this->getAlias().'.debug_header', $debugHeader);
55 6
            $loader->load('cache_control_listener.xml');
56
        }
57
58 26
        $this->loadCacheable($container, $config['cacheable']);
59
60 26
        if (!empty($config['cache_control'])) {
61 6
            $this->loadCacheControl($container, $config['cache_control']);
62
        }
63
64 25
        if (isset($config['proxy_client'])) {
65 17
            $this->loadProxyClient($container, $loader, $config['proxy_client']);
66
        }
67
68 24
        if (isset($config['test'])) {
69 1
            $this->loadTest($container, $loader, $config['test']);
70
        }
71
72 24
        if ($config['cache_manager']['enabled']) {
73 17
            if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
74
                // overwrite the previously set alias, if a proxy client was also configured
75 1
                $container->setAlias(
76 1
                    $this->getAlias().'.default_proxy_client',
77 1
                    $config['cache_manager']['custom_proxy_client']
78
                );
79
            }
80 17
            if ('auto' === $config['cache_manager']['generate_url_type']) {
81 17
                if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
82 1
                    $generateUrlType = UrlGeneratorInterface::ABSOLUTE_URL;
83
                } else {
84 16
                    $defaultClient = $this->getDefaultProxyClient($config['proxy_client']);
85 16
                    if ('noop' !== $defaultClient
86 16
                        && array_key_exists('base_url', $config['proxy_client'][$defaultClient])) {
87
                        $generateUrlType = UrlGeneratorInterface::ABSOLUTE_PATH;
88
                    } else {
89 17
                        $generateUrlType = UrlGeneratorInterface::ABSOLUTE_URL;
90
                    }
91
                }
92
            } else {
93
                $generateUrlType = $config['cache_manager']['generate_url_type'];
94
            }
95 17
            $container->setParameter($this->getAlias().'.cache_manager.generate_url_type', $generateUrlType);
96 17
            $loader->load('cache_manager.xml');
97
        }
98
99 24
        if ($config['tags']['enabled']) {
100 17
            $this->loadCacheTagging(
101 17
                $container,
102 17
                $loader,
103 17
                $config['tags'],
104 17
                array_key_exists('proxy_client', $config)
105 16
                    ? $this->getDefaultProxyClient($config['proxy_client'])
106 17
                    : 'custom'
107
            );
108
        } else {
109 7
            $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', false);
110
        }
111
112 23
        if ($config['invalidation']['enabled']) {
113 16
            $loader->load('invalidation_listener.xml');
114
115 16
            if (!empty($config['invalidation']['expression_language'])) {
116
                $container->setAlias(
117
                    $this->getAlias().'.invalidation.expression_language',
118
                    $config['invalidation']['expression_language']
119
                );
120
            }
121
122 16
            if (!empty($config['invalidation']['rules'])) {
123 2
                $this->loadInvalidatorRules($container, $config['invalidation']['rules']);
124
            }
125
        }
126
127 23
        if ($config['user_context']['enabled']) {
128 4
            $this->loadUserContext($container, $loader, $config['user_context']);
129
        }
130
131 23
        if (!empty($config['flash_message']) && $config['flash_message']['enabled']) {
132 2
            unset($config['flash_message']['enabled']);
133 2
            $container->setParameter($this->getAlias().'.event_listener.flash_message.options', $config['flash_message']);
134
135 2
            $loader->load('flash_message.xml');
136
        }
137 23
    }
138
139 26
    private function loadCacheable(ContainerBuilder $container, array $config)
140
    {
141 26
        $definition = $container->getDefinition($this->getAlias().'.response_matcher.cacheable');
142
143
        // Change CacheableResponseMatcher to ExpressionResponseMatcher
144 26
        if ($config['response']['expression']) {
145
            $definition->setClass(ExpressionResponseMatcher::class)
146
                ->setArguments([$config['response']['expression']]);
147
        } else {
148 26
            $container->setParameter(
149 26
                $this->getAlias().'.cacheable.response.additional_status',
150 26
                $config['response']['additional_status']
151
            );
152
        }
153 26
    }
154
155
    /**
156
     * @param ContainerBuilder $container
157
     * @param array            $config
158
     *
159
     * @throws InvalidConfigurationException
160
     */
161 6
    private function loadCacheControl(ContainerBuilder $container, array $config)
162
    {
163 6
        $controlDefinition = $container->getDefinition($this->getAlias().'.event_listener.cache_control');
164
165 6
        foreach ($config['rules'] as $rule) {
166 6
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
167
168 6
            if ('default' === $rule['headers']['overwrite']) {
169 6
                $rule['headers']['overwrite'] = $config['defaults']['overwrite'];
170
            }
171
172 6
            $controlDefinition->addMethodCall('addRule', [$ruleMatcher, $rule['headers']]);
173
        }
174 5
    }
175
176
    /**
177
     * Parse one cache control rule match configuration.
178
     *
179
     * @param ContainerBuilder $container
180
     * @param array            $match     Request and response match criteria
181
     *
182
     * @return Reference pointing to a rule matcher service
183
     */
184 6
    private function parseRuleMatcher(ContainerBuilder $container, array $match)
185
    {
186 6
        $requestMatcher = $this->parseRequestMatcher($container, $match);
187 6
        $responseMatcher = $this->parseResponseMatcher($container, $match);
188
189 6
        $signature = serialize([(string) $requestMatcher, (string) $responseMatcher]);
190 6
        $id = $this->getAlias().'.cache_control.rule_matcher.'.md5($signature);
191
192 6
        if ($container->hasDefinition($id)) {
193 1
            throw new InvalidConfigurationException('Duplicate match criteria. Would be hidden by a previous rule. match: '.json_encode($match));
194
        }
195
196
        $container
197 6
            ->setDefinition($id, $this->createChildDefinition($this->getAlias().'.rule_matcher'))
198 6
            ->replaceArgument(0, $requestMatcher)
199 6
            ->replaceArgument(1, $responseMatcher)
200
        ;
201
202 6
        return new Reference($id);
203
    }
204
205
    /**
206
     * Used for cache control, tag and invalidation rules.
207
     *
208
     * @param ContainerBuilder $container
209
     * @param array            $match
210
     *
211
     * @return Reference to the request matcher
212
     */
213 8
    private function parseRequestMatcher(ContainerBuilder $container, array $match)
214
    {
215 8
        $match['ips'] = (empty($match['ips'])) ? null : $match['ips'];
216
217
        $arguments = [
218 8
            $match['path'],
219 8
            $match['host'],
220 8
            $match['methods'],
221 8
            $match['ips'],
222 8
            $match['attributes'],
223
        ];
224 8
        $serialized = serialize($arguments);
225 8
        $id = $this->getAlias().'.request_matcher.'.md5($serialized).sha1($serialized);
226
227 8
        if (!$container->hasDefinition($id)) {
228
            $container
229 8
                ->setDefinition($id, $this->createChildDefinition($this->getAlias().'.request_matcher'))
230 8
                ->setArguments($arguments)
231
            ;
232
233 8
            if (!empty($match['query_string'])) {
234
                $container->getDefinition($id)->addMethodCall('setQueryString', [$match['query_string']]);
235
            }
236
        }
237
238 8
        return new Reference($id);
239
    }
240
241
    /**
242
     * Used only for cache control rules.
243
     *
244
     * @param ContainerBuilder $container
245
     * @param array            $config
246
     *
247
     * @return Reference to the correct response matcher service
248
     */
249 6
    private function parseResponseMatcher(ContainerBuilder $container, array $config)
250
    {
251 6
        if (!empty($config['additional_response_status'])) {
252 1
            $id = $this->getAlias().'cache_control.expression.'.md5(serialize($config['additional_response_status']));
253 1 View Code Duplication
            if (!$container->hasDefinition($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
254
                $container
255 1
                    ->setDefinition($id, $this->createChildDefinition($this->getAlias().'.response_matcher.cache_control.cacheable_response'))
256 1
                    ->setArguments([$config['additional_response_status']])
257
                ;
258
            }
259 5
        } elseif (!empty($config['match_response'])) {
260 2
            $id = $this->getAlias().'cache_control.match_response.'.md5($config['match_response']);
261 2 View Code Duplication
            if (!$container->hasDefinition($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
262
                $container
263 2
                    ->setDefinition($id, $this->createChildDefinition($this->getAlias().'.response_matcher.cache_control.expression'))
264 2
                    ->replaceArgument(0, $config['match_response'])
265
                ;
266
            }
267
        } else {
268 3
            $id = $this->getAlias().'.response_matcher.cacheable';
269
        }
270
271 6
        return new Reference($id);
272
    }
273
274 4
    private function loadUserContext(ContainerBuilder $container, XmlFileLoader $loader, array $config)
275
    {
276 4
        $loader->load('user_context.xml');
277
278 4
        $container->getDefinition($this->getAlias().'.user_context.request_matcher')
279 4
            ->replaceArgument(0, $config['match']['accept'])
280 4
            ->replaceArgument(1, $config['match']['method']);
281
282 4
        $container->setParameter($this->getAlias().'.event_listener.user_context.options', [
283 4
            'user_identifier_headers' => $config['user_identifier_headers'],
284 4
            'user_hash_header' => $config['user_hash_header'],
285 4
            'ttl' => $config['hash_cache_ttl'],
286 4
            'add_vary_on_hash' => $config['always_vary_on_context_hash'],
287
        ]);
288 4
        $container->getDefinition($this->getAlias().'.event_listener.user_context')
289 4
            ->replaceArgument(0, new Reference($config['match']['matcher_service']));
290
291 4
        $container->getDefinition($this->getAlias().'.user_context.anonymous_request_matcher')
292 4
            ->replaceArgument(0, $config['user_identifier_headers']);
293
294 4
        if ($config['logout_handler']['enabled']) {
295 4
            $container->getDefinition($this->getAlias().'.user_context_invalidator')
296 4
                ->replaceArgument(1, $config['user_identifier_headers'])
297 4
                ->replaceArgument(2, $config['match']['accept']);
298
299 4
            $container->setAlias('security.logout.handler.session', $this->getAlias().'.user_context.session_logout_handler');
300
        } else {
301
            $container->removeDefinition($this->getAlias().'.user_context.logout_handler');
302
            $container->removeDefinition($this->getAlias().'.user_context.session_logout_handler');
303
            $container->removeDefinition($this->getAlias().'.user_context_invalidator');
304
        }
305
306 4
        if ($config['role_provider']) {
307 2
            $container->getDefinition($this->getAlias().'.user_context.role_provider')
308 2
                ->addTag(HashGeneratorPass::TAG_NAME)
309 2
                ->setAbstract(false);
310
        }
311 4
    }
312
313 17
    private function loadProxyClient(ContainerBuilder $container, XmlFileLoader $loader, array $config)
314
    {
315 17
        if (isset($config['varnish'])) {
316 13
            $this->loadVarnish($container, $loader, $config['varnish']);
317
        }
318 16
        if (isset($config['nginx'])) {
319 2
            $this->loadNginx($container, $loader, $config['nginx']);
320
        }
321 16
        if (isset($config['symfony'])) {
322 1
            $this->loadSymfony($container, $loader, $config['symfony']);
323
        }
324 16
        if (isset($config['noop'])) {
325 1
            $loader->load('noop.xml');
326
        }
327
328 16
        $container->setAlias(
329 16
            $this->getAlias().'.default_proxy_client',
330 16
            $this->getAlias().'.proxy_client.'.$this->getDefaultProxyClient($config)
331
        );
332 16
    }
333
334
    /**
335
     * Define the http dispatcher service for the proxy client $name.
336
     *
337
     * @param ContainerBuilder $container
338
     * @param array            $config
339
     * @param string           $serviceName
340
     */
341 16
    private function createHttpDispatcherDefinition(ContainerBuilder $container, array $config, $serviceName)
342
    {
343 16
        foreach ($config['servers'] as $url) {
344 16
            $this->validateUrl($url, 'Not a valid Varnish server address: "%s"');
345
        }
346 16
        if (!empty($config['base_url'])) {
347 16
            $baseUrl = $this->prefixSchema($config['base_url']);
348 16
            $this->validateUrl($baseUrl, 'Not a valid base path: "%s"');
349
        } else {
350
            $baseUrl = null;
351
        }
352 15
        $httpClient = null;
353 15
        if ($config['http_client']) {
354 1
            $httpClient = new Reference($config['http_client']);
355
        }
356
357 15
        $definition = new Definition(HttpDispatcher::class, [
358 15
            $config['servers'],
359 15
            $baseUrl,
360 15
            $httpClient,
361
        ]);
362
363 15
        $container->setDefinition($serviceName, $definition);
364 15
    }
365
366 13
    private function loadVarnish(ContainerBuilder $container, XmlFileLoader $loader, array $config)
367
    {
368 13
        $this->createHttpDispatcherDefinition($container, $config['http'], $this->getAlias().'.proxy_client.varnish.http_dispatcher');
369
        $options = [
370 12
            'tags_header' => $config['tags_header'],
371
        ];
372 12
        if (!empty($config['header_length'])) {
373
            $options['header_length'] = $config['header_length'];
374
        }
375 12
        if (!empty($config['default_ban_headers'])) {
376
            $options['default_ban_headers'] = $config['default_ban_headers'];
377
        }
378 12
        $container->setParameter($this->getAlias().'.proxy_client.varnish.options', $options);
379
380 12
        $loader->load('varnish.xml');
381 12
    }
382
383 2
    private function loadNginx(ContainerBuilder $container, XmlFileLoader $loader, array $config)
384
    {
385 2
        $this->createHttpDispatcherDefinition($container, $config['http'], $this->getAlias().'.proxy_client.nginx.http_dispatcher');
386 2
        $container->setParameter($this->getAlias().'.proxy_client.nginx.options', [
387 2
            'purge_location' => $config['purge_location'],
388
        ]);
389 2
        $loader->load('nginx.xml');
390 2
    }
391
392 1
    private function loadSymfony(ContainerBuilder $container, XmlFileLoader $loader, array $config)
393
    {
394 1
        $this->createHttpDispatcherDefinition($container, $config['http'], $this->getAlias().'.proxy_client.symfony.http_dispatcher');
395 1
        $loader->load('symfony.xml');
396 1
    }
397
398
    /**
399
     * @param ContainerBuilder $container
400
     * @param XmlFileLoader    $loader
401
     * @param array            $config    Configuration section for the tags node
402
     * @param string           $client    Name of the client used with the cache manager,
403
     *                                    "custom" when a custom client is used
404
     */
405 17
    private function loadCacheTagging(ContainerBuilder $container, XmlFileLoader $loader, array $config, $client)
406
    {
407 17
        if ('auto' === $config['enabled'] && 'varnish' !== $client) {
408 4
            $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', false);
409
410 4
            return;
411
        }
412 13
        if (!in_array($client, ['varnish', 'custom', 'noop'])) {
413 1
            throw new InvalidConfigurationException(sprintf('You can not enable cache tagging with the %s client', $client));
414
        }
415
416 12
        $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', true);
417 12
        $container->setParameter($this->getAlias().'.tag_handler.response_header', $config['response_header']);
418 12
        $container->setParameter($this->getAlias().'.tag_handler.strict', $config['strict']);
419 12
        $loader->load('cache_tagging.xml');
420
421 12
        if (!empty($config['expression_language'])) {
422
            $container->setAlias(
423
                $this->getAlias().'.tag_handler.expression_language',
424
                $config['expression_language']
425
            );
426
        }
427
428 12
        if (!empty($config['rules'])) {
429 2
            $this->loadTagRules($container, $config['rules']);
430
        }
431 12
    }
432
433 1
    private function loadTest(ContainerBuilder $container, XmlFileLoader $loader, array $config)
434
    {
435 1
        $container->setParameter($this->getAlias().'.test.cache_header', $config['cache_header']);
436
437 1
        if ($config['proxy_server']) {
438 1
            $this->loadProxyServer($container, $loader, $config['proxy_server']);
439
        }
440 1
    }
441
442 1
    private function loadProxyServer(ContainerBuilder $container, XmlFileLoader $loader, array $config)
443
    {
444 1
        if (isset($config['varnish'])) {
445 1
            $this->loadVarnishProxyServer($container, $loader, $config['varnish']);
446
        }
447
448 1
        if (isset($config['nginx'])) {
449
            $this->loadNginxProxyServer($container, $loader, $config['varnish']);
450
        }
451
452 1
        $container->setAlias(
453 1
            $this->getAlias().'.test.default_proxy_server',
454 1
            $this->getAlias().'.test.proxy_server.'.$this->getDefaultProxyClient($config)
455
        );
456 1
    }
457
458 1
    private function loadVarnishProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
459
    {
460 1
        $loader->load('varnish_proxy.xml');
461 1
        foreach ($config as $key => $value) {
462 1
            $container->setParameter(
463 1
                $this->getAlias().'.test.proxy_server.varnish.'.$key,
464 1
                $value
465
            );
466
        }
467 1
    }
468
469
    private function loadNginxProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
470
    {
471
        $loader->load('nginx_proxy.xml');
472
        foreach ($config as $key => $value) {
473
            $container->setParameter(
474
                $this->getAlias().'.test.proxy_server.nginx.'.$key,
475
                $value
476
            );
477
        }
478
    }
479
480 2
    private function loadTagRules(ContainerBuilder $container, array $config)
481
    {
482 2
        $tagDefinition = $container->getDefinition($this->getAlias().'.event_listener.tag');
483
484 2
        foreach ($config as $rule) {
485 2
            $ruleMatcher = $this->parseRequestMatcher($container, $rule['match']);
486
487
            $tags = [
488 2
                'tags' => $rule['tags'],
489 2
                'expressions' => $rule['tag_expressions'],
490
            ];
491
492 2
            $tagDefinition->addMethodCall('addRule', [$ruleMatcher, $tags]);
493
        }
494 2
    }
495
496 2
    private function loadInvalidatorRules(ContainerBuilder $container, array $config)
497
    {
498 2
        $tagDefinition = $container->getDefinition($this->getAlias().'.event_listener.invalidation');
499
500 2
        foreach ($config as $rule) {
501 2
            $ruleMatcher = $this->parseRequestMatcher($container, $rule['match']);
502 2
            $tagDefinition->addMethodCall('addRule', [$ruleMatcher, $rule['routes']]);
503
        }
504 2
    }
505
506 16
    private function validateUrl($url, $msg)
507
    {
508 16
        $prefixed = $this->prefixSchema($url);
509
510 16
        if (!$parts = parse_url($prefixed)) {
511 1
            throw new InvalidConfigurationException(sprintf($msg, $url));
512
        }
513 16
    }
514
515 16
    private function prefixSchema($url)
516
    {
517 16
        if (false === strpos($url, '://')) {
518 16
            $url = sprintf('%s://%s', 'http', $url);
519
        }
520
521 16
        return $url;
522
    }
523
524 16
    private function getDefaultProxyClient(array $config)
525
    {
526 16
        if (isset($config['default'])) {
527
            return $config['default'];
528
        }
529
530 16
        if (isset($config['varnish'])) {
531 12
            return 'varnish';
532
        }
533
534 4
        if (isset($config['nginx'])) {
535 2
            return 'nginx';
536
        }
537
538 2
        if (isset($config['symfony'])) {
539 1
            return 'symfony';
540
        }
541
542 1
        if (isset($config['noop'])) {
543 1
            return 'noop';
544
        }
545
546
        throw new InvalidConfigurationException('No proxy client configured');
547
    }
548
549
    /**
550
     * Build the child definition with fallback for Symfony versions < 3.3.
551
     *
552
     * @param string $id Id of the service to extend
553
     *
554
     * @return ChildDefinition|DefinitionDecorator
555
     */
556 8
    private function createChildDefinition($id)
557
    {
558 8
        if (class_exists(ChildDefinition::class)) {
559
            return new ChildDefinition($id);
560
        }
561
562 8
        return new DefinitionDecorator($id);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
563
    }
564
}
565