Completed
Push — master ( 849954...8f1795 )
by David
9s
created

src/DependencyInjection/Configuration.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 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\Varnish;
15
use FOS\HttpCache\SymfonyCache\PurgeListener;
16
use FOS\HttpCache\SymfonyCache\PurgeTagsListener;
17
use FOS\HttpCache\TagHeaderFormatter\TagHeaderFormatter;
18
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
19
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
20
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
21
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
22
use Symfony\Component\Config\Definition\ConfigurationInterface;
23
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
24
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
25
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
26
27
/**
28
 * This class contains the configuration information for the bundle.
29
 *
30
 * This information is solely responsible for how the different configuration
31
 * sections are normalized, and merged.
32
 *
33
 * @author David de Boer <[email protected]>
34
 * @author David Buchmann <[email protected]>
35
 */
36
class Configuration implements ConfigurationInterface
37
{
38
    /**
39
     * @var bool
40
     */
41
    private $debug;
42
43
    /**
44
     * @param bool $debug Whether to use the debug mode
45
     */
46 46
    public function __construct($debug)
47
    {
48 46
        $this->debug = $debug;
49 46
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54 46
    public function getConfigTreeBuilder()
55
    {
56 46
        $treeBuilder = new TreeBuilder();
57 46
        $rootNode = $treeBuilder->root('fos_http_cache');
58
59
        $rootNode
60 46
            ->validate()
61 46
                ->ifTrue(function ($v) {
62 44
                    return $v['cache_manager']['enabled']
63 44
                        && !isset($v['proxy_client'])
64 44
                        && !isset($v['cache_manager']['custom_proxy_client'])
65
                    ;
66 46
                })
67 46 View Code Duplication
                ->then(function ($v) {
68 15
                    if ('auto' === $v['cache_manager']['enabled']) {
69 14
                        $v['cache_manager']['enabled'] = false;
70
71 14
                        return $v;
72
                    }
73
74 1
                    throw new InvalidConfigurationException('You need to configure a proxy_client or specify a custom_proxy_client to use the cache_manager.');
75 46
                })
76 46
            ->end()
77 46
            ->validate()
78 46
                ->ifTrue(function ($v) {
79 43
                    return $v['tags']['enabled'] && !$v['cache_manager']['enabled'];
80 46
                })
81 46 View Code Duplication
                ->then(function ($v) {
82 16
                    if ('auto' === $v['tags']['enabled']) {
83 15
                        $v['tags']['enabled'] = false;
84
85 15
                        return $v;
86
                    }
87
88 1
                    throw new InvalidConfigurationException('You need to configure a proxy_client to get the cache_manager needed for tag handling.');
89 46
                })
90 46
            ->end()
91 46
            ->validate()
92 46
                ->ifTrue(function ($v) {
93 42
                    return $v['invalidation']['enabled'] && !$v['cache_manager']['enabled'];
94 46
                })
95 46 View Code Duplication
                ->then(function ($v) {
96 15
                    if ('auto' === $v['invalidation']['enabled']) {
97 14
                        $v['invalidation']['enabled'] = false;
98
99 14
                        return $v;
100
                    }
101
102 1
                    throw new InvalidConfigurationException('You need to configure a proxy_client to get the cache_manager needed for invalidation handling.');
103 46
                })
104 46
            ->end()
105 46
            ->validate()
106 46
                ->ifTrue(
107 46
                    function ($v) {
108 41
                        return $v['user_context']['logout_handler']['enabled']
109 41
                            && !isset($v['proxy_client']);
110 46
                    }
111
                )
112 46 View Code Duplication
                ->then(function ($v) {
0 ignored issues
show
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...
113 16
                    if ('auto' === $v['user_context']['logout_handler']['enabled']) {
114 16
                        $v['user_context']['logout_handler']['enabled'] = false;
115
116 16
                        return $v;
117
                    }
118
119
                    throw new InvalidConfigurationException('You need to configure a proxy_client for the logout_handler.');
120 46
                })
121
        ;
122
123 46
        $this->addCacheableResponseSection($rootNode);
124 46
        $this->addCacheControlSection($rootNode);
125 46
        $this->addProxyClientSection($rootNode);
126 46
        $this->addCacheManagerSection($rootNode);
127 46
        $this->addTagSection($rootNode);
128 46
        $this->addInvalidationSection($rootNode);
129 46
        $this->addUserContextListenerSection($rootNode);
130 46
        $this->addFlashMessageSection($rootNode);
131 46
        $this->addTestSection($rootNode);
132 46
        $this->addDebugSection($rootNode);
133
134 46
        return $treeBuilder;
135
    }
136
137 46
    private function addCacheableResponseSection(ArrayNodeDefinition $rootNode)
138
    {
139
        $rootNode
140 46
            ->children()
141 46
                ->arrayNode('cacheable')
142 46
                    ->addDefaultsIfNotSet()
143 46
                    ->children()
144 46
                        ->arrayNode('response')
145 46
                            ->addDefaultsIfNotSet()
146 46
                            ->children()
147 46
                                ->arrayNode('additional_status')
148 46
                                    ->prototype('scalar')->end()
149 46
                                    ->info('Additional response HTTP status codes that will be considered cacheable.')
150 46
                                ->end()
151 46
                                ->scalarNode('expression')
152 46
                                    ->defaultNull()
153 46
                                    ->info('Expression to decide whether response is cacheable. Replaces the default status codes.')
154 46
                            ->end()
155 46
                        ->end()
156
157 46
                        ->validate()
158 46
                            ->ifTrue(function ($v) {
159 6
                                return !empty($v['additional_status']) && !empty($v['expression']);
160 46
                            })
161 46
                            ->thenInvalid('You may not set both additional_status and expression.')
162 46
                        ->end()
163 46
                    ->end()
164 46
                ->end()
165 46
            ->end();
166 46
    }
167
168
    /**
169
     * Cache header control main section.
170
     *
171
     * @param ArrayNodeDefinition $rootNode
172
     */
173 46
    private function addCacheControlSection(ArrayNodeDefinition $rootNode)
174
    {
175
        $rules = $rootNode
176 46
            ->children()
177 46
                ->arrayNode('cache_control')
178 46
                    ->fixXmlConfig('rule')
179 46
                    ->children()
180 46
                        ->arrayNode('defaults')
181 46
                            ->addDefaultsIfNotSet()
182 46
                            ->children()
183 46
                                ->booleanNode('overwrite')
184 46
                                    ->info('Whether to overwrite existing cache headers')
185 46
                                    ->defaultFalse()
186 46
                                ->end()
187 46
                            ->end()
188 46
                        ->end()
189 46
                        ->arrayNode('rules')
190 46
                            ->prototype('array')
191 46
                                ->children();
192
193 46
        $this->addMatch($rules, true);
194
        $rules
195 46
            ->arrayNode('headers')
196 46
                ->isRequired()
197
                // todo validate there is some header defined
198 46
                ->children()
199 46
                    ->enumNode('overwrite')
200 46
                        ->info('Whether to overwrite cache headers for this rule, defaults to the cache_control.defaults.overwrite setting')
201 46
                        ->values(['default', true, false])
202 46
                        ->defaultValue('default')
203 46
                    ->end()
204 46
                    ->arrayNode('cache_control')
205 46
                        ->info('Add the specified cache control directives.')
206 46
                        ->children()
207 46
                            ->scalarNode('max_age')->end()
208 46
                            ->scalarNode('s_maxage')->end()
209 46
                            ->booleanNode('private')->end()
210 46
                            ->booleanNode('public')->end()
211 46
                            ->booleanNode('must_revalidate')->end()
212 46
                            ->booleanNode('proxy_revalidate')->end()
213 46
                            ->booleanNode('no_transform')->end()
214 46
                            ->booleanNode('no_cache')->end()
215 46
                            ->booleanNode('no_store')->end()
216 46
                            ->scalarNode('stale_if_error')->end()
217 46
                            ->scalarNode('stale_while_revalidate')->end()
218 46
                        ->end()
219 46
                    ->end()
220 46
                    ->enumNode('etag')
221 46
                        ->defaultValue(false)
222 46
                        ->treatTrueLike('strong')
223 46
                        ->info('Set a simple ETag which is just the md5 hash of the response body. '.
224 46
                               'You can specify which type of ETag you want by passing "strong" or "weak".')
225 46
                        ->values(['weak', 'strong', false])
226 46
                    ->end()
227 46
                    ->scalarNode('last_modified')
228 46
                        ->validate()
229 46
                            ->ifTrue(function ($v) {
230 2
                                if (is_string($v)) {
231 2
                                    new \DateTime($v);
232
                                }
233
234 1
                                return false;
235 46
                            })
236 46
                            ->thenInvalid('') // this will never happen as new DateTime will throw an exception if $v is no date
237 46
                        ->end()
238 46
                        ->info('Set a default last modified timestamp if none is set yet. Value must be parseable by DateTime')
239 46
                    ->end()
240 46
                    ->scalarNode('reverse_proxy_ttl')
241 46
                        ->defaultNull()
242 46
                        ->info('Specify an X-Reverse-Proxy-TTL header with a time in seconds for a caching proxy under your control.')
243 46
                    ->end()
244 46
                    ->arrayNode('vary')
245 46
                        ->beforeNormalization()->ifString()->then(function ($v) {
246 2
                            return preg_split('/\s*,\s*/', $v);
247 46
                        })->end()
248 46
                        ->prototype('scalar')->end()
249 46
                        ->info('Define a list of additional headers on which the response varies.')
250 46
                    ->end()
251 46
                ->end()
252 46
            ->end()
253
        ;
254 46
    }
255
256
    /**
257
     * Shared configuration between cache control, tags and invalidation.
258
     *
259
     * @param NodeBuilder $rules
260
     * @param bool        $matchResponse whether to also add fields to match response
261
     */
262 46
    private function addMatch(NodeBuilder $rules, $matchResponse = false)
263
    {
264
        $match = $rules
265 46
            ->arrayNode('match')
266 46
                ->cannotBeOverwritten()
267 46
                ->isRequired()
268 46
                ->fixXmlConfig('method')
269 46
                ->fixXmlConfig('ip')
270 46
                ->fixXmlConfig('attribute')
271 46
                ->validate()
272 46
                    ->ifTrue(function ($v) {
273 14
                        return !empty($v['additional_response_status']) && !empty($v['match_response']);
274 46
                    })
275 46
                    ->thenInvalid('You may not set both additional_response_status and match_response.')
276 46
                ->end()
277 46
                ->children()
278 46
                    ->scalarNode('path')
279 46
                        ->defaultNull()
280 46
                        ->info('Request path.')
281 46
                    ->end()
282 46
                    ->scalarNode('query_string')
283 46
                        ->defaultNull()
284 46
                        ->info('Request query string.')
285 46
                    ->end()
286 46
                    ->scalarNode('host')
287 46
                        ->defaultNull()
288 46
                        ->info('Request host name.')
289 46
                    ->end()
290 46
                    ->arrayNode('methods')
291 46
                        ->beforeNormalization()->ifString()->then(function ($v) {
292 3
                            return preg_split('/\s*,\s*/', $v);
293 46
                        })->end()
294 46
                        ->useAttributeAsKey('name')
295 46
                        ->prototype('scalar')->end()
296 46
                        ->info('Request HTTP methods.')
297 46
                    ->end()
298 46
                    ->arrayNode('ips')
299 46
                        ->beforeNormalization()->ifString()->then(function ($v) {
300 3
                            return preg_split('/\s*,\s*/', $v);
301 46
                        })->end()
302 46
                        ->useAttributeAsKey('name')
303 46
                        ->prototype('scalar')->end()
304 46
                        ->info('List of client IPs.')
305 46
                    ->end()
306 46
                    ->arrayNode('attributes')
307 46
                        ->useAttributeAsKey('name')
308 46
                        ->prototype('scalar')->end()
309 46
                        ->info('Regular expressions on request attributes.')
310 46
                    ->end()
311
        ;
312 46
        if ($matchResponse) {
313
            $match
314 46
                ->arrayNode('additional_response_status')
315 46
                    ->prototype('scalar')->end()
316 46
                    ->info('Additional response HTTP status codes that will match. Replaces cacheable configuration.')
317 46
                ->end()
318 46
                ->scalarNode('match_response')
319 46
                    ->defaultNull()
320 46
                    ->info('Expression to decide whether response should be matched. Replaces cacheable configuration.')
321 46
                ->end()
322
            ;
323
        }
324 46
    }
325
326 46
    private function addProxyClientSection(ArrayNodeDefinition $rootNode)
327
    {
328
        $rootNode
329 46
            ->children()
330 46
                ->arrayNode('proxy_client')
331 46
                    ->children()
332 46
                        ->enumNode('default')
333 46
                            ->values(['varnish', 'nginx', 'symfony', 'noop'])
334 46
                            ->info('If you configure more than one proxy client, you need to specify which client is the default.')
335 46
                        ->end()
336 46
                        ->arrayNode('varnish')
337 46
                            ->fixXmlConfig('default_ban_header')
338 46
                            ->validate()
339 46
                                ->always(function ($v) {
340 16
                                    if (!count($v['default_ban_headers'])) {
341 15
                                        unset($v['default_ban_headers']);
342
                                    }
343
344 16
                                    return $v;
345 46
                                })
346 46
                            ->end()
347 46
                            ->children()
348 46
                                ->scalarNode('tags_header')
349 46
                                    ->defaultValue(Varnish::DEFAULT_HTTP_HEADER_CACHE_TAGS)
350 46
                                    ->info('HTTP header to use when sending tag invalidation requests to Varnish')
351 46
                                ->end()
352 46
                                ->scalarNode('header_length')
353 46
                                    ->info('Maximum header length when invalidating tags. If there are more tags to invalidate than fit into the header, the invalidation request is split into several requests.')
354 46
                                ->end()
355 46
                                ->arrayNode('default_ban_headers')
356 46
                                    ->useAttributeAsKey('name')
357 46
                                    ->info('Map of additional headers to include in each ban request.')
358 46
                                    ->prototype('scalar')->end()
359 46
                                ->end()
360 46
                                ->append($this->getHttpDispatcherNode())
361 46
                            ->end()
362 46
                        ->end()
363
364 46
                        ->arrayNode('nginx')
365 46
                            ->children()
366 46
                                ->scalarNode('purge_location')
367 46
                                    ->defaultValue(false)
368 46
                                    ->info('Path to trigger the purge on Nginx for different location purge.')
369 46
                                ->end()
370 46
                                ->append($this->getHttpDispatcherNode())
371 46
                            ->end()
372 46
                        ->end()
373
374 46
                        ->arrayNode('symfony')
375 46
                            ->children()
376 46
                                ->scalarNode('tags_header')
377 46
                                    ->defaultValue(PurgeTagsListener::DEFAULT_TAGS_HEADER)
378 46
                                    ->info('HTTP header to use when sending tag invalidation requests to Symfony HttpCache')
379 46
                                ->end()
380 46
                                ->scalarNode('tags_method')
381 46
                                    ->defaultValue(PurgeTagsListener::DEFAULT_TAGS_METHOD)
382 46
                                    ->info('HTTP method for sending tag invalidation requests to Symfony HttpCache')
383 46
                                ->end()
384 46
                                ->scalarNode('header_length')
385 46
                                    ->info('Maximum header length when invalidating tags. If there are more tags to invalidate than fit into the header, the invalidation request is split into several requests.')
386 46
                                ->end()
387 46
                                ->scalarNode('purge_method')
388 46
                                    ->defaultValue(PurgeListener::DEFAULT_PURGE_METHOD)
389 46
                                    ->info('HTTP method to use when sending purge requests to Symfony HttpCache')
390 46
                                ->end()
391 46
                                ->booleanNode('use_kernel_dispatcher')
392 46
                                    ->defaultFalse()
393 46
                                    ->info('Dispatches invalidation requests to the kernel directly instead of executing real HTTP requests. Requires special kernel setup! Refer to the documentation for more information.')
394 46
                                ->end()
395 46
                                ->append($this->getHttpDispatcherNode())
396 46
                            ->end()
397 46
                        ->end()
398
399 46
                        ->booleanNode('noop')->end()
400 46
                    ->end()
401 46
                    ->validate()
402 46
                        ->always()
403 46
                        ->then(function ($config) {
404 26
                            foreach ($config as $proxyName => $proxyConfig) {
405 26
                                $serversConfigured = isset($proxyConfig['http']) && isset($proxyConfig['http']['servers']) && \is_array($proxyConfig['http']['servers']);
406
407 26
                                if (!\in_array($proxyName, ['noop', 'default', 'symfony'])) {
408 19
                                    if (!$serversConfigured) {
409
                                        throw new \InvalidArgumentException(sprintf('The "http.servers" section must be defined for the proxy "%s"', $proxyName));
410
                                    }
411
412 19
                                    return $config;
413
                                }
414
415 7
                                if ('symfony' === $proxyName) {
416 4
                                    if (!$serversConfigured && false === $proxyConfig['use_kernel_dispatcher']) {
417 7
                                        throw new \InvalidArgumentException(sprintf('Either configure the "http.servers" section or enable "use_kernel_dispatcher" the proxy "%s"', $proxyName));
418
                                    }
419
                                }
420
                            }
421
422 6
                            return $config;
423 46
                        })
424 46
                    ->end()
425 46
                ->end()
426 46
            ->end();
427 46
    }
428
429
    /**
430
     * Get the configuration node for a HTTP dispatcher in a proxy client.
431
     *
432
     * @return NodeDefinition
433
     */
434 46
    private function getHttpDispatcherNode()
435
    {
436 46
        $treeBuilder = new TreeBuilder();
437 46
        $node = $treeBuilder->root('http');
438
439
        $node
440 46
            ->fixXmlConfig('server')
441 46
            ->children()
442 46
                ->arrayNode('servers')
443 46
                    ->info('Addresses of the hosts the caching proxy is running on. May be hostname or ip, and with :port if not the default port 80.')
444 46
                    ->useAttributeAsKey('name')
445 46
                    ->isRequired()
446 46
                    ->requiresAtLeastOneElement()
447 46
                    ->prototype('scalar')->end()
448 46
                ->end()
449 46
                ->scalarNode('base_url')
450 46
                    ->defaultNull()
451 46
                    ->info('Default host name and optional path for path based invalidation.')
452 46
                ->end()
453 46
                ->scalarNode('http_client')
454 46
                    ->defaultNull()
455 46
                    ->info('Httplug async client service name to use for sending the requests.')
456 46
                ->end()
457 46
            ->end()
458
        ;
459
460 46
        return $node;
461
    }
462
463 46
    private function addTestSection(ArrayNodeDefinition $rootNode)
464
    {
465
        $rootNode
466 46
            ->children()
467 46
                ->arrayNode('test')
468 46
                    ->children()
469 46
                        ->scalarNode('cache_header')
470 46
                            ->defaultValue('X-Cache')
471 46
                            ->info('HTTP cache hit/miss header')
472 46
                        ->end()
473 46
                        ->arrayNode('proxy_server')
474 46
                            ->info('Configure how caching proxy will be run in your tests')
475 46
                            ->children()
476 46
                                ->enumNode('default')
477 46
                                    ->values(['varnish', 'nginx'])
478 46
                                    ->info('If you configure more than one proxy server, specify which client is the default.')
479 46
                                ->end()
480 46
                                ->arrayNode('varnish')
481 46
                                    ->children()
482 46
                                        ->scalarNode('config_file')->isRequired()->end()
483 46
                                        ->scalarNode('binary')->defaultValue('varnishd')->end()
484 46
                                        ->integerNode('port')->defaultValue(6181)->end()
485 46
                                        ->scalarNode('ip')->defaultValue('127.0.0.1')->end()
486 46
                                    ->end()
487 46
                                ->end()
488 46
                                ->arrayNode('nginx')
489 46
                                    ->children()
490 46
                                        ->scalarNode('config_file')->isRequired()->end()
491 46
                                        ->scalarNode('binary')->defaultValue('nginx')->end()
492 46
                                        ->integerNode('port')->defaultValue(8080)->end()
493 46
                                        ->scalarNode('ip')->defaultValue('127.0.0.1')->end()
494 46
                                    ->end()
495 46
                                ->end()
496 46
                            ->end()
497 46
                        ->end()
498 46
                    ->end()
499 46
                ->end()
500 46
            ->end();
501 46
    }
502
503
    /**
504
     * Cache manager main section.
505
     *
506
     * @param ArrayNodeDefinition $rootNode
507
     */
508 46
    private function addCacheManagerSection(ArrayNodeDefinition $rootNode)
509
    {
510
        $rootNode
511 46
            ->children()
512 46
                ->arrayNode('cache_manager')
513 46
                    ->addDefaultsIfNotSet()
514 46
                    ->beforeNormalization()
515 46
                        ->ifArray()
516 46
                        ->then(function ($v) {
517 8
                            $v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;
518
519 8
                            return $v;
520 46
                        })
521 46
                    ->end()
522 46
                    ->info('Configure the cache manager. Needs a proxy_client to be configured.')
523 46
                    ->children()
524 46
                        ->enumNode('enabled')
525 46
                            ->values([true, false, 'auto'])
526 46
                            ->defaultValue('auto')
527 46
                            ->info('Allows to disable the invalidation manager. Enabled by default if you configure a proxy client.')
528 46
                        ->end()
529 46
                        ->scalarNode('custom_proxy_client')
530 46
                            ->info('Service name of a custom proxy client to use. With a custom client, generate_url_type defaults to ABSOLUTE_URL and tag support needs to be explicitly enabled. If no custom proxy client is specified, the first proxy client you configured is used.')
531 46
                            ->cannotBeEmpty()
532 46
                        ->end()
533 46
                        ->enumNode('generate_url_type')
534 46
                            ->values([
535 46
                                'auto',
536
                                UrlGeneratorInterface::ABSOLUTE_PATH,
537
                                UrlGeneratorInterface::ABSOLUTE_URL,
538
                                UrlGeneratorInterface::NETWORK_PATH,
539
                                UrlGeneratorInterface::RELATIVE_PATH,
540
                            ])
541 46
                            ->defaultValue('auto')
542 46
                            ->info('Set what URLs to generate on invalidate/refresh Route. Auto means path if base_url is set on the default proxy client, full URL otherwise.')
543 46
                        ->end()
544 46
                    ->end()
545
        ;
546 46
    }
547
548 46
    private function addTagSection(ArrayNodeDefinition $rootNode)
549
    {
550
        $rules = $rootNode
551 46
            ->children()
552 46
                ->arrayNode('tags')
553 46
                    ->addDefaultsIfNotSet()
554 46
                    ->fixXmlConfig('rule')
555 46
                    ->children()
556 46
                        ->enumNode('enabled')
557 46
                            ->values([true, false, 'auto'])
558 46
                            ->defaultValue('auto')
559 46
                            ->info('Allows to disable the event subscriber for tag configuration and annotations when your project does not use the annotations. Enabled by default if you configured the cache manager.')
560 46
                        ->end()
561 46
                        ->booleanNode('strict')->defaultFalse()->end()
562 46
                        ->scalarNode('expression_language')
563 46
                            ->defaultNull()
564 46
                            ->info('Service name of a custom ExpressionLanugage to use.')
565 46
                        ->end()
566 46
                        ->scalarNode('response_header')
567 46
                            ->defaultValue(TagHeaderFormatter::DEFAULT_HEADER_NAME)
568 46
                            ->info('HTTP header that contains cache tags')
569 46
                        ->end()
570 46
                        ->arrayNode('rules')
571 46
                            ->prototype('array')
572 46
                                ->fixXmlConfig('tag')
573 46
                                ->fixXmlConfig('tag_expression')
574 46
                                ->validate()
575 46
                                    ->ifTrue(function ($v) {
576 4
                                        return !empty($v['tag_expressions']) && !class_exists(ExpressionLanguage::class);
577 46
                                    })
578 46
                                    ->thenInvalid('Configured a tag_expression but ExpressionLanugage is not available')
579 46
                                ->end()
580 46
                                ->children();
581
582 46
        $this->addMatch($rules);
583
584
        $rules
585 46
            ->arrayNode('tags')
586 46
                ->prototype('scalar')
587 46
                ->info('Tags to add to the response on safe requests, to invalidate on unsafe requests')
588 46
            ->end()->end()
589 46
            ->arrayNode('tag_expressions')
590 46
                ->prototype('scalar')
591 46
                ->info('Tags to add to the response on safe requests, to invalidate on unsafe requests')
592 46
            ->end()
593
        ;
594 46
    }
595
596 46
    private function addInvalidationSection(ArrayNodeDefinition $rootNode)
597
    {
598
        $rules = $rootNode
599 46
            ->children()
600 46
                ->arrayNode('invalidation')
601 46
                    ->fixXmlConfig('rule')
602 46
                    ->addDefaultsIfNotSet()
603 46
                    ->children()
604 46
                        ->enumNode('enabled')
605 46
                            ->values([true, false, 'auto'])
606 46
                            ->defaultValue('auto')
607 46
                            ->info('Allows to disable the listener for invalidation. Enabled by default if the cache manager is configured. When disabled, the cache manager is no longer flushed automatically.')
608 46
                        ->end()
609 46
                        ->scalarNode('expression_language')
610 46
                            ->defaultNull()
611 46
                            ->info('Service name of a custom ExpressionLanugage to use.')
612 46
                        ->end()
613 46
                        ->arrayNode('rules')
614 46
                            ->info('Set what requests should invalidate which target routes.')
615 46
                            ->prototype('array')
616 46
                                ->fixXmlConfig('route')
617 46
                                ->children();
618
619 46
        $this->addMatch($rules);
620
        $rules
621 46
            ->arrayNode('routes')
622 46
                ->isRequired()
623 46
                ->requiresAtLeastOneElement()
624 46
                ->useAttributeAsKey('name')
625 46
                ->info('Target routes to invalidate when request is matched')
626 46
                ->prototype('array')
627 46
                    ->children()
628 46
                        ->booleanNode('ignore_extra_params')->defaultTrue()->end()
629 46
                    ->end()
630 46
                ->end()
631 46
            ->end();
632 46
    }
633
634
    /**
635
     * User context main section.
636
     *
637
     * @param ArrayNodeDefinition $rootNode
638
     */
639 46
    private function addUserContextListenerSection(ArrayNodeDefinition $rootNode)
640
    {
641
        $rootNode
642 46
            ->children()
643 46
                ->arrayNode('user_context')
644 46
                    ->info('Listener that returns the request for the user context hash as early as possible.')
645 46
                    ->addDefaultsIfNotSet()
646 46
                    ->canBeEnabled()
647 46
                    ->fixXmlConfig('user_identifier_header')
648 46
                    ->children()
649 46
                        ->arrayNode('match')
650 46
                            ->addDefaultsIfNotSet()
651 46
                            ->children()
652 46
                                ->scalarNode('matcher_service')
653 46
                                    ->defaultValue('fos_http_cache.user_context.request_matcher')
654 46
                                    ->info('Service id of a request matcher that tells whether the request is a context hash request.')
655 46
                                ->end()
656 46
                                ->scalarNode('accept')
657 46
                                    ->defaultValue('application/vnd.fos.user-context-hash')
658 46
                                    ->info('Specify the accept HTTP header used for context hash requests.')
659 46
                                ->end()
660 46
                                ->scalarNode('method')
661 46
                                    ->defaultNull()
662 46
                                    ->info('Specify the HTTP method used for context hash requests.')
663 46
                                ->end()
664 46
                            ->end()
665 46
                        ->end()
666 46
                        ->scalarNode('hash_cache_ttl')
667 46
                            ->defaultValue(0)
668 46
                            ->info('Cache the response for the hash for the specified number of seconds. Setting this to 0 will not cache those responses at all.')
669 46
                        ->end()
670 46
                        ->booleanNode('always_vary_on_context_hash')
671 46
                            ->defaultTrue()
672 46
                            ->info('Whether to always add the user context hash header name in the response Vary header.')
673 46
                        ->end()
674 46
                        ->arrayNode('user_identifier_headers')
675 46
                            ->prototype('scalar')->end()
676 46
                            ->defaultValue(['Cookie', 'Authorization'])
677 46
                            ->info('List of headers that contain the unique identifier for the user in the hash request.')
678 46
                        ->end()
679 46
                        ->scalarNode('session_name_prefix')
680 46
                            ->defaultValue(false)
681 46
                            ->info('Prefix for session cookies. Must match your PHP session configuration. Set to false to ignore the session in user context.')
682 46
                        ->end()
683 46
                        ->scalarNode('user_hash_header')
684 46
                            ->defaultValue('X-User-Context-Hash')
685 46
                            ->info('Name of the header that contains the hash information for the context.')
686 46
                        ->end()
687 46
                        ->booleanNode('role_provider')
688 46
                            ->defaultFalse()
689 46
                            ->info('Whether to enable a provider that automatically adds all roles of the current user to the context.')
690 46
                        ->end()
691 46
                        ->arrayNode('logout_handler')
692 46
                            ->addDefaultsIfNotSet()
693 46
                            ->canBeEnabled()
694 46
                            ->children()
695 46
                                ->enumNode('enabled')
696 46
                                    ->values([true, false, 'auto'])
697 46
                                    ->defaultValue('auto')
698 46
                                    ->info('Whether to enable the user context logout handler.')
699 46
                                ->end()
700 46
                            ->end()
701 46
                        ->end()
702 46
                    ->end()
703 46
                ->end()
704 46
            ->end()
705
        ;
706 46
    }
707
708 46
    private function addFlashMessageSection(ArrayNodeDefinition $rootNode)
709
    {
710
        $rootNode
711 46
            ->children()
712 46
                ->arrayNode('flash_message')
713 46
                    ->canBeUnset()
714 46
                    ->canBeEnabled()
715 46
                    ->info('Activate the flash message listener that puts flash messages into a cookie.')
716 46
                    ->children()
717 46
                        ->scalarNode('name')
718 46
                            ->defaultValue('flashes')
719 46
                            ->info('Name of the cookie to set for flashes.')
720 46
                        ->end()
721 46
                        ->scalarNode('path')
722 46
                            ->defaultValue('/')
723 46
                            ->info('Cookie path validity.')
724 46
                        ->end()
725 46
                        ->scalarNode('host')
726 46
                            ->defaultNull()
727 46
                            ->info('Cookie host name validity.')
728 46
                        ->end()
729 46
                        ->scalarNode('secure')
730 46
                            ->defaultFalse()
731 46
                            ->info('Whether the cookie should only be transmitted over a secure HTTPS connection from the client.')
732 46
                        ->end()
733 46
                    ->end()
734 46
                ->end()
735 46
            ->end();
736 46
    }
737
738 46
    private function addDebugSection(ArrayNodeDefinition $rootNode)
739
    {
740
        $rootNode
741 46
            ->children()
742 46
                ->arrayNode('debug')
743 46
                ->addDefaultsIfNotSet()
744 46
                ->canBeEnabled()
745 46
                ->children()
746 46
                    ->booleanNode('enabled')
747 46
                        ->defaultValue($this->debug)
748 46
                        ->info('Whether to send a debug header with the response to trigger a caching proxy to send debug information. If not set, defaults to kernel.debug.')
749 46
                    ->end()
750 46
                    ->scalarNode('header')
751 46
                        ->defaultValue('X-Cache-Debug')
752 46
                        ->info('The header to send if debug is true.')
753 46
                    ->end()
754 46
                ->end()
755 46
            ->end()
756 46
        ->end();
757 46
    }
758
}
759