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