Completed
Push — master ( 720695...de9ede )
by Fabien
14:35
created

Configuration::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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 25
    public function __construct($debug)
43
    {
44 25
        $this->debug = (bool) $debug;
45 25
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 25
    public function getConfigTreeBuilder()
51
    {
52 25
        $treeBuilder = new TreeBuilder();
53 25
        $rootNode = $treeBuilder->root('httplug');
54
55 25
        $this->configureClients($rootNode);
56 25
        $this->configureSharedPlugins($rootNode);
57
58
        $rootNode
59 25
            ->validate()
60
                ->ifTrue(function ($v) {
61 21
                    return !empty($v['classes']['client'])
62 21
                        || !empty($v['classes']['message_factory'])
63 18
                        || !empty($v['classes']['uri_factory'])
64 21
                        || !empty($v['classes']['stream_factory']);
65 25
                })
66
                ->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
                                $key
73 1
                            ));
74
                        }
75 2
                    }
76
77 2
                    return $v;
78 25
                })
79 25
            ->end()
80 25
            ->beforeNormalization()
81
                ->ifTrue(function ($v) {
82 25
                    return is_array($v) && array_key_exists('toolbar', $v) && is_array($v['toolbar']);
83 25
                })
84
                ->then(function ($v) {
85 4
                    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 3
                    @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 3
                    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 1
                    }
95
96 3
                    $v['profiling'] = $v['toolbar'];
97
98 3
                    unset($v['toolbar']);
99
100 3
                    return $v;
101 25
                })
102 25
            ->end()
103 25
            ->fixXmlConfig('client')
104 25
            ->children()
105 25
                ->arrayNode('main_alias')
106 25
                    ->addDefaultsIfNotSet()
107 25
                    ->info('Configure which service the main alias point to.')
108 25
                    ->children()
109 25
                        ->scalarNode('client')->defaultValue('httplug.client.default')->end()
110 25
                        ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end()
111 25
                        ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end()
112 25
                        ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end()
113 25
                    ->end()
114 25
                ->end()
115 25
                ->arrayNode('classes')
116 25
                    ->addDefaultsIfNotSet()
117 25
                    ->info('Overwrite a service class instead of using the discovery mechanism.')
118 25
                    ->children()
119 25
                        ->scalarNode('client')->defaultNull()->end()
120 25
                        ->scalarNode('message_factory')->defaultNull()->end()
121 25
                        ->scalarNode('uri_factory')->defaultNull()->end()
122 25
                        ->scalarNode('stream_factory')->defaultNull()->end()
123 25
                    ->end()
124 25
                ->end()
125 25
                ->arrayNode('profiling')
126 25
                    ->addDefaultsIfNotSet()
127 25
                    ->treatFalseLike(['enabled' => false])
128 25
                    ->treatTrueLike(['enabled' => true])
129 25
                    ->treatNullLike(['enabled' => $this->debug])
130 25
                    ->info('Extend the debug profiler with information about requests.')
131 25
                    ->children()
132 25
                        ->booleanNode('enabled')
133 25
                            ->info('Turn the toolbar on or off. Defaults to kernel debug mode.')
134 25
                            ->defaultValue($this->debug)
135 25
                        ->end()
136 25
                        ->scalarNode('formatter')->defaultNull()->end()
137 25
                        ->integerNode('captured_body_length')
138 25
                            ->defaultValue(0)
139 25
                            ->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 25
                        ->end()
141 25
                    ->end()
142 25
                ->end()
143 25
                ->arrayNode('discovery')
144 25
                    ->addDefaultsIfNotSet()
145 25
                    ->info('Control what clients should be found by the discovery.')
146 25
                    ->children()
147 25
                        ->scalarNode('client')
148 25
                            ->defaultValue('auto')
149 25
                            ->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 25
                        ->end()
151 25
                        ->scalarNode('async_client')
152 25
                            ->defaultNull()
153 25
                            ->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 25
                        ->end()
155 25
                    ->end()
156 25
                ->end()
157 25
            ->end();
158
159 25
        return $treeBuilder;
160
    }
161
162 25
    private function configureClients(ArrayNodeDefinition $root)
163
    {
164 25
        $root->children()
165 25
            ->arrayNode('clients')
166 25
                ->useAttributeAsKey('name')
167 25
                ->prototype('array')
168 25
                ->fixXmlConfig('plugin')
169 25
                ->validate()
170
                    ->ifTrue(function ($config) {
171
                        // Make sure we only allow one of these to be true
172 9
                        return (bool) $config['flexible_client'] + (bool) $config['http_methods_client'] + (bool) $config['batch_client'] >= 2;
173 25
                    })
174 25
                    ->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 25
                ->end()
176 25
                ->validate()
177
                    ->ifTrue(function ($config) {
178 9
                        return $config['factory'] === 'httplug.factory.auto' && !empty($config['config']);
179 25
                    })
180 25
                    ->thenInvalid('If you want to use the "config" key you must also specify a valid "factory".')
181 25
                ->end()
182 25
                ->children()
183 25
                    ->scalarNode('factory')
184 25
                        ->defaultValue('httplug.factory.auto')
185 25
                        ->cannotBeEmpty()
186 25
                        ->info('The service id of a factory to use when creating the adapter.')
187 25
                    ->end()
188 25
                    ->booleanNode('flexible_client')
189 25
                        ->defaultFalse()
190 25
                        ->info('Set to true to get the client wrapped in a FlexibleHttpClient which emulates async or sync behavior.')
191 25
                    ->end()
192 25
                    ->booleanNode('http_methods_client')
193 25
                        ->defaultFalse()
194 25
                        ->info('Set to true to get the client wrapped in a HttpMethodsClient which emulates provides functions for HTTP verbs.')
195 25
                    ->end()
196 25
                    ->booleanNode('batch_client')
197 25
                        ->defaultFalse()
198 25
                        ->info('Set to true to get the client wrapped in a BatchClient which allows you to send multiple request at the same time.')
199 25
                    ->end()
200 25
                    ->variableNode('config')->defaultValue([])->end()
201 25
                    ->append($this->createClientPluginNode())
202 25
                ->end()
203 25
            ->end()
204 25
        ->end();
205 25
    }
206
207
    /**
208
     * @param ArrayNodeDefinition $root
209
     */
210 25
    private function configureSharedPlugins(ArrayNodeDefinition $root)
211
    {
212
        $pluginsNode = $root
213 25
            ->children()
214 25
                ->arrayNode('plugins')
215 25
                ->info('Global plugin configuration. Plugins need to be explicitly added to clients.')
216 25
                ->addDefaultsIfNotSet()
217
            // don't call end to get the plugins node
218 25
        ;
219 25
        $this->addSharedPluginNodes($pluginsNode);
220 25
    }
221
222
    /**
223
     * Createplugins node of a client.
224
     *
225
     * @return ArrayNodeDefinition The plugin node
226
     */
227 25
    private function createClientPluginNode()
228
    {
229 25
        $builder = new TreeBuilder();
230 25
        $node = $builder->root('plugins');
231
232
        /** @var ArrayNodeDefinition $pluginList */
233
        $pluginList = $node
234 25
            ->info('A list of plugin service ids and client specific plugin definitions. The order is important.')
235 25
            ->prototype('array')
236 25
        ;
237
        $pluginList
238
            // support having just a service id in the list
239 25
            ->beforeNormalization()
240
                ->always(function ($plugin) {
241 10
                    if (is_string($plugin)) {
242
                        return [
243
                            'reference' => [
244 9
                                'enabled' => true,
245 9
                                'id' => $plugin,
246 9
                            ],
247 9
                        ];
248
                    }
249
250 7
                    return $plugin;
251 25
                })
252 25
            ->end()
253
254 25
            ->validate()
255
                ->always(function ($plugins) {
256 9
                    foreach ($plugins as $name => $definition) {
257 9
                        if ('authentication' === $name) {
258 9
                            if (!count($definition)) {
259 9
                                unset($plugins['authentication']);
260 9
                            }
261 9
                        } elseif (!$definition['enabled']) {
262 9
                            unset($plugins[$name]);
263 9
                        }
264 9
                    }
265
266 9
                    return $plugins;
267 25
                })
268 25
            ->end()
269
        ;
270 25
        $this->addSharedPluginNodes($pluginList, true);
271
272
        $pluginList
273 25
            ->children()
274 25
                ->arrayNode('reference')
275 25
                    ->canBeEnabled()
276 25
                    ->info('Reference to a plugin service')
277 25
                    ->children()
278 25
                        ->scalarNode('id')
279 25
                            ->info('Service id of a plugin')
280 25
                            ->isRequired()
281 25
                            ->cannotBeEmpty()
282 25
                        ->end()
283 25
                    ->end()
284 25
                ->end()
285 25
                ->arrayNode('add_host')
286 25
                    ->canBeEnabled()
287 25
                    ->addDefaultsIfNotSet()
288 25
                    ->info('Set scheme, host and port in the request URI.')
289 25
                    ->children()
290 25
                        ->scalarNode('host')
291 25
                            ->info('Host name including protocol and optionally the port number, e.g. https://api.local:8000')
292 25
                            ->isRequired()
293 25
                            ->cannotBeEmpty()
294 25
                        ->end()
295 25
                        ->scalarNode('replace')
296 25
                            ->info('Whether to replace the host if request already specifies one')
297 25
                            ->defaultValue(false)
298 25
                        ->end()
299 25
                    ->end()
300 25
                ->end()
301 25
                ->arrayNode('header_append')
302 25
                    ->canBeEnabled()
303 25
                    ->info('Append headers to the request. If the header already exists the value will be appended to the current value.')
304 25
                    ->fixXmlConfig('header')
305 25
                    ->children()
306 25
                        ->arrayNode('headers')
307 25
                            ->info('Keys are the header names, values the header values')
308 25
                            ->normalizeKeys(false)
309 25
                            ->useAttributeAsKey('name')
310 25
                            ->prototype('scalar')->end()
311 25
                        ->end()
312 25
                    ->end()
313 25
                ->end()
314 25
                ->arrayNode('header_defaults')
315 25
                    ->canBeEnabled()
316 25
                    ->info('Set header to default value if it does not exist.')
317 25
                    ->fixXmlConfig('header')
318 25
                    ->children()
319 25
                        ->arrayNode('headers')
320 25
                            ->info('Keys are the header names, values the header values')
321 25
                            ->normalizeKeys(false)
322 25
                            ->useAttributeAsKey('name')
323 25
                            ->prototype('scalar')->end()
324 25
                        ->end()
325 25
                    ->end()
326 25
                ->end()
327 25
                ->arrayNode('header_set')
328 25
                    ->canBeEnabled()
329 25
                    ->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 25
                    ->fixXmlConfig('header')
331 25
                    ->children()
332 25
                        ->arrayNode('headers')
333 25
                            ->info('Keys are the header names, values the header values')
334 25
                            ->normalizeKeys(false)
335 25
                            ->useAttributeAsKey('name')
336 25
                            ->prototype('scalar')->end()
337 25
                        ->end()
338 25
                    ->end()
339 25
                ->end()
340 25
                ->arrayNode('header_remove')
341 25
                    ->canBeEnabled()
342 25
                    ->info('Remove headers from requests.')
343 25
                    ->fixXmlConfig('header')
344 25
                    ->children()
345 25
                        ->arrayNode('headers')
346 25
                            ->info('List of header names to remove')
347 25
                            ->prototype('scalar')->end()
348 25
                        ->end()
349 25
                    ->end()
350 25
                ->end()
351 25
            ->end()
352 25
        ->end();
353
354 25
        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 25
    private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableAll = false)
364
    {
365 25
        $children = $pluginNode->children();
366
367 25
        $children->append($this->createAuthenticationPluginNode());
368 25
        $children->append($this->createCachePluginNode());
369
370
        $children
371 25
            ->arrayNode('cookie')
372 25
                ->canBeEnabled()
373 25
                ->children()
374 25
                    ->scalarNode('cookie_jar')
375 25
                        ->info('This must be a service id to a service implementing '.CookieJar::class)
376 25
                        ->isRequired()
377 25
                        ->cannotBeEmpty()
378 25
                    ->end()
379 25
                ->end()
380 25
            ->end();
381
        // End cookie plugin
382
383
        $children
384 25
            ->arrayNode('history')
385 25
                ->canBeEnabled()
386 25
                ->children()
387 25
                    ->scalarNode('journal')
388 25
                        ->info('This must be a service id to a service implementing '.Journal::class)
389 25
                        ->isRequired()
390 25
                        ->cannotBeEmpty()
391 25
                    ->end()
392 25
                ->end()
393 25
            ->end();
394
        // End history plugin
395
396 25
        $decoder = $children->arrayNode('decoder');
397 25
        $disableAll ? $decoder->canBeEnabled() : $decoder->canBeDisabled();
398 25
        $decoder->addDefaultsIfNotSet()
399 25
            ->children()
400 25
                ->scalarNode('use_content_encoding')->defaultTrue()->end()
401 25
            ->end()
402 25
        ->end();
403
        // End decoder plugin
404
405 25
        $logger = $children->arrayNode('logger');
406 25
        $disableAll ? $logger->canBeEnabled() : $logger->canBeDisabled();
407 25
        $logger->addDefaultsIfNotSet()
408 25
            ->children()
409 25
                ->scalarNode('logger')
410 25
                    ->info('This must be a service id to a service implementing '.LoggerInterface::class)
411 25
                    ->defaultValue('logger')
412 25
                    ->cannotBeEmpty()
413 25
                ->end()
414 25
                ->scalarNode('formatter')
415 25
                    ->info('This must be a service id to a service implementing '.Formatter::class)
416 25
                    ->defaultNull()
417 25
                ->end()
418 25
            ->end()
419 25
        ->end();
420
        // End logger plugin
421
422 25
        $redirect = $children->arrayNode('redirect');
423 25
        $disableAll ? $redirect->canBeEnabled() : $redirect->canBeDisabled();
424 25
        $redirect->addDefaultsIfNotSet()
425 25
            ->children()
426 25
                ->scalarNode('preserve_header')->defaultTrue()->end()
427 25
                ->scalarNode('use_default_for_multiple')->defaultTrue()->end()
428 25
            ->end()
429 25
        ->end();
430
        // End redirect plugin
431
432 25
        $retry = $children->arrayNode('retry');
433 25
        $disableAll ? $retry->canBeEnabled() : $retry->canBeDisabled();
434 25
        $retry->addDefaultsIfNotSet()
435 25
            ->children()
436 25
                ->scalarNode('retry')->defaultValue(1)->end() // TODO: should be called retries for consistency with the class
437 25
            ->end()
438 25
        ->end();
439
        // End retry plugin
440
441 25
        $stopwatch = $children->arrayNode('stopwatch');
442 25
        $disableAll ? $stopwatch->canBeEnabled() : $stopwatch->canBeDisabled();
443 25
        $stopwatch->addDefaultsIfNotSet()
444 25
            ->children()
445 25
                ->scalarNode('stopwatch')
446 25
                    ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch')
447 25
                    ->defaultValue('debug.stopwatch')
448 25
                    ->cannotBeEmpty()
449 25
                ->end()
450 25
            ->end()
451 25
        ->end();
452
        // End stopwatch plugin
453 25
    }
454
455
    /**
456
     * Create configuration for authentication plugin.
457
     *
458
     * @return NodeDefinition Definition for the authentication node in the plugins list.
459
     */
460 25
    private function createAuthenticationPluginNode()
461
    {
462 25
        $builder = new TreeBuilder();
463 25
        $node = $builder->root('authentication');
464
        $node
465 25
            ->useAttributeAsKey('name')
466 25
            ->prototype('array')
467 25
                ->validate()
468 25
                    ->always()
469
                    ->then(function ($config) {
470 7
                        switch ($config['type']) {
471 7
                            case 'basic':
472 6
                                $this->validateAuthenticationType(['username', 'password'], $config, 'basic');
473
474 6
                                break;
475 2
                            case 'bearer':
476 1
                                $this->validateAuthenticationType(['token'], $config, 'bearer');
477
478 1
                                break;
479 2
                            case 'service':
480 2
                                $this->validateAuthenticationType(['service'], $config, 'service');
481
482 1
                                break;
483 1
                            case 'wsse':
484 1
                                $this->validateAuthenticationType(['username', 'password'], $config, 'wsse');
485
486 1
                                break;
487 6
                        }
488
489 6
                        return $config;
490 25
                    })
491 25
                ->end()
492 25
                ->children()
493 25
                    ->enumNode('type')
494 25
                        ->values(['basic', 'bearer', 'wsse', 'service'])
495 25
                        ->isRequired()
496 25
                        ->cannotBeEmpty()
497 25
                    ->end()
498 25
                    ->scalarNode('username')->end()
499 25
                    ->scalarNode('password')->end()
500 25
                    ->scalarNode('token')->end()
501 25
                    ->scalarNode('service')->end()
502 25
                    ->end()
503 25
                ->end()
504 25
            ->end(); // End authentication plugin
505
506 25
        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 1
        ));
535
    }
536
537
    /**
538
     * Create configuration for cache plugin.
539
     *
540
     * @return NodeDefinition Definition for the cache node in the plugins list.
541
     */
542 25
    private function createCachePluginNode()
543
    {
544 25
        $builder = new TreeBuilder();
545
546 25
        $config = $builder->root('config');
547
        $config
548 25
            ->fixXmlConfig('method')
549 25
            ->fixXmlConfig('respect_response_cache_directive')
550 25
            ->addDefaultsIfNotSet()
551 25
            ->validate()
552
                ->ifTrue(function ($config) {
553
                    // Cannot set both respect_cache_headers and respect_response_cache_directives
554 4
                    return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']);
555 25
                })
556 25
                ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.')
557 25
            ->end()
558 25
            ->children()
559 25
                ->scalarNode('cache_key_generator')
560 25
                    ->info('This must be a service id to a service implementing '.CacheKeyGenerator::class)
561 25
                ->end()
562 25
                ->integerNode('cache_lifetime')
563 25
                    ->info('The minimum time we should store a cache item')
564 25
                ->end()
565 25
                ->integerNode('default_ttl')
566 25
                    ->info('The default max age of a Response')
567 25
                ->end()
568 25
                ->enumNode('hash_algo')
569 25
                    ->info('Hashing algorithm to use')
570 25
                    ->values(hash_algos())
571 25
                    ->cannotBeEmpty()
572 25
                ->end()
573 25
                ->arrayNode('methods')
574 25
                    ->info('Which request methods to cache')
575 25
                    ->defaultValue(['GET', 'HEAD'])
576 25
                    ->prototype('scalar')
577 25
                        ->validate()
578
                            ->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 25
                            })
582 25
                            ->thenInvalid('Invalid method: %s')
583 25
                        ->end()
584 25
                    ->end()
585 25
                ->end()
586 25
                ->scalarNode('respect_cache_headers')
587 25
                    ->info('Whether we should care about cache headers or not [DEPRECATED]')
588 25
                    ->beforeNormalization()
589
                        ->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 25
                        })
594 25
                    ->end()
595 25
                    ->validate()
596 25
                        ->ifNotInArray([null, true, false])
597 25
                        ->thenInvalid('Value for "respect_cache_headers" must be null or boolean')
598 25
                    ->end()
599 25
                ->end()
600 25
                ->variableNode('respect_response_cache_directives')
601 25
                    ->info('A list of cache directives to respect when caching responses')
602 25
                    ->validate()
603 25
                        ->always(function ($v) {
604 2
                            if (is_null($v) || is_array($v)) {
605 2
                                return $v;
606
                            }
607
608
                            throw new InvalidTypeException();
609 25
                        })
610 25
                    ->end()
611 25
                ->end()
612 25
            ->end()
613
        ;
614
615 25
        $cache = $builder->root('cache');
616
        $cache
617 25
            ->canBeEnabled()
618 25
            ->addDefaultsIfNotSet()
619 25
            ->children()
620 25
                ->scalarNode('cache_pool')
621 25
                    ->info('This must be a service id to a service implementing '.CacheItemPoolInterface::class)
622 25
                    ->isRequired()
623 25
                    ->cannotBeEmpty()
624 25
                ->end()
625 25
                ->scalarNode('stream_factory')
626 25
                    ->info('This must be a service id to a service implementing '.StreamFactory::class)
627 25
                    ->defaultValue('httplug.stream_factory')
628 25
                    ->cannotBeEmpty()
629 25
                ->end()
630 25
            ->end()
631 25
            ->append($config)
632
        ;
633
634 25
        return $cache;
635
    }
636
}
637