Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Configuration often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Configuration, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
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 | 60 | public function __construct($debug) |
|
50 | |||
51 | /** |
||
52 | * {@inheritdoc} |
||
53 | */ |
||
54 | 60 | public function getConfigTreeBuilder() |
|
55 | { |
||
56 | 60 | $treeBuilder = new TreeBuilder('fos_http_cache'); |
|
57 | |||
58 | // Keep compatibility with symfony/config < 4.2 |
||
59 | 60 | if (!method_exists($treeBuilder, 'getRootNode')) { |
|
60 | $rootNode = $treeBuilder->root('fos_http_cache'); |
||
|
|||
61 | } else { |
||
62 | 60 | $rootNode = $treeBuilder->getRootNode(); |
|
63 | } |
||
64 | |||
65 | $rootNode |
||
66 | 60 | ->validate() |
|
67 | ->ifTrue(function ($v) { |
||
68 | 58 | return $v['cache_manager']['enabled'] |
|
69 | 58 | && !isset($v['proxy_client']) |
|
70 | 58 | && !isset($v['cache_manager']['custom_proxy_client']) |
|
71 | ; |
||
72 | 60 | }) |
|
73 | View Code Duplication | ->then(function ($v) { |
|
74 | 17 | if ('auto' === $v['cache_manager']['enabled']) { |
|
75 | 16 | $v['cache_manager']['enabled'] = false; |
|
76 | |||
77 | 16 | return $v; |
|
78 | } |
||
79 | |||
80 | 1 | throw new InvalidConfigurationException('You need to configure a proxy_client or specify a custom_proxy_client to use the cache_manager.'); |
|
81 | 60 | }) |
|
82 | 60 | ->end() |
|
83 | 60 | ->validate() |
|
84 | ->ifTrue(function ($v) { |
||
85 | 57 | return $v['tags']['enabled'] && !$v['cache_manager']['enabled']; |
|
86 | 60 | }) |
|
87 | View Code Duplication | ->then(function ($v) { |
|
88 | 18 | if ('auto' === $v['tags']['enabled']) { |
|
89 | 17 | $v['tags']['enabled'] = false; |
|
90 | |||
91 | 17 | return $v; |
|
92 | } |
||
93 | |||
94 | 1 | throw new InvalidConfigurationException('You need to configure a proxy_client to get the cache_manager needed for tag handling.'); |
|
95 | 60 | }) |
|
96 | 60 | ->end() |
|
97 | 60 | ->validate() |
|
98 | ->ifTrue(function ($v) { |
||
99 | 56 | return $v['invalidation']['enabled'] && !$v['cache_manager']['enabled']; |
|
100 | 60 | }) |
|
101 | View Code Duplication | ->then(function ($v) { |
|
102 | 17 | if ('auto' === $v['invalidation']['enabled']) { |
|
103 | 16 | $v['invalidation']['enabled'] = false; |
|
104 | |||
105 | 16 | return $v; |
|
106 | } |
||
107 | |||
108 | 1 | throw new InvalidConfigurationException('You need to configure a proxy_client to get the cache_manager needed for invalidation handling.'); |
|
109 | 60 | }) |
|
110 | 60 | ->end() |
|
111 | 60 | ->validate() |
|
112 | 60 | ->ifTrue( |
|
113 | function ($v) { |
||
114 | 55 | return false !== $v['user_context']['logout_handler']['enabled']; |
|
115 | 60 | } |
|
116 | ) |
||
117 | ->then(function ($v) { |
||
118 | 54 | if (isset($v['cache_manager']['custom_proxy_client'])) { |
|
119 | 5 | $v['user_context']['logout_handler']['enabled'] = true; |
|
120 | |||
121 | 5 | return $v; |
|
122 | } |
||
123 | |||
124 | 49 | if (isset($v['proxy_client']['default']) |
|
125 | 49 | && in_array($v['proxy_client']['default'], ['varnish', 'symfony', 'noop']) |
|
126 | ) { |
||
127 | $v['user_context']['logout_handler']['enabled'] = true; |
||
128 | |||
129 | return $v; |
||
130 | } |
||
131 | 49 | if (isset($v['proxy_client']['varnish']) |
|
132 | 26 | || isset($v['proxy_client']['symfony']) |
|
133 | 49 | || isset($v['proxy_client']['noop']) |
|
134 | ) { |
||
135 | 28 | $v['user_context']['logout_handler']['enabled'] = true; |
|
136 | |||
137 | 28 | return $v; |
|
138 | } |
||
139 | |||
140 | 21 | if ('auto' === $v['user_context']['logout_handler']['enabled']) { |
|
141 | 19 | $v['user_context']['logout_handler']['enabled'] = false; |
|
142 | |||
143 | 19 | return $v; |
|
144 | } |
||
145 | |||
146 | 2 | throw new InvalidConfigurationException('To enable the user context logout handler, you need to configure a tag capable proxy_client (varnish, symfony, noop or custom_proxy_client).'); |
|
147 | 60 | }) |
|
148 | 60 | ->end() |
|
149 | // Determine the default tags header for the varnish client, depending on whether we use BAN or xkey |
||
150 | 60 | ->validate() |
|
151 | 60 | ->ifTrue( |
|
152 | View Code Duplication | function ($v) { |
|
153 | return |
||
154 | 53 | array_key_exists('proxy_client', $v) |
|
155 | 53 | && array_key_exists('varnish', $v['proxy_client']) |
|
156 | 53 | && empty($v['proxy_client']['varnish']['tags_header']) |
|
157 | ; |
||
158 | 60 | } |
|
159 | ) |
||
160 | ->then(function ($v) { |
||
161 | 20 | $v['proxy_client']['varnish']['tags_header'] = |
|
162 | 20 | (Varnish::TAG_XKEY === $v['proxy_client']['varnish']['tag_mode']) |
|
163 | 1 | ? Varnish::DEFAULT_HTTP_HEADER_CACHE_XKEY |
|
164 | 19 | : Varnish::DEFAULT_HTTP_HEADER_CACHE_TAGS; |
|
165 | |||
166 | 20 | return $v; |
|
167 | 60 | }) |
|
168 | 60 | ->end() |
|
169 | // Determine the default tag response header, depending on whether we use BAN or xkey |
||
170 | 60 | ->validate() |
|
171 | 60 | ->ifTrue( |
|
172 | function ($v) { |
||
173 | 53 | return empty($v['tags']['response_header']); |
|
174 | 60 | } |
|
175 | ) |
||
176 | ->then(function ($v) { |
||
177 | 49 | $v['tags']['response_header'] = $this->isVarnishXkey($v) ? 'xkey' : TagHeaderFormatter::DEFAULT_HEADER_NAME; |
|
178 | |||
179 | 49 | return $v; |
|
180 | 60 | }) |
|
181 | 60 | ->end() |
|
182 | // Determine the default separator for the tags header, depending on whether we use BAN or xkey |
||
183 | 60 | ->validate() |
|
184 | 60 | ->ifTrue( |
|
185 | function ($v) { |
||
186 | 53 | return empty($v['tags']['separator']); |
|
187 | 60 | } |
|
188 | ) |
||
189 | ->then(function ($v) { |
||
190 | 50 | $v['tags']['separator'] = $this->isVarnishXkey($v) ? ' ' : ','; |
|
191 | |||
192 | 50 | return $v; |
|
193 | 60 | }) |
|
194 | ; |
||
195 | |||
196 | 60 | $this->addCacheableResponseSection($rootNode); |
|
197 | 60 | $this->addCacheControlSection($rootNode); |
|
198 | 60 | $this->addProxyClientSection($rootNode); |
|
199 | 60 | $this->addCacheManagerSection($rootNode); |
|
200 | 60 | $this->addTagSection($rootNode); |
|
201 | 60 | $this->addInvalidationSection($rootNode); |
|
202 | 60 | $this->addUserContextListenerSection($rootNode); |
|
203 | 60 | $this->addFlashMessageSection($rootNode); |
|
204 | 60 | $this->addTestSection($rootNode); |
|
205 | 60 | $this->addDebugSection($rootNode); |
|
206 | |||
207 | 60 | return $treeBuilder; |
|
208 | } |
||
209 | |||
210 | 50 | View Code Duplication | private function isVarnishXkey(array $v): bool |
217 | |||
218 | 60 | private function addCacheableResponseSection(ArrayNodeDefinition $rootNode) |
|
219 | { |
||
220 | $rootNode |
||
221 | 60 | ->children() |
|
222 | 60 | ->arrayNode('cacheable') |
|
223 | 60 | ->addDefaultsIfNotSet() |
|
224 | 60 | ->children() |
|
225 | 60 | ->arrayNode('response') |
|
226 | 60 | ->addDefaultsIfNotSet() |
|
227 | 60 | ->children() |
|
228 | 60 | ->arrayNode('additional_status') |
|
229 | 60 | ->prototype('scalar')->end() |
|
230 | 60 | ->info('Additional response HTTP status codes that will be considered cacheable.') |
|
231 | 60 | ->end() |
|
232 | 60 | ->scalarNode('expression') |
|
233 | 60 | ->defaultNull() |
|
234 | 60 | ->info('Expression to decide whether response is cacheable. Replaces the default status codes.') |
|
235 | 60 | ->end() |
|
236 | 60 | ->end() |
|
237 | |||
238 | 60 | ->validate() |
|
239 | ->ifTrue(function ($v) { |
||
240 | 6 | return !empty($v['additional_status']) && !empty($v['expression']); |
|
241 | 60 | }) |
|
242 | 60 | ->thenInvalid('You may not set both additional_status and expression.') |
|
243 | 60 | ->end() |
|
244 | 60 | ->end() |
|
245 | 60 | ->end() |
|
246 | 60 | ->end(); |
|
247 | 60 | } |
|
248 | |||
249 | /** |
||
250 | * Cache header control main section. |
||
251 | * |
||
252 | * @param ArrayNodeDefinition $rootNode |
||
253 | */ |
||
254 | 60 | private function addCacheControlSection(ArrayNodeDefinition $rootNode) |
|
255 | { |
||
256 | $rules = $rootNode |
||
257 | 60 | ->children() |
|
258 | 60 | ->arrayNode('cache_control') |
|
259 | 60 | ->fixXmlConfig('rule') |
|
260 | 60 | ->children() |
|
261 | 60 | ->arrayNode('defaults') |
|
262 | 60 | ->addDefaultsIfNotSet() |
|
263 | 60 | ->children() |
|
264 | 60 | ->booleanNode('overwrite') |
|
265 | 60 | ->info('Whether to overwrite existing cache headers') |
|
266 | 60 | ->defaultFalse() |
|
267 | 60 | ->end() |
|
268 | 60 | ->end() |
|
269 | 60 | ->end() |
|
270 | 60 | ->arrayNode('rules') |
|
271 | 60 | ->prototype('array') |
|
272 | 60 | ->children(); |
|
273 | |||
274 | 60 | $this->addMatch($rules, true); |
|
275 | $rules |
||
276 | 60 | ->arrayNode('headers') |
|
277 | 60 | ->isRequired() |
|
278 | // todo validate there is some header defined |
||
279 | 60 | ->children() |
|
280 | 60 | ->enumNode('overwrite') |
|
281 | 60 | ->info('Whether to overwrite cache headers for this rule, defaults to the cache_control.defaults.overwrite setting') |
|
282 | 60 | ->values(['default', true, false]) |
|
283 | 60 | ->defaultValue('default') |
|
284 | 60 | ->end() |
|
285 | 60 | ->arrayNode('cache_control') |
|
286 | 60 | ->info('Add the specified cache control directives.') |
|
287 | 60 | ->children() |
|
288 | 60 | ->scalarNode('max_age')->end() |
|
289 | 60 | ->scalarNode('s_maxage')->end() |
|
290 | 60 | ->booleanNode('private')->end() |
|
291 | 60 | ->booleanNode('public')->end() |
|
292 | 60 | ->booleanNode('must_revalidate')->end() |
|
293 | 60 | ->booleanNode('proxy_revalidate')->end() |
|
294 | 60 | ->booleanNode('no_transform')->end() |
|
295 | 60 | ->booleanNode('no_cache')->end() |
|
296 | 60 | ->booleanNode('no_store')->end() |
|
297 | 60 | ->scalarNode('stale_if_error')->end() |
|
298 | 60 | ->scalarNode('stale_while_revalidate')->end() |
|
299 | 60 | ->end() |
|
300 | 60 | ->end() |
|
301 | 60 | ->enumNode('etag') |
|
302 | 60 | ->defaultValue(false) |
|
303 | 60 | ->treatTrueLike('strong') |
|
304 | 60 | ->info('Set a simple ETag which is just the md5 hash of the response body. '. |
|
305 | 60 | 'You can specify which type of ETag you want by passing "strong" or "weak".') |
|
306 | 60 | ->values(['weak', 'strong', false]) |
|
307 | 60 | ->end() |
|
308 | 60 | ->scalarNode('last_modified') |
|
309 | 60 | ->validate() |
|
310 | ->ifTrue(function ($v) { |
||
311 | 2 | if (is_string($v)) { |
|
312 | 2 | new \DateTime($v); |
|
313 | } |
||
314 | |||
315 | 1 | return false; |
|
316 | 60 | }) |
|
317 | 60 | ->thenInvalid('') // this will never happen as new DateTime will throw an exception if $v is no date |
|
318 | 60 | ->end() |
|
319 | 60 | ->info('Set a default last modified timestamp if none is set yet. Value must be parseable by DateTime') |
|
320 | 60 | ->end() |
|
321 | 60 | ->scalarNode('reverse_proxy_ttl') |
|
322 | 60 | ->defaultNull() |
|
323 | 60 | ->info('Specify an X-Reverse-Proxy-TTL header with a time in seconds for a caching proxy under your control.') |
|
324 | 60 | ->end() |
|
325 | 60 | ->arrayNode('vary') |
|
326 | ->beforeNormalization()->ifString()->then(function ($v) { |
||
327 | 2 | return preg_split('/\s*,\s*/', $v); |
|
328 | 60 | })->end() |
|
329 | 60 | ->prototype('scalar')->end() |
|
330 | 60 | ->info('Define a list of additional headers on which the response varies.') |
|
331 | 60 | ->end() |
|
332 | 60 | ->end() |
|
333 | 60 | ->end() |
|
334 | ; |
||
335 | 60 | } |
|
336 | |||
337 | /** |
||
338 | * Shared configuration between cache control, tags and invalidation. |
||
339 | * |
||
340 | * @param NodeBuilder $rules |
||
341 | * @param bool $matchResponse whether to also add fields to match response |
||
342 | */ |
||
343 | 60 | private function addMatch(NodeBuilder $rules, $matchResponse = false) |
|
344 | { |
||
345 | $match = $rules |
||
346 | 60 | ->arrayNode('match') |
|
347 | 60 | ->cannotBeOverwritten() |
|
348 | 60 | ->isRequired() |
|
349 | 60 | ->fixXmlConfig('method') |
|
350 | 60 | ->fixXmlConfig('ip') |
|
351 | 60 | ->fixXmlConfig('attribute') |
|
352 | 60 | ->validate() |
|
353 | ->ifTrue(function ($v) { |
||
354 | 14 | return !empty($v['additional_response_status']) && !empty($v['match_response']); |
|
355 | 60 | }) |
|
356 | 60 | ->thenInvalid('You may not set both additional_response_status and match_response.') |
|
357 | 60 | ->end() |
|
358 | 60 | ->children() |
|
359 | 60 | ->scalarNode('path') |
|
360 | 60 | ->defaultNull() |
|
361 | 60 | ->info('Request path.') |
|
362 | 60 | ->end() |
|
363 | 60 | ->scalarNode('query_string') |
|
364 | 60 | ->defaultNull() |
|
365 | 60 | ->info('Request query string.') |
|
366 | 60 | ->end() |
|
367 | 60 | ->scalarNode('host') |
|
368 | 60 | ->defaultNull() |
|
369 | 60 | ->info('Request host name.') |
|
370 | 60 | ->end() |
|
371 | 60 | ->arrayNode('methods') |
|
372 | ->beforeNormalization()->ifString()->then(function ($v) { |
||
373 | 3 | return preg_split('/\s*,\s*/', $v); |
|
374 | 60 | })->end() |
|
375 | 60 | ->useAttributeAsKey('name') |
|
376 | 60 | ->prototype('scalar')->end() |
|
377 | 60 | ->info('Request HTTP methods.') |
|
378 | 60 | ->end() |
|
379 | 60 | ->arrayNode('ips') |
|
380 | ->beforeNormalization()->ifString()->then(function ($v) { |
||
381 | 3 | return preg_split('/\s*,\s*/', $v); |
|
382 | 60 | })->end() |
|
383 | 60 | ->useAttributeAsKey('name') |
|
384 | 60 | ->prototype('scalar')->end() |
|
385 | 60 | ->info('List of client IPs.') |
|
386 | 60 | ->end() |
|
387 | 60 | ->arrayNode('attributes') |
|
388 | 60 | ->useAttributeAsKey('name') |
|
389 | 60 | ->prototype('scalar')->end() |
|
390 | 60 | ->info('Regular expressions on request attributes.') |
|
391 | 60 | ->end() |
|
392 | ; |
||
393 | 60 | if ($matchResponse) { |
|
394 | $match |
||
395 | 60 | ->arrayNode('additional_response_status') |
|
396 | 60 | ->prototype('scalar')->end() |
|
397 | 60 | ->info('Additional response HTTP status codes that will match. Replaces cacheable configuration.') |
|
398 | 60 | ->end() |
|
399 | 60 | ->scalarNode('match_response') |
|
400 | 60 | ->defaultNull() |
|
401 | 60 | ->info('Expression to decide whether response should be matched. Replaces cacheable configuration.') |
|
402 | 60 | ->end() |
|
403 | ; |
||
404 | } |
||
405 | 60 | } |
|
406 | |||
407 | 60 | private function addProxyClientSection(ArrayNodeDefinition $rootNode) |
|
408 | { |
||
409 | $rootNode |
||
410 | 60 | ->children() |
|
411 | 60 | ->arrayNode('proxy_client') |
|
412 | 60 | ->children() |
|
413 | 60 | ->enumNode('default') |
|
414 | 60 | ->values(['varnish', 'nginx', 'symfony', 'noop']) |
|
415 | 60 | ->info('If you configure more than one proxy client, you need to specify which client is the default.') |
|
416 | 60 | ->end() |
|
417 | 60 | ->arrayNode('varnish') |
|
418 | 60 | ->fixXmlConfig('default_ban_header') |
|
419 | 60 | ->validate() |
|
420 | ->always(function ($v) { |
||
421 | 24 | if (!count($v['default_ban_headers'])) { |
|
422 | 23 | unset($v['default_ban_headers']); |
|
423 | } |
||
424 | |||
425 | 24 | return $v; |
|
426 | 60 | }) |
|
427 | 60 | ->end() |
|
428 | 60 | ->children() |
|
429 | 60 | ->scalarNode('tags_header') |
|
430 | 60 | ->info('HTTP header to use when sending tag invalidation requests to Varnish') |
|
431 | 60 | ->end() |
|
432 | 60 | ->scalarNode('header_length') |
|
433 | 60 | ->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.') |
|
434 | 60 | ->end() |
|
435 | 60 | ->arrayNode('default_ban_headers') |
|
436 | 60 | ->useAttributeAsKey('name') |
|
437 | 60 | ->info('Map of additional headers to include in each ban request.') |
|
438 | 60 | ->prototype('scalar')->end() |
|
439 | 60 | ->end() |
|
440 | 60 | ->enumNode('tag_mode') |
|
441 | 60 | ->info('If you can enable the xkey module in Varnish, use the purgekeys mode for more efficient tag handling') |
|
442 | 60 | ->values(['ban', 'purgekeys']) |
|
443 | 60 | ->defaultValue('ban') |
|
444 | 60 | ->end() |
|
445 | 60 | ->append($this->getHttpDispatcherNode()) |
|
446 | 60 | ->end() |
|
447 | 60 | ->end() |
|
448 | |||
449 | 60 | ->arrayNode('nginx') |
|
450 | 60 | ->children() |
|
451 | 60 | ->scalarNode('purge_location') |
|
452 | 60 | ->defaultValue(false) |
|
453 | 60 | ->info('Path to trigger the purge on Nginx for different location purge.') |
|
454 | 60 | ->end() |
|
455 | 60 | ->append($this->getHttpDispatcherNode()) |
|
456 | 60 | ->end() |
|
457 | 60 | ->end() |
|
458 | |||
459 | 60 | ->arrayNode('symfony') |
|
460 | 60 | ->children() |
|
461 | 60 | ->scalarNode('tags_header') |
|
462 | 60 | ->defaultValue(PurgeTagsListener::DEFAULT_TAGS_HEADER) |
|
463 | 60 | ->info('HTTP header to use when sending tag invalidation requests to Symfony HttpCache') |
|
464 | 60 | ->end() |
|
465 | 60 | ->scalarNode('tags_method') |
|
466 | 60 | ->defaultValue(PurgeTagsListener::DEFAULT_TAGS_METHOD) |
|
467 | 60 | ->info('HTTP method for sending tag invalidation requests to Symfony HttpCache') |
|
468 | 60 | ->end() |
|
469 | 60 | ->scalarNode('header_length') |
|
470 | 60 | ->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.') |
|
471 | 60 | ->end() |
|
472 | 60 | ->scalarNode('purge_method') |
|
473 | 60 | ->defaultValue(PurgeListener::DEFAULT_PURGE_METHOD) |
|
474 | 60 | ->info('HTTP method to use when sending purge requests to Symfony HttpCache') |
|
475 | 60 | ->end() |
|
476 | 60 | ->booleanNode('use_kernel_dispatcher') |
|
477 | 60 | ->defaultFalse() |
|
478 | 60 | ->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.') |
|
479 | 60 | ->end() |
|
480 | 60 | ->append($this->getHttpDispatcherNode()) |
|
481 | 60 | ->end() |
|
482 | 60 | ->end() |
|
483 | |||
484 | 60 | ->booleanNode('noop')->end() |
|
485 | 60 | ->end() |
|
486 | 60 | ->validate() |
|
487 | 60 | ->always() |
|
488 | ->then(function ($config) { |
||
489 | 36 | foreach ($config as $proxyName => $proxyConfig) { |
|
490 | 36 | $serversConfigured = isset($proxyConfig['http']) && isset($proxyConfig['http']['servers']) && \is_array($proxyConfig['http']['servers']); |
|
491 | |||
492 | 36 | if (!\in_array($proxyName, ['noop', 'default', 'symfony'])) { |
|
493 | 29 | if (!$serversConfigured) { |
|
494 | throw new \InvalidArgumentException(sprintf('The "http.servers" section must be defined for the proxy "%s"', $proxyName)); |
||
495 | } |
||
496 | |||
497 | 29 | return $config; |
|
498 | } |
||
499 | |||
500 | 7 | if ('symfony' === $proxyName) { |
|
501 | 4 | if (!$serversConfigured && false === $proxyConfig['use_kernel_dispatcher']) { |
|
502 | 1 | throw new \InvalidArgumentException('Either configure the "http.servers" section or enable "proxy_client.symfony.use_kernel_dispatcher"'); |
|
503 | } |
||
504 | } |
||
505 | } |
||
506 | |||
507 | 6 | return $config; |
|
508 | 60 | }) |
|
509 | 60 | ->end() |
|
510 | 60 | ->end() |
|
511 | 60 | ->end(); |
|
512 | 60 | } |
|
513 | |||
514 | /** |
||
515 | * Get the configuration node for a HTTP dispatcher in a proxy client. |
||
516 | * |
||
517 | * @return NodeDefinition |
||
518 | */ |
||
519 | 60 | private function getHttpDispatcherNode() |
|
520 | { |
||
521 | 60 | $treeBuilder = new TreeBuilder('http'); |
|
522 | |||
523 | // Keep compatibility with symfony/config < 4.2 |
||
524 | 60 | if (!method_exists($treeBuilder, 'getRootNode')) { |
|
525 | $node = $treeBuilder->root('http'); |
||
526 | } else { |
||
527 | 60 | $node = $treeBuilder->getRootNode(); |
|
528 | } |
||
529 | |||
530 | $node |
||
531 | 60 | ->fixXmlConfig('server') |
|
532 | 60 | ->children() |
|
533 | 60 | ->arrayNode('servers') |
|
534 | 60 | ->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.') |
|
535 | 60 | ->useAttributeAsKey('name') |
|
536 | 60 | ->isRequired() |
|
537 | 60 | ->requiresAtLeastOneElement() |
|
538 | 60 | ->prototype('scalar')->end() |
|
539 | 60 | ->end() |
|
540 | 60 | ->scalarNode('base_url') |
|
541 | 60 | ->defaultNull() |
|
542 | 60 | ->info('Default host name and optional path for path based invalidation.') |
|
543 | 60 | ->end() |
|
544 | 60 | ->scalarNode('http_client') |
|
545 | 60 | ->defaultNull() |
|
546 | 60 | ->info('Httplug async client service name to use for sending the requests.') |
|
547 | 60 | ->end() |
|
548 | 60 | ->end() |
|
549 | ; |
||
550 | |||
551 | 60 | return $node; |
|
552 | } |
||
553 | |||
554 | 60 | private function addTestSection(ArrayNodeDefinition $rootNode) |
|
593 | |||
594 | /** |
||
595 | * Cache manager main section. |
||
596 | * |
||
597 | * @param ArrayNodeDefinition $rootNode |
||
598 | */ |
||
599 | 60 | private function addCacheManagerSection(ArrayNodeDefinition $rootNode) |
|
600 | { |
||
601 | $rootNode |
||
602 | 60 | ->children() |
|
603 | 60 | ->arrayNode('cache_manager') |
|
604 | 60 | ->addDefaultsIfNotSet() |
|
605 | 60 | ->beforeNormalization() |
|
606 | 60 | ->ifArray() |
|
607 | ->then(function ($v) { |
||
608 | 10 | $v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true; |
|
609 | |||
610 | 10 | return $v; |
|
611 | 60 | }) |
|
612 | 60 | ->end() |
|
613 | 60 | ->info('Configure the cache manager. Needs a proxy_client to be configured.') |
|
614 | 60 | ->children() |
|
615 | 60 | ->enumNode('enabled') |
|
616 | 60 | ->values([true, false, 'auto']) |
|
617 | 60 | ->defaultValue('auto') |
|
618 | 60 | ->info('Allows to disable the invalidation manager. Enabled by default if you configure a proxy client.') |
|
619 | 60 | ->end() |
|
620 | 60 | ->scalarNode('custom_proxy_client') |
|
621 | 60 | ->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.') |
|
622 | 60 | ->cannotBeEmpty() |
|
623 | 60 | ->end() |
|
624 | 60 | ->enumNode('generate_url_type') |
|
625 | 60 | ->values([ |
|
626 | 60 | 'auto', |
|
627 | UrlGeneratorInterface::ABSOLUTE_PATH, |
||
628 | UrlGeneratorInterface::ABSOLUTE_URL, |
||
629 | UrlGeneratorInterface::NETWORK_PATH, |
||
630 | UrlGeneratorInterface::RELATIVE_PATH, |
||
631 | ]) |
||
632 | 60 | ->defaultValue('auto') |
|
633 | 60 | ->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.') |
|
634 | 60 | ->end() |
|
635 | 60 | ->end() |
|
636 | ; |
||
637 | 60 | } |
|
638 | |||
639 | 60 | private function addTagSection(ArrayNodeDefinition $rootNode) |
|
640 | { |
||
641 | $rules = $rootNode |
||
642 | 60 | ->children() |
|
643 | 60 | ->arrayNode('tags') |
|
644 | 60 | ->addDefaultsIfNotSet() |
|
645 | 60 | ->fixXmlConfig('rule') |
|
646 | 60 | ->children() |
|
647 | 60 | ->enumNode('enabled') |
|
648 | 60 | ->values([true, false, 'auto']) |
|
649 | 60 | ->defaultValue('auto') |
|
650 | 60 | ->info('Allows to disable tag support. Enabled by default if you configured the cache manager and have a proxy client that supports tagging.') |
|
651 | 60 | ->end() |
|
652 | 60 | ->arrayNode('annotations') |
|
653 | 60 | ->info('Annotations require the FrameworkExtraBundle. Because we can not detect whether annotations are used when the FrameworkExtraBundle is not available, this option must be set to false explicitly if the application does not use annotations.') |
|
654 | 60 | ->canBeDisabled() |
|
655 | 60 | ->end() |
|
656 | 60 | ->booleanNode('strict')->defaultFalse()->end() |
|
657 | 60 | ->scalarNode('expression_language') |
|
658 | 60 | ->defaultNull() |
|
659 | 60 | ->info('Service name of a custom ExpressionLanugage to use.') |
|
660 | 60 | ->end() |
|
661 | 60 | ->scalarNode('response_header') |
|
662 | 60 | ->defaultNull() |
|
663 | 60 | ->info('HTTP header that contains cache tags. Defaults to xkey-softpurge for Varnish xkey or X-Cache-Tags otherwise') |
|
664 | 60 | ->end() |
|
665 | 60 | ->scalarNode('separator') |
|
666 | 60 | ->defaultNull() |
|
667 | 60 | ->info('Character(s) to use to separate multiple tags. Defaults to " " for Varnish xkey or "," otherwise') |
|
668 | 60 | ->end() |
|
669 | 60 | ->scalarNode('max_header_value_length') |
|
670 | 60 | ->defaultNull() |
|
671 | 60 | ->info('If configured the tag header value will be split into multiple response headers of the same name (see "response_header" configuration key) that all do not exceed the configured "max_header_value_length" (recommended is 4KB = 4096) - configure in bytes.') |
|
672 | 60 | ->end() |
|
673 | 60 | ->arrayNode('rules') |
|
674 | 60 | ->prototype('array') |
|
675 | 60 | ->fixXmlConfig('tag') |
|
676 | 60 | ->fixXmlConfig('tag_expression') |
|
677 | 60 | ->validate() |
|
678 | ->ifTrue(function ($v) { |
||
679 | 4 | return !empty($v['tag_expressions']) && !class_exists(ExpressionLanguage::class); |
|
680 | 60 | }) |
|
681 | 60 | ->thenInvalid('Configured a tag_expression but ExpressionLanugage is not available') |
|
682 | 60 | ->end() |
|
683 | 60 | ->children() |
|
684 | ; |
||
685 | 60 | $this->addMatch($rules); |
|
686 | |||
687 | $rules |
||
688 | 60 | ->arrayNode('tags') |
|
689 | 60 | ->prototype('scalar') |
|
690 | 60 | ->info('Tags to add to the response on safe requests, to invalidate on unsafe requests') |
|
691 | 60 | ->end()->end() |
|
692 | 60 | ->arrayNode('tag_expressions') |
|
693 | 60 | ->prototype('scalar') |
|
694 | 60 | ->info('Tags to add to the response on safe requests, to invalidate on unsafe requests') |
|
695 | 60 | ->end() |
|
696 | ; |
||
697 | 60 | } |
|
698 | |||
699 | 60 | private function addInvalidationSection(ArrayNodeDefinition $rootNode) |
|
736 | |||
737 | /** |
||
738 | * User context main section. |
||
739 | * |
||
740 | * @param ArrayNodeDefinition $rootNode |
||
741 | */ |
||
742 | 60 | private function addUserContextListenerSection(ArrayNodeDefinition $rootNode) |
|
810 | |||
811 | 60 | private function addFlashMessageSection(ArrayNodeDefinition $rootNode) |
|
840 | |||
841 | 60 | private function addDebugSection(ArrayNodeDefinition $rootNode) |
|
861 | } |
||
862 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.