Completed
Push — master ( 5eb8de...a6b875 )
by Tobias
14:06
created

Configuration::createAuthenticationPluginNode()   B

Complexity

Conditions 5
Paths 1

Size

Total Lines 48
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 5.0291

Importance

Changes 0
Metric Value
dl 0
loc 48
ccs 34
cts 38
cp 0.8947
rs 8.551
c 0
b 0
f 0
cc 5
eloc 38
nc 1
nop 0
crap 5.0291
1
<?php
2
3
namespace Http\HttplugBundle\DependencyInjection;
4
5
use Http\Client\Common\Plugin\Cache\Generator\CacheKeyGenerator;
6
use Http\Client\Common\Plugin\Journal;
7
use Http\Message\CookieJar;
8
use Http\Message\Formatter;
9
use Http\Message\StreamFactory;
10
use Psr\Cache\CacheItemPoolInterface;
11
use Psr\Log\LoggerInterface;
12
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
13
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
14
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
15
use Symfony\Component\Config\Definition\ConfigurationInterface;
16
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
17
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
18
19
/**
20
 * This class contains the configuration information for the bundle.
21
 *
22
 * This information is solely responsible for how the different configuration
23
 * sections are normalized, and merged.
24
 *
25
 * @author David Buchmann <[email protected]>
26
 * @author Tobias Nyholm <[email protected]>
27
 */
28
class Configuration implements ConfigurationInterface
29
{
30
    /**
31
     * Whether to use the debug mode.
32
     *
33
     * @see https://github.com/doctrine/DoctrineBundle/blob/v1.5.2/DependencyInjection/Configuration.php#L31-L41
34
     *
35
     * @var bool
36
     */
37
    private $debug;
38
39
    /**
40
     * @param bool $debug
41
     */
42 23
    public function __construct($debug)
43
    {
44 23
        $this->debug = (bool) $debug;
45 23
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 23
    public function getConfigTreeBuilder()
51
    {
52 23
        $treeBuilder = new TreeBuilder();
53 23
        $rootNode = $treeBuilder->root('httplug');
54
55 23
        $this->configureClients($rootNode);
56 23
        $this->configureSharedPlugins($rootNode);
57
58
        $rootNode
59 23
            ->validate()
60 23
                ->ifTrue(function ($v) {
61 19
                    return !empty($v['classes']['client'])
62 16
                        || !empty($v['classes']['message_factory'])
63 16
                        || !empty($v['classes']['uri_factory'])
64 19
                        || !empty($v['classes']['stream_factory']);
65 23
                })
66 23
                ->then(function ($v) {
67 3
                    foreach ($v['classes'] as $key => $class) {
68 3
                        if (null !== $class && !class_exists($class)) {
69 1
                            throw new InvalidConfigurationException(sprintf(
70 1
                                'Class %s specified for httplug.classes.%s does not exist.',
71 1
                                $class,
72 3
                                $key
73
                            ));
74
                        }
75
                    }
76
77 2
                    return $v;
78 23
                })
79 23
            ->end()
80 23
            ->beforeNormalization()
81 23
                ->ifTrue(function ($v) {
82 23
                    return is_array($v) && array_key_exists('toolbar', $v) && is_array($v['toolbar']);
83 23
                })
84 23
                ->then(function ($v) {
85 3
                    if (array_key_exists('profiling', $v)) {
86 1
                        throw new InvalidConfigurationException('Can\'t configure both "toolbar" and "profiling" section. The "toolbar" config is deprecated as of version 1.3.0, please only use "profiling".');
87
                    }
88
89 2
                    @trigger_error('"httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use "httplug.profiling" instead.', E_USER_DEPRECATED);
90
91 2
                    if (array_key_exists('enabled', $v['toolbar']) && 'auto' === $v['toolbar']['enabled']) {
92 1
                        @trigger_error('"auto" value in "httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use a boolean value instead.', E_USER_DEPRECATED);
93 1
                        $v['toolbar']['enabled'] = $this->debug;
94
                    }
95
96 2
                    $v['profiling'] = $v['toolbar'];
97
98 2
                    unset($v['toolbar']);
99
100 2
                    return $v;
101 23
                })
102 23
            ->end()
103 23
            ->fixXmlConfig('client')
104 23
            ->children()
105 23
                ->arrayNode('main_alias')
106 23
                    ->addDefaultsIfNotSet()
107 23
                    ->info('Configure which service the main alias point to.')
108 23
                    ->children()
109 23
                        ->scalarNode('client')->defaultValue('httplug.client.default')->end()
110 23
                        ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end()
111 23
                        ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end()
112 23
                        ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end()
113 23
                    ->end()
114 23
                ->end()
115 23
                ->arrayNode('classes')
116 23
                    ->addDefaultsIfNotSet()
117 23
                    ->info('Overwrite a service class instead of using the discovery mechanism.')
118 23
                    ->children()
119 23
                        ->scalarNode('client')->defaultNull()->end()
120 23
                        ->scalarNode('message_factory')->defaultNull()->end()
121 23
                        ->scalarNode('uri_factory')->defaultNull()->end()
122 23
                        ->scalarNode('stream_factory')->defaultNull()->end()
123 23
                    ->end()
124 23
                ->end()
125 23
                ->arrayNode('profiling')
126 23
                    ->addDefaultsIfNotSet()
127 23
                    ->treatFalseLike(['enabled' => false])
128 23
                    ->treatTrueLike(['enabled' => true])
129 23
                    ->treatNullLike(['enabled' => $this->debug])
130 23
                    ->info('Extend the debug profiler with information about requests.')
131 23
                    ->children()
132 23
                        ->booleanNode('enabled')
133 23
                            ->info('Turn the toolbar on or off. Defaults to kernel debug mode.')
134 23
                            ->defaultValue($this->debug)
135 23
                        ->end()
136 23
                        ->scalarNode('formatter')->defaultNull()->end()
137 23
                        ->integerNode('captured_body_length')
138 23
                            ->defaultValue(0)
139 23
                            ->info('Limit long HTTP message bodies to x characters. If set to 0 we do not read the message body. Only available with the default formatter (FullHttpMessageFormatter).')
140 23
                        ->end()
141 23
                    ->end()
142 23
                ->end()
143 23
                ->arrayNode('discovery')
144 23
                    ->addDefaultsIfNotSet()
145 23
                    ->info('Control what clients should be found by the discovery.')
146 23
                    ->children()
147 23
                        ->scalarNode('client')
148 23
                            ->defaultValue('auto')
149 23
                            ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.')
150 23
                        ->end()
151 23
                        ->scalarNode('async_client')
152 23
                            ->defaultNull()
153 23
                            ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.')
154 23
                        ->end()
155 23
                    ->end()
156 23
                ->end()
157 23
            ->end();
158
159 23
        return $treeBuilder;
160
    }
161
162 23
    private function configureClients(ArrayNodeDefinition $root)
163
    {
164 23
        $root->children()
165 23
            ->arrayNode('clients')
166 23
                ->useAttributeAsKey('name')
167 23
                ->prototype('array')
168 23
                ->fixXmlConfig('plugin')
169 23
                ->validate()
170 23
                    ->ifTrue(function ($config) {
171
                        // Make sure we only allow one of these to be true
172 7
                        return (bool) $config['flexible_client'] + (bool) $config['http_methods_client'] + (bool) $config['batch_client'] >= 2;
173 23
                    })
174 23
                    ->thenInvalid('A http client can\'t be decorated with several of FlexibleHttpClient, HttpMethodsClient and BatchClient. Only one of the following options can be true. ("flexible_client", "http_methods_client", "batch_client")')
175 23
                ->end()
176 23
                ->validate()
177 23
                    ->ifTrue(function ($config) {
178 7
                        return 'httplug.factory.auto' === $config['factory'] && !empty($config['config']);
179 23
                    })
180 23
                    ->thenInvalid('If you want to use the "config" key you must also specify a valid "factory".')
181 23
                ->end()
182 23
                ->children()
183 23
                    ->scalarNode('factory')
184 23
                        ->defaultValue('httplug.factory.auto')
185 23
                        ->cannotBeEmpty()
186 23
                        ->info('The service id of a factory to use when creating the adapter.')
187 23
                    ->end()
188 23
                    ->booleanNode('flexible_client')
189 23
                        ->defaultFalse()
190 23
                        ->info('Set to true to get the client wrapped in a FlexibleHttpClient which emulates async or sync behavior.')
191 23
                    ->end()
192 23
                    ->booleanNode('http_methods_client')
193 23
                        ->defaultFalse()
194 23
                        ->info('Set to true to get the client wrapped in a HttpMethodsClient which emulates provides functions for HTTP verbs.')
195 23
                    ->end()
196 23
                    ->booleanNode('batch_client')
197 23
                        ->defaultFalse()
198 23
                        ->info('Set to true to get the client wrapped in a BatchClient which allows you to send multiple request at the same time.')
199 23
                    ->end()
200 23
                    ->variableNode('config')->defaultValue([])->end()
201 23
                    ->append($this->createClientPluginNode())
202 23
                ->end()
203 23
            ->end()
204 23
        ->end();
205 23
    }
206
207
    /**
208
     * @param ArrayNodeDefinition $root
209
     */
210 23
    private function configureSharedPlugins(ArrayNodeDefinition $root)
211
    {
212
        $pluginsNode = $root
213 23
            ->children()
214 23
                ->arrayNode('plugins')
215 23
                ->info('Global plugin configuration. Plugins need to be explicitly added to clients.')
216 23
                ->addDefaultsIfNotSet()
217
            // don't call end to get the plugins node
218
        ;
219 23
        $this->addSharedPluginNodes($pluginsNode);
220 23
    }
221
222
    /**
223
     * Createplugins node of a client.
224
     *
225
     * @return ArrayNodeDefinition The plugin node
226
     */
227 23
    private function createClientPluginNode()
228
    {
229 23
        $builder = new TreeBuilder();
230 23
        $node = $builder->root('plugins');
231
232
        /** @var ArrayNodeDefinition $pluginList */
233
        $pluginList = $node
234 23
            ->info('A list of plugin service ids and client specific plugin definitions. The order is important.')
235 23
            ->prototype('array')
236
        ;
237
        $pluginList
238
            // support having just a service id in the list
239 23
            ->beforeNormalization()
240 23
                ->always(function ($plugin) {
241 8
                    if (is_string($plugin)) {
242
                        return [
243 7
                            'reference' => [
244
                                'enabled' => true,
245 7
                                'id' => $plugin,
246
                            ],
247
                        ];
248
                    }
249
250 7
                    return $plugin;
251 23
                })
252 23
            ->end()
253
254 23
            ->validate()
255 23
                ->always(function ($plugins) {
256 7
                    foreach ($plugins as $name => $definition) {
257 7
                        if ('authentication' === $name) {
258 7
                            if (!count($definition)) {
259 7
                                unset($plugins['authentication']);
260
                            }
261 7
                        } elseif (!$definition['enabled']) {
262 7
                            unset($plugins[$name]);
263
                        }
264
                    }
265
266 7
                    return $plugins;
267 23
                })
268 23
            ->end()
269
        ;
270 23
        $this->addSharedPluginNodes($pluginList, true);
271
272
        $pluginList
273 23
            ->children()
274 23
                ->arrayNode('reference')
275 23
                    ->canBeEnabled()
276 23
                    ->info('Reference to a plugin service')
277 23
                    ->children()
278 23
                        ->scalarNode('id')
279 23
                            ->info('Service id of a plugin')
280 23
                            ->isRequired()
281 23
                            ->cannotBeEmpty()
282 23
                        ->end()
283 23
                    ->end()
284 23
                ->end()
285 23
                ->arrayNode('add_host')
286 23
                    ->canBeEnabled()
287 23
                    ->addDefaultsIfNotSet()
288 23
                    ->info('Set scheme, host and port in the request URI.')
289 23
                    ->children()
290 23
                        ->scalarNode('host')
291 23
                            ->info('Host name including protocol and optionally the port number, e.g. https://api.local:8000')
292 23
                            ->isRequired()
293 23
                            ->cannotBeEmpty()
294 23
                        ->end()
295 23
                        ->scalarNode('replace')
296 23
                            ->info('Whether to replace the host if request already specifies one')
297 23
                            ->defaultValue(false)
298 23
                        ->end()
299 23
                    ->end()
300 23
                ->end()
301 23
                ->arrayNode('header_append')
302 23
                    ->canBeEnabled()
303 23
                    ->info('Append headers to the request. If the header already exists the value will be appended to the current value.')
304 23
                    ->fixXmlConfig('header')
305 23
                    ->children()
306 23
                        ->arrayNode('headers')
307 23
                            ->info('Keys are the header names, values the header values')
308 23
                            ->normalizeKeys(false)
309 23
                            ->useAttributeAsKey('name')
310 23
                            ->prototype('scalar')->end()
311 23
                        ->end()
312 23
                    ->end()
313 23
                ->end()
314 23
                ->arrayNode('header_defaults')
315 23
                    ->canBeEnabled()
316 23
                    ->info('Set header to default value if it does not exist.')
317 23
                    ->fixXmlConfig('header')
318 23
                    ->children()
319 23
                        ->arrayNode('headers')
320 23
                            ->info('Keys are the header names, values the header values')
321 23
                            ->normalizeKeys(false)
322 23
                            ->useAttributeAsKey('name')
323 23
                            ->prototype('scalar')->end()
324 23
                        ->end()
325 23
                    ->end()
326 23
                ->end()
327 23
                ->arrayNode('header_set')
328 23
                    ->canBeEnabled()
329 23
                    ->info('Set headers to requests. If the header does not exist it wil be set, if the header already exists it will be replaced.')
330 23
                    ->fixXmlConfig('header')
331 23
                    ->children()
332 23
                        ->arrayNode('headers')
333 23
                            ->info('Keys are the header names, values the header values')
334 23
                            ->normalizeKeys(false)
335 23
                            ->useAttributeAsKey('name')
336 23
                            ->prototype('scalar')->end()
337 23
                        ->end()
338 23
                    ->end()
339 23
                ->end()
340 23
                ->arrayNode('header_remove')
341 23
                    ->canBeEnabled()
342 23
                    ->info('Remove headers from requests.')
343 23
                    ->fixXmlConfig('header')
344 23
                    ->children()
345 23
                        ->arrayNode('headers')
346 23
                            ->info('List of header names to remove')
347 23
                            ->prototype('scalar')->end()
348 23
                        ->end()
349 23
                    ->end()
350 23
                ->end()
351 23
            ->end()
352 23
        ->end();
353
354 23
        return $node;
355
    }
356
357
    /**
358
     * Add the definitions for shared plugin configurations.
359
     *
360
     * @param ArrayNodeDefinition $pluginNode The node to add to.
361
     * @param bool                $disableAll Some shared plugins are enabled by default. On the client, all are disabled by default.
362
     */
363 23
    private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableAll = false)
364
    {
365 23
        $children = $pluginNode->children();
366
367 23
        $children->append($this->createAuthenticationPluginNode());
368 23
        $children->append($this->createCachePluginNode());
369
370
        $children
371 23
            ->arrayNode('cookie')
372 23
                ->canBeEnabled()
373 23
                ->children()
374 23
                    ->scalarNode('cookie_jar')
375 23
                        ->info('This must be a service id to a service implementing '.CookieJar::class)
376 23
                        ->isRequired()
377 23
                        ->cannotBeEmpty()
378 23
                    ->end()
379 23
                ->end()
380 23
            ->end();
381
        // End cookie plugin
382
383
        $children
384 23
            ->arrayNode('history')
385 23
                ->canBeEnabled()
386 23
                ->children()
387 23
                    ->scalarNode('journal')
388 23
                        ->info('This must be a service id to a service implementing '.Journal::class)
389 23
                        ->isRequired()
390 23
                        ->cannotBeEmpty()
391 23
                    ->end()
392 23
                ->end()
393 23
            ->end();
394
        // End history plugin
395
396 23
        $decoder = $children->arrayNode('decoder');
397 23
        $disableAll ? $decoder->canBeEnabled() : $decoder->canBeDisabled();
398 23
        $decoder->addDefaultsIfNotSet()
399 23
            ->children()
400 23
                ->scalarNode('use_content_encoding')->defaultTrue()->end()
401 23
            ->end()
402 23
        ->end();
403
        // End decoder plugin
404
405 23
        $logger = $children->arrayNode('logger');
406 23
        $disableAll ? $logger->canBeEnabled() : $logger->canBeDisabled();
407 23
        $logger->addDefaultsIfNotSet()
408 23
            ->children()
409 23
                ->scalarNode('logger')
410 23
                    ->info('This must be a service id to a service implementing '.LoggerInterface::class)
411 23
                    ->defaultValue('logger')
412 23
                    ->cannotBeEmpty()
413 23
                ->end()
414 23
                ->scalarNode('formatter')
415 23
                    ->info('This must be a service id to a service implementing '.Formatter::class)
416 23
                    ->defaultNull()
417 23
                ->end()
418 23
            ->end()
419 23
        ->end();
420
        // End logger plugin
421
422 23
        $redirect = $children->arrayNode('redirect');
423 23
        $disableAll ? $redirect->canBeEnabled() : $redirect->canBeDisabled();
424 23
        $redirect->addDefaultsIfNotSet()
425 23
            ->children()
426 23
                ->scalarNode('preserve_header')->defaultTrue()->end()
427 23
                ->scalarNode('use_default_for_multiple')->defaultTrue()->end()
428 23
            ->end()
429 23
        ->end();
430
        // End redirect plugin
431
432 23
        $retry = $children->arrayNode('retry');
433 23
        $disableAll ? $retry->canBeEnabled() : $retry->canBeDisabled();
434 23
        $retry->addDefaultsIfNotSet()
435 23
            ->children()
436 23
                ->scalarNode('retry')->defaultValue(1)->end() // TODO: should be called retries for consistency with the class
437 23
            ->end()
438 23
        ->end();
439
        // End retry plugin
440
441 23
        $stopwatch = $children->arrayNode('stopwatch');
442 23
        $disableAll ? $stopwatch->canBeEnabled() : $stopwatch->canBeDisabled();
443 23
        $stopwatch->addDefaultsIfNotSet()
444 23
            ->children()
445 23
                ->scalarNode('stopwatch')
446 23
                    ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch')
447 23
                    ->defaultValue('debug.stopwatch')
448 23
                    ->cannotBeEmpty()
449 23
                ->end()
450 23
            ->end()
451 23
        ->end();
452
        // End stopwatch plugin
453 23
    }
454
455
    /**
456
     * Create configuration for authentication plugin.
457
     *
458
     * @return NodeDefinition Definition for the authentication node in the plugins list.
459
     */
460 23
    private function createAuthenticationPluginNode()
461
    {
462 23
        $builder = new TreeBuilder();
463 23
        $node = $builder->root('authentication');
464
        $node
465 23
            ->useAttributeAsKey('name')
466 23
            ->prototype('array')
467 23
                ->validate()
468 23
                    ->always()
469 23
                    ->then(function ($config) {
470 7
                        switch ($config['type']) {
471
                            case 'basic':
472 6
                                $this->validateAuthenticationType(['username', 'password'], $config, 'basic');
473
474 6
                                break;
475
                            case 'bearer':
476 1
                                $this->validateAuthenticationType(['token'], $config, 'bearer');
477
478 1
                                break;
479
                            case 'service':
480 2
                                $this->validateAuthenticationType(['service'], $config, 'service');
481
482 1
                                break;
483
                            case 'wsse':
484 1
                                $this->validateAuthenticationType(['username', 'password'], $config, 'wsse');
485
486 1
                                break;
487
                        }
488
489 6
                        return $config;
490 23
                    })
491 23
                ->end()
492 23
                ->children()
493 23
                    ->enumNode('type')
494 23
                        ->values(['basic', 'bearer', 'wsse', 'service'])
495 23
                        ->isRequired()
496 23
                        ->cannotBeEmpty()
497 23
                    ->end()
498 23
                    ->scalarNode('username')->end()
499 23
                    ->scalarNode('password')->end()
500 23
                    ->scalarNode('token')->end()
501 23
                    ->scalarNode('service')->end()
502 23
                    ->end()
503 23
                ->end()
504 23
            ->end(); // End authentication plugin
505
506 23
        return $node;
507
    }
508
509
    /**
510
     * Validate that the configuration fragment has the specified keys and none other.
511
     *
512
     * @param array  $expected Fields that must exist
513
     * @param array  $actual   Actual configuration hashmap
514
     * @param string $authName Name of authentication method for error messages
515
     *
516
     * @throws InvalidConfigurationException If $actual does not have exactly the keys specified in $expected (plus 'type')
517
     */
518 7
    private function validateAuthenticationType(array $expected, array $actual, $authName)
519
    {
520 7
        unset($actual['type']);
521 7
        $actual = array_keys($actual);
522 7
        sort($actual);
523 7
        sort($expected);
524
525 7
        if ($expected === $actual) {
526 6
            return;
527
        }
528
529 1
        throw new InvalidConfigurationException(sprintf(
530 1
            'Authentication "%s" requires %s but got %s',
531 1
            $authName,
532 1
            implode(', ', $expected),
533 1
            implode(', ', $actual)
534
        ));
535
    }
536
537
    /**
538
     * Create configuration for cache plugin.
539
     *
540
     * @return NodeDefinition Definition for the cache node in the plugins list.
541
     */
542 23
    private function createCachePluginNode()
543
    {
544 23
        $builder = new TreeBuilder();
545
546 23
        $config = $builder->root('config');
547
        $config
548 23
            ->fixXmlConfig('method')
549 23
            ->fixXmlConfig('respect_response_cache_directive')
550 23
            ->addDefaultsIfNotSet()
551 23
            ->validate()
552 23
                ->ifTrue(function ($config) {
553
                    // Cannot set both respect_cache_headers and respect_response_cache_directives
554 5
                    return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']);
555 23
                })
556 23
                ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.')
557 23
            ->end()
558 23
            ->children()
559 23
                ->scalarNode('cache_key_generator')
560 23
                    ->info('This must be a service id to a service implementing '.CacheKeyGenerator::class)
561 23
                ->end()
562 23
                ->integerNode('cache_lifetime')
563 23
                    ->info('The minimum time we should store a cache item')
564 23
                ->end()
565 23
                ->integerNode('default_ttl')
566 23
                    ->info('The default max age of a Response')
567 23
                ->end()
568 23
                ->enumNode('hash_algo')
569 23
                    ->info('Hashing algorithm to use')
570 23
                    ->values(hash_algos())
571 23
                    ->cannotBeEmpty()
572 23
                ->end()
573 23
                ->arrayNode('methods')
574 23
                    ->info('Which request methods to cache')
575 23
                    ->defaultValue(['GET', 'HEAD'])
576 23
                    ->prototype('scalar')
577 23
                        ->validate()
578 23
                            ->ifTrue(function ($v) {
579
                                /* RFC7230 sections 3.1.1 and 3.2.6 except limited to uppercase characters. */
580 1
                                return preg_match('/[^A-Z0-9!#$%&\'*+\-.^_`|~]+/', $v);
581 23
                            })
582 23
                            ->thenInvalid('Invalid method: %s')
583 23
                        ->end()
584 23
                    ->end()
585 23
                ->end()
586 23
                ->scalarNode('respect_cache_headers')
587 23
                    ->info('Whether we should care about cache headers or not [DEPRECATED]')
588 23
                    ->beforeNormalization()
589 23
                        ->always(function ($v) {
590 3
                            @trigger_error('The option "respect_cache_headers" is deprecated since version 1.3 and will be removed in 2.0. Use "respect_response_cache_directives" instead.', E_USER_DEPRECATED);
591
592 3
                            return $v;
593 23
                        })
594 23
                    ->end()
595 23
                    ->validate()
596 23
                        ->ifNotInArray([null, true, false])
597 23
                        ->thenInvalid('Value for "respect_cache_headers" must be null or boolean')
598 23
                    ->end()
599 23
                ->end()
600 23
                ->variableNode('respect_response_cache_directives')
601 23
                    ->info('A list of cache directives to respect when caching responses')
602 23
                    ->validate()
603 23
                        ->always(function ($v) {
604 2
                            if (is_null($v) || is_array($v)) {
605 2
                                return $v;
606
                            }
607
608
                            throw new InvalidTypeException();
609 23
                        })
610 23
                    ->end()
611 23
                ->end()
612 23
            ->end()
613
        ;
614
615 23
        $cache = $builder->root('cache');
616
        $cache
617 23
            ->canBeEnabled()
618 23
            ->addDefaultsIfNotSet()
619 23
            ->children()
620 23
                ->scalarNode('cache_pool')
621 23
                    ->info('This must be a service id to a service implementing '.CacheItemPoolInterface::class)
622 23
                    ->isRequired()
623 23
                    ->cannotBeEmpty()
624 23
                ->end()
625 23
                ->scalarNode('stream_factory')
626 23
                    ->info('This must be a service id to a service implementing '.StreamFactory::class)
627 23
                    ->defaultValue('httplug.stream_factory')
628 23
                    ->cannotBeEmpty()
629 23
                ->end()
630 23
            ->end()
631 23
            ->append($config)
632
        ;
633
634 23
        return $cache;
635
    }
636
}
637