FOSHttpCacheExtension::loadInvalidatorRules()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 4
cp 1
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
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\HttpCache\ProxyClient\ProxyClient;
16
use FOS\HttpCache\SymfonyCache\KernelDispatcher;
17
use FOS\HttpCache\TagHeaderFormatter\MaxHeaderValueLengthFormatter;
18
use FOS\HttpCacheBundle\DependencyInjection\Compiler\HashGeneratorPass;
19
use FOS\HttpCacheBundle\Http\ResponseMatcher\ExpressionResponseMatcher;
20
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
21
use Symfony\Component\Config\FileLocator;
22
use Symfony\Component\Console\Application;
23
use Symfony\Component\DependencyInjection\ChildDefinition;
24
use Symfony\Component\DependencyInjection\ContainerBuilder;
25
use Symfony\Component\DependencyInjection\Definition;
26
use Symfony\Component\DependencyInjection\DefinitionDecorator;
27
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
28
use Symfony\Component\DependencyInjection\Reference;
29
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
30
use Symfony\Component\HttpKernel\Kernel;
31
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
32
33
/**
34
 * {@inheritdoc}
35
 */
36
class FOSHttpCacheExtension extends Extension
37
{
38
    /**
39
     * {@inheritdoc}
40
     */
41 37
    public function getConfiguration(array $config, ContainerBuilder $container)
42
    {
43 37
        return new Configuration($container->getParameter('kernel.debug'));
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 37
    public function load(array $configs, ContainerBuilder $container)
50
    {
51 37
        $configuration = $this->getConfiguration($configs, $container);
52 37
        $config = $this->processConfiguration($configuration, $configs);
0 ignored issues
show
Bug introduced by
It seems like $configuration defined by $this->getConfiguration($configs, $container) on line 51 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...
53
54 37
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
55 37
        $loader->load('matcher.xml');
56
57 37
        if ($config['debug']['enabled'] || (!empty($config['cache_control']))) {
58 7
            $debugHeader = $config['debug']['enabled'] ? $config['debug']['header'] : false;
59 7
            $container->setParameter('fos_http_cache.debug_header', $debugHeader);
60 7
            $loader->load('cache_control_listener.xml');
61
        }
62
63 37
        $this->loadCacheable($container, $config['cacheable']);
64
65 37
        if (!empty($config['cache_control'])) {
66 7
            $this->loadCacheControl($container, $config['cache_control']);
67
        }
68
69 36
        if (isset($config['proxy_client'])) {
70 27
            $this->loadProxyClient($container, $loader, $config['proxy_client']);
71
        }
72
73 35
        if (isset($config['test'])) {
74 2
            $this->loadTest($container, $loader, $config['test']);
75
        }
76
77 35
        if ($config['cache_manager']['enabled']) {
78 27
            if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
79
                // overwrite the previously set alias, if a proxy client was also configured
80 1
                $container->setAlias(
81 1
                    'fos_http_cache.default_proxy_client',
82 1
                    $config['cache_manager']['custom_proxy_client']
83
                );
84
            }
85 27
            if ('auto' === $config['cache_manager']['generate_url_type']) {
86 27
                if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
87 1
                    $generateUrlType = UrlGeneratorInterface::ABSOLUTE_URL;
88
                } else {
89 26
                    $defaultClient = $this->getDefaultProxyClient($config['proxy_client']);
90 26
                    if ('noop' !== $defaultClient
91 26
                        && array_key_exists('base_url', $config['proxy_client'][$defaultClient])) {
92
                        $generateUrlType = UrlGeneratorInterface::ABSOLUTE_PATH;
93
                    } else {
94 27
                        $generateUrlType = UrlGeneratorInterface::ABSOLUTE_URL;
95
                    }
96
                }
97
            } else {
98
                $generateUrlType = $config['cache_manager']['generate_url_type'];
99
            }
100 27
            $container->setParameter('fos_http_cache.cache_manager.generate_url_type', $generateUrlType);
101 27
            $loader->load('cache_manager.xml');
102 27
            if (class_exists(Application::class)) {
103 27
                $loader->load('cache_manager_commands.xml');
104
            }
105
        }
106
107 35
        if ($config['tags']['enabled']) {
108 27
            $this->loadCacheTagging(
109 27
                $container,
110
                $loader,
111 27
                $config['tags'],
112 27
                array_key_exists('proxy_client', $config)
113 26
                    ? $this->getDefaultProxyClient($config['proxy_client'])
114 27
                    : 'custom'
115
            );
116
        } else {
117 8
            $container->setParameter('fos_http_cache.compiler_pass.tag_annotations', false);
118
        }
119
120 34
        if ($config['invalidation']['enabled']) {
121 26
            $loader->load('invalidation_listener.xml');
122
123 26
            if (!empty($config['invalidation']['expression_language'])) {
124
                $container->setAlias(
125
                    'fos_http_cache.invalidation.expression_language',
126
                    $config['invalidation']['expression_language']
127
                );
128
            }
129
130 26
            if (!empty($config['invalidation']['rules'])) {
131 3
                $this->loadInvalidatorRules($container, $config['invalidation']['rules']);
132
            }
133
        }
134
135 34
        if ($config['user_context']['enabled']) {
136 6
            $this->loadUserContext($container, $loader, $config['user_context']);
137
        }
138
139 34
        if (!empty($config['flash_message']) && $config['flash_message']['enabled']) {
140 3
            unset($config['flash_message']['enabled']);
141 3
            $container->setParameter('fos_http_cache.event_listener.flash_message.options', $config['flash_message']);
142
143 3
            $loader->load('flash_message.xml');
144
        }
145 34
146
        if (\PHP_VERSION_ID >= 80000) {
147 37
            $loader->load('php8_attributes.xml');
148
        }
149 37
    }
150
151
    private function loadCacheable(ContainerBuilder $container, array $config)
152 37
    {
153
        $definition = $container->getDefinition('fos_http_cache.response_matcher.cacheable');
154
155
        // Change CacheableResponseMatcher to ExpressionResponseMatcher
156 37
        if ($config['response']['expression']) {
157 37
            $definition->setClass(ExpressionResponseMatcher::class)
158 37
                ->setArguments([$config['response']['expression']]);
159
        } else {
160
            $container->setParameter(
161 37
                'fos_http_cache.cacheable.response.additional_status',
162
                $config['response']['additional_status']
163
            );
164
        }
165
    }
166
167
    /**
168
     * @throws InvalidConfigurationException
169 7
     */
170
    private function loadCacheControl(ContainerBuilder $container, array $config)
171 7
    {
172
        $controlDefinition = $container->getDefinition('fos_http_cache.event_listener.cache_control');
173 7
174 7
        foreach ($config['rules'] as $rule) {
175
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
176 7
177 7
            if ('default' === $rule['headers']['overwrite']) {
178
                $rule['headers']['overwrite'] = $config['defaults']['overwrite'];
179
            }
180 7
181
            $controlDefinition->addMethodCall('addRule', [$ruleMatcher, $rule['headers']]);
182 6
        }
183
    }
184
185
    /**
186
     * Parse one cache control rule match configuration.
187
     *
188
     * @param array $match Request and response match criteria
189
     *
190
     * @return Reference pointing to a rule matcher service
191
     */
192 7
    private function parseRuleMatcher(ContainerBuilder $container, array $match)
193
    {
194 7
        $requestMatcher = $this->parseRequestMatcher($container, $match);
195 7
        $responseMatcher = $this->parseResponseMatcher($container, $match);
196
197 7
        $signature = serialize([(string) $requestMatcher, (string) $responseMatcher]);
198 7
        $id = 'fos_http_cache.cache_control.rule_matcher.'.md5($signature);
199
200 7
        if ($container->hasDefinition($id)) {
201 1
            throw new InvalidConfigurationException('Duplicate match criteria. Would be hidden by a previous rule. match: '.json_encode($match));
202
        }
203
204
        $container
205 7
            ->setDefinition($id, $this->createChildDefinition('fos_http_cache.rule_matcher'))
206 7
            ->replaceArgument(0, $requestMatcher)
207 7
            ->replaceArgument(1, $responseMatcher)
208
        ;
209
210 7
        return new Reference($id);
211
    }
212
213
    /**
214
     * Used for cache control, tag and invalidation rules.
215
     *
216
     * @return Reference to the request matcher
217
     */
218
    private function parseRequestMatcher(ContainerBuilder $container, array $match)
219
    {
220
        $match['ips'] = (empty($match['ips'])) ? null : $match['ips'];
221 9
222
        $arguments = [
223 9
            $match['path'],
224
            $match['host'],
225
            $match['methods'],
226 9
            $match['ips'],
227 9
            $match['attributes'],
228 9
        ];
229 9
        $serialized = serialize($arguments);
230 9
        $id = 'fos_http_cache.request_matcher.'.md5($serialized).sha1($serialized);
231
232 9
        if (!$container->hasDefinition($id)) {
233 9
            $container
234
                ->setDefinition($id, $this->createChildDefinition('fos_http_cache.request_matcher'))
235 9
                ->setArguments($arguments)
236
            ;
237 9
238 9
            if (!empty($match['query_string'])) {
239
                $container->getDefinition($id)->addMethodCall('setQueryString', [$match['query_string']]);
240
            }
241 9
        }
242
243
        return new Reference($id);
244
    }
245
246 9
    /**
247
     * Used only for cache control rules.
248
     *
249
     * @return Reference to the correct response matcher service
250
     */
251
    private function parseResponseMatcher(ContainerBuilder $container, array $config)
252
    {
253
        if (!empty($config['additional_response_status'])) {
254
            $id = 'fos_http_cache.cache_control.expression.'.md5(serialize($config['additional_response_status']));
255
            if (!$container->hasDefinition($id)) {
256
                $container
257 7
                    ->setDefinition($id, $this->createChildDefinition('fos_http_cache.response_matcher.cache_control.cacheable_response'))
258
                    ->setArguments([$config['additional_response_status']])
259 7
                ;
260 1
            }
261 1
        } elseif (!empty($config['match_response'])) {
262
            $id = 'fos_http_cache.cache_control.match_response.'.md5($config['match_response']);
263 1
            if (!$container->hasDefinition($id)) {
264 1
                $container
265
                    ->setDefinition($id, $this->createChildDefinition('fos_http_cache.response_matcher.cache_control.expression'))
266
                    ->replaceArgument(0, $config['match_response'])
267 6
                ;
268 2
            }
269 2
        } else {
270
            $id = 'fos_http_cache.response_matcher.cacheable';
271 2
        }
272 2
273
        return new Reference($id);
274
    }
275
276 4
    private function loadUserContext(ContainerBuilder $container, XmlFileLoader $loader, array $config)
277
    {
278
        $configuredUserIdentifierHeaders = array_map('strtolower', $config['user_identifier_headers']);
279 7
        $completeUserIdentifierHeaders = $configuredUserIdentifierHeaders;
280
        if (false !== $config['session_name_prefix'] && !in_array('cookie', $completeUserIdentifierHeaders)) {
281
            $completeUserIdentifierHeaders[] = 'cookie';
282 6
        }
283
284 6
        $loader->load('user_context.xml');
285 6
286 6
        $container->getDefinition('fos_http_cache.user_context.request_matcher')
287
            ->replaceArgument(0, $config['match']['accept'])
288
            ->replaceArgument(1, $config['match']['method']);
289
290 6
        $container->setParameter('fos_http_cache.event_listener.user_context.options', [
291
            'user_identifier_headers' => $completeUserIdentifierHeaders,
292 6
            'user_hash_header' => $config['user_hash_header'],
293 6
            'ttl' => $config['hash_cache_ttl'],
294 6
            'add_vary_on_hash' => $config['always_vary_on_context_hash'],
295
        ]);
296 6
297 6
        $container->getDefinition('fos_http_cache.event_listener.user_context')
298 6
            ->replaceArgument(0, new Reference($config['match']['matcher_service']))
299 6
        ;
300 6
301
        $options = [
302
            'user_identifier_headers' => $configuredUserIdentifierHeaders,
303 6
            'session_name_prefix' => $config['session_name_prefix'],
304 6
        ];
305
        $container->getDefinition('fos_http_cache.user_context.anonymous_request_matcher')
306
            ->replaceArgument(0, $options);
307
308 6
        if ($config['logout_handler']['enabled']) {
309 6
            $container->setAlias('security.logout.handler.session', 'fos_http_cache.user_context.session_logout_handler');
310
        } else {
311 6
            $container->removeDefinition('fos_http_cache.user_context.logout_handler');
312 6
            $container->removeDefinition('fos_http_cache.user_context.session_logout_handler');
313
            $container->removeDefinition('fos_http_cache.user_context_invalidator');
314 6
        }
315 5
316
        if ($config['role_provider']) {
317 1
            $container->getDefinition('fos_http_cache.user_context.role_provider')
318 1
                ->addTag(HashGeneratorPass::TAG_NAME)
319 1
                ->setAbstract(false);
320
        }
321
322 6
        // Only decorate default SessionListener for Symfony 3.4 - 4.0
323 4
        // For Symfony 4.1+, the UserContextListener sets the header that tells
324 4
        // the SessionListener to leave the cache-control header unchanged.
325 4
        if (version_compare(Kernel::VERSION, '3.4', '>=')
326
            && version_compare(Kernel::VERSION, '4.1', '<')
327
        ) {
328
            $container->getDefinition('fos_http_cache.user_context.session_listener')
329
                ->setArgument(1, strtolower($config['user_hash_header']))
330
                ->setArgument(2, $completeUserIdentifierHeaders);
331 6
        } else {
332 6
            $container->removeDefinition('fos_http_cache.user_context.session_listener');
333
        }
334
    }
335
336
    private function loadProxyClient(ContainerBuilder $container, XmlFileLoader $loader, array $config)
337
    {
338 6
        if (isset($config['varnish'])) {
339
            $this->loadVarnish($container, $loader, $config['varnish']);
340 6
        }
341
        if (isset($config['nginx'])) {
342 27
            $this->loadNginx($container, $loader, $config['nginx']);
343
        }
344 27
        if (isset($config['symfony'])) {
345 22
            $this->loadSymfony($container, $loader, $config['symfony']);
346
        }
347 26
        if (isset($config['noop'])) {
348 2
            $loader->load('noop.xml');
349
        }
350 26
351 2
        $container->setAlias(
352
            'fos_http_cache.default_proxy_client',
353 26
            'fos_http_cache.proxy_client.'.$this->getDefaultProxyClient($config)
354 1
        );
355
        $container->setAlias(
356
            ProxyClient::class,
357 26
            'fos_http_cache.default_proxy_client'
358 26
        );
359 26
    }
360
361 26
    /**
362 26
     * Define the http dispatcher service for the proxy client $name.
363 26
     *
364
     * @param string $serviceName
365 26
     */
366
    private function createHttpDispatcherDefinition(ContainerBuilder $container, array $config, $serviceName)
367
    {
368
        foreach ($config['servers'] as $url) {
369
            $usedEnvs = [];
370
            $container->resolveEnvPlaceholders($url, null, $usedEnvs);
371
            if (0 === \count($usedEnvs)) {
372
                $this->validateUrl($url, 'Not a valid Varnish server address: "%s"');
373
            }
374 25
        }
375
        if (!empty($config['base_url'])) {
376 25
            $baseUrl = $config['base_url'];
377 25
            $usedEnvs = [];
378 25
            $container->resolveEnvPlaceholders($baseUrl, null, $usedEnvs);
379 25
            if (0 === \count($usedEnvs)) {
380 25
                $baseUrl = $this->prefixSchema($baseUrl);
381
                $this->validateUrl($baseUrl, 'Not a valid base path: "%s"');
382
            }
383 25
        } else {
384 25
            $baseUrl = null;
385 25
        }
386 25
        $httpClient = null;
387 25
        if ($config['http_client']) {
388 25
            $httpClient = new Reference($config['http_client']);
389 25
        }
390
391
        $definition = new Definition(HttpDispatcher::class, [
392
            $config['servers'],
393
            $baseUrl,
394 24
            $httpClient,
395 24
        ]);
396 1
397
        $container->setDefinition($serviceName, $definition);
398
    }
399 24
400 24
    private function loadVarnish(ContainerBuilder $container, XmlFileLoader $loader, array $config)
401 24
    {
402 24
        $this->createHttpDispatcherDefinition($container, $config['http'], 'fos_http_cache.proxy_client.varnish.http_dispatcher');
403
        $options = [
404
            'tag_mode' => $config['tag_mode'],
405 24
            'tags_header' => $config['tags_header'],
406 24
        ];
407
408 22
        if (!empty($config['header_length'])) {
409
            $options['header_length'] = $config['header_length'];
410 22
        }
411
        if (!empty($config['default_ban_headers'])) {
412 21
            $options['default_ban_headers'] = $config['default_ban_headers'];
413 21
        }
414
        $container->setParameter('fos_http_cache.proxy_client.varnish.options', $options);
415
416 21
        $loader->load('varnish.xml');
417
    }
418
419 21
    private function loadNginx(ContainerBuilder $container, XmlFileLoader $loader, array $config)
420
    {
421
        $this->createHttpDispatcherDefinition($container, $config['http'], 'fos_http_cache.proxy_client.nginx.http_dispatcher');
422 21
        $container->setParameter('fos_http_cache.proxy_client.nginx.options', [
423
            'purge_location' => $config['purge_location'],
424 21
        ]);
425 21
        $loader->load('nginx.xml');
426
    }
427 2
428
    private function loadSymfony(ContainerBuilder $container, XmlFileLoader $loader, array $config)
429 2
    {
430 2
        $serviceName = 'fos_http_cache.proxy_client.symfony.http_dispatcher';
431 2
432
        if ($config['use_kernel_dispatcher']) {
433 2
            $definition = new Definition(KernelDispatcher::class, [
434 2
                new Reference('kernel'),
435
            ]);
436 2
            $container->setDefinition($serviceName, $definition);
437
        } else {
438 2
            $this->createHttpDispatcherDefinition($container, $config['http'], $serviceName);
439
        }
440 2
441 1
        $options = [
442 1
            'tags_header' => $config['tags_header'],
443
            'tags_method' => $config['tags_method'],
444 1
            'purge_method' => $config['purge_method'],
445
        ];
446 1
        if (!empty($config['header_length'])) {
447
            $options['header_length'] = $config['header_length'];
448
        }
449
        $container->setParameter('fos_http_cache.proxy_client.symfony.options', $options);
450 2
451 2
        $loader->load('symfony.xml');
452 2
    }
453
454 2
    /**
455
     * @param array  $config Configuration section for the tags node
456
     * @param string $client Name of the client used with the cache manager,
457 2
     *                       "custom" when a custom client is used
458
     */
459 2
    private function loadCacheTagging(ContainerBuilder $container, XmlFileLoader $loader, array $config, $client)
460 2
    {
461
        if ('auto' === $config['enabled'] && !in_array($client, ['varnish', 'symfony'])) {
462
            $container->setParameter('fos_http_cache.compiler_pass.tag_annotations', false);
463
464
            return;
465
        }
466
        if (!in_array($client, ['varnish', 'symfony', 'custom', 'noop'])) {
467
            throw new InvalidConfigurationException(sprintf('You can not enable cache tagging with the %s client', $client));
468
        }
469 27
470
        $container->setParameter('fos_http_cache.compiler_pass.tag_annotations', $config['annotations']['enabled']);
471 27
        $container->setParameter('fos_http_cache.tag_handler.response_header', $config['response_header']);
472 3
        $container->setParameter('fos_http_cache.tag_handler.separator', $config['separator']);
473
        $container->setParameter('fos_http_cache.tag_handler.strict', $config['strict']);
474 3
475
        $loader->load('cache_tagging.xml');
476 24
        if (class_exists(Application::class)) {
477 1
            $loader->load('cache_tagging_commands.xml');
478
        }
479
480 23
        if (!empty($config['expression_language'])) {
481 23
            $container->setAlias(
482 23
                'fos_http_cache.tag_handler.expression_language',
483 23
                $config['expression_language']
484
            );
485 23
        }
486 23
487 23
        if (!empty($config['rules'])) {
488
            $this->loadTagRules($container, $config['rules']);
489
        }
490 23
491
        if (null !== $config['max_header_value_length']) {
492
            $container->register('fos_http_cache.tag_handler.max_header_value_length_header_formatter', MaxHeaderValueLengthFormatter::class)
493
                ->setDecoratedService('fos_http_cache.tag_handler.header_formatter')
494
                ->addArgument(new Reference('fos_http_cache.tag_handler.max_header_value_length_header_formatter.inner'))
495
                ->addArgument((int) $config['max_header_value_length']);
496
        }
497 23
    }
498 3
499
    private function loadTest(ContainerBuilder $container, XmlFileLoader $loader, array $config)
500
    {
501 23
        $container->setParameter('fos_http_cache.test.cache_header', $config['cache_header']);
502 1
503 1
        if ($config['proxy_server']) {
504 1
            $this->loadProxyServer($container, $loader, $config['proxy_server']);
505 1
        }
506
    }
507 23
508
    private function loadProxyServer(ContainerBuilder $container, XmlFileLoader $loader, array $config)
509 2
    {
510
        if (isset($config['varnish'])) {
511 2
            $this->loadVarnishProxyServer($container, $loader, $config['varnish']);
512
        }
513 2
514 2
        if (isset($config['nginx'])) {
515
            $this->loadNginxProxyServer($container, $loader, $config['nginx']);
516 2
        }
517
518 2
        $container->setAlias(
519
            'fos_http_cache.test.default_proxy_server',
520 2
            'fos_http_cache.test.proxy_server.'.$this->getDefaultProxyClient($config)
521 2
        );
522
    }
523
524 2
    private function loadVarnishProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
525
    {
526
        $loader->load('varnish_proxy.xml');
527
        foreach ($config as $key => $value) {
528 2
            $container->setParameter(
529 2
                'fos_http_cache.test.proxy_server.varnish.'.$key,
530 2
                $value
531
            );
532 2
        }
533
    }
534 2
535
    private function loadNginxProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
536 2
    {
537 2
        $loader->load('nginx_proxy.xml');
538 2
        foreach ($config as $key => $value) {
539 2
            $container->setParameter(
540
                'fos_http_cache.test.proxy_server.nginx.'.$key,
541
                $value
542
            );
543 2
        }
544
    }
545
546
    private function loadTagRules(ContainerBuilder $container, array $config)
547
    {
548
        $tagDefinition = $container->getDefinition('fos_http_cache.event_listener.tag');
549
550
        foreach ($config as $rule) {
551
            $ruleMatcher = $this->parseRequestMatcher($container, $rule['match']);
552
553
            $tags = [
554
                'tags' => $rule['tags'],
555
                'expressions' => $rule['tag_expressions'],
556 3
            ];
557
558 3
            $tagDefinition->addMethodCall('addRule', [$ruleMatcher, $tags]);
559
        }
560 3
    }
561 3
562
    private function loadInvalidatorRules(ContainerBuilder $container, array $config)
563
    {
564 3
        $tagDefinition = $container->getDefinition('fos_http_cache.event_listener.invalidation');
565 3
566
        foreach ($config as $rule) {
567
            $ruleMatcher = $this->parseRequestMatcher($container, $rule['match']);
568 3
            $tagDefinition->addMethodCall('addRule', [$ruleMatcher, $rule['routes']]);
569
        }
570 3
    }
571
572 3
    private function validateUrl($url, $msg)
573
    {
574 3
        $prefixed = $this->prefixSchema($url);
575
576 3
        if (!$parts = parse_url($prefixed)) {
577 3
            throw new InvalidConfigurationException(sprintf($msg, $url));
578 3
        }
579
    }
580 3
581
    private function prefixSchema($url)
582 25
    {
583
        if (false === strpos($url, '://')) {
584 25
            $url = sprintf('%s://%s', 'http', $url);
585
        }
586 25
587 1
        return $url;
588
    }
589 25
590
    private function getDefaultProxyClient(array $config)
591 25
    {
592
        if (isset($config['default'])) {
593 25
            return $config['default'];
594 25
        }
595
596
        if (isset($config['varnish'])) {
597 25
            return 'varnish';
598
        }
599
600 26
        if (isset($config['nginx'])) {
601
            return 'nginx';
602 26
        }
603
604
        if (isset($config['symfony'])) {
605
            return 'symfony';
606 26
        }
607 21
608
        if (isset($config['noop'])) {
609
            return 'noop';
610 5
        }
611 2
612
        throw new InvalidConfigurationException('No proxy client configured');
613
    }
614 3
615 2
    /**
616
     * Build the child definition with fallback for Symfony versions < 3.3.
617
     *
618 1
     * @param string $id Id of the service to extend
619 1
     *
620
     * @return ChildDefinition|DefinitionDecorator
621
     */
622
    private function createChildDefinition($id)
623
    {
624
        if (class_exists(ChildDefinition::class)) {
625
            return new ChildDefinition($id);
626
        }
627
628
        return new DefinitionDecorator($id);
629
    }
630
}
631