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