diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index 70c191ff..f9a2ea85 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -2,6 +2,13 @@
namespace Http\HttplugBundle\DependencyInjection;
+use Http\Client\Common\Plugin\Cache\Generator\CacheKeyGenerator;
+use Http\Client\Common\Plugin\Journal;
+use Http\Message\CookieJar;
+use Http\Message\Formatter;
+use Http\Message\StreamFactory;
+use Psr\Cache\CacheItemPoolInterface;
+use Psr\Log\LoggerInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
@@ -352,69 +359,33 @@ private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableA
$children = $pluginNode->children();
$children->append($this->createAuthenticationPluginNode());
+ $children->append($this->createCachePluginNode());
- $children->arrayNode('cache')
- ->canBeEnabled()
- ->addDefaultsIfNotSet()
+ $children
+ ->arrayNode('cookie')
+ ->canBeEnabled()
->children()
- ->scalarNode('cache_pool')
- ->info('This must be a service id to a service implementing Psr\Cache\CacheItemPoolInterface')
+ ->scalarNode('cookie_jar')
+ ->info('This must be a service id to a service implementing '.CookieJar::class)
->isRequired()
->cannotBeEmpty()
->end()
- ->scalarNode('stream_factory')
- ->info('This must be a service id to a service implementing Http\Message\StreamFactory')
- ->defaultValue('httplug.stream_factory')
- ->cannotBeEmpty()
- ->end()
- ->arrayNode('config')
- ->addDefaultsIfNotSet()
- ->validate()
- ->ifTrue(function ($config) {
- // Cannot set both respect_cache_headers and respect_response_cache_directives
- return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']);
- })
- ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.')
- ->end()
- ->children()
- ->scalarNode('default_ttl')->defaultValue(0)->end()
- ->enumNode('respect_cache_headers')
- ->values([null, true, false])
- ->beforeNormalization()
- ->always(function ($v) {
- @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);
-
- return $v;
- })
- ->end()
- ->end()
- ->variableNode('respect_response_cache_directives')
- ->validate()
- ->always(function ($v) {
- if (is_null($v) || is_array($v)) {
- return $v;
- }
- throw new InvalidTypeException();
- })
- ->end()
- ->end()
- ->end()
- ->end()
->end()
->end();
- // End cache plugin
+ // End cookie plugin
- $children->arrayNode('cookie')
- ->canBeEnabled()
+ $children
+ ->arrayNode('history')
+ ->canBeEnabled()
->children()
- ->scalarNode('cookie_jar')
- ->info('This must be a service id to a service implementing Http\Message\CookieJar')
+ ->scalarNode('journal')
+ ->info('This must be a service id to a service implementing '.Journal::class)
->isRequired()
->cannotBeEmpty()
->end()
->end()
->end();
- // End cookie plugin
+ // End history plugin
$decoder = $children->arrayNode('decoder');
$disableAll ? $decoder->canBeEnabled() : $decoder->canBeDisabled();
@@ -425,29 +396,17 @@ private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableA
->end();
// End decoder plugin
- $children->arrayNode('history')
- ->canBeEnabled()
- ->children()
- ->scalarNode('journal')
- ->info('This must be a service id to a service implementing Http\Client\Plugin\Journal')
- ->isRequired()
- ->cannotBeEmpty()
- ->end()
- ->end()
- ->end();
- // End history plugin
-
$logger = $children->arrayNode('logger');
$disableAll ? $logger->canBeEnabled() : $logger->canBeDisabled();
$logger->addDefaultsIfNotSet()
->children()
->scalarNode('logger')
- ->info('This must be a service id to a service implementing Psr\Log\LoggerInterface')
+ ->info('This must be a service id to a service implementing '.LoggerInterface::class)
->defaultValue('logger')
->cannotBeEmpty()
->end()
->scalarNode('formatter')
- ->info('This must be a service id to a service implementing Http\Message\Formatter')
+ ->info('This must be a service id to a service implementing '.Formatter::class)
->defaultNull()
->end()
->end()
@@ -564,4 +523,101 @@ private function validateAuthenticationType(array $expected, array $actual, $aut
implode(', ', $actual)
));
}
+
+ /**
+ * Create configuration for cache plugin.
+ *
+ * @return NodeDefinition Definition for the cache node in the plugins list.
+ */
+ private function createCachePluginNode()
+ {
+ $builder = new TreeBuilder();
+
+ $config = $builder->root('config');
+ $config
+ ->fixXmlConfig('method')
+ ->fixXmlConfig('respect_response_cache_directive')
+ ->addDefaultsIfNotSet()
+ ->validate()
+ ->ifTrue(function ($config) {
+ // Cannot set both respect_cache_headers and respect_response_cache_directives
+ return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']);
+ })
+ ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.')
+ ->end()
+ ->children()
+ ->scalarNode('cache_key_generator')
+ ->info('This must be a service id to a service implementing '.CacheKeyGenerator::class)
+ ->end()
+ ->integerNode('cache_lifetime')
+ ->info('The minimum time we should store a cache item')
+ ->end()
+ ->integerNode('default_ttl')
+ ->info('The default max age of a Response')
+ ->end()
+ ->enumNode('hash_algo')
+ ->info('Hashing algorithm to use')
+ ->values(hash_algos())
+ ->cannotBeEmpty()
+ ->end()
+ ->arrayNode('methods')
+ ->info('Which request methods to cache')
+ ->defaultValue(['GET', 'HEAD'])
+ ->prototype('scalar')
+ ->validate()
+ ->ifTrue(function ($v) {
+ /* RFC7230 sections 3.1.1 and 3.2.6 except limited to uppercase characters. */
+ return preg_match('/[^A-Z0-9!#$%&\'*+\-.^_`|~]+/', $v);
+ })
+ ->thenInvalid('Invalid method: %s')
+ ->end()
+ ->end()
+ ->end()
+ ->enumNode('respect_cache_headers')
+ ->info('Whether we should care about cache headers or not [DEPRECATED]')
+ ->values([null, true, false])
+ ->beforeNormalization()
+ ->always(function ($v) {
+ @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);
+
+ return $v;
+ })
+ ->end()
+ ->end()
+ ->variableNode('respect_response_cache_directives')
+ ->info('A list of cache directives to respect when caching responses')
+ ->validate()
+ ->always(function ($v) {
+ if (is_null($v) || is_array($v)) {
+ return $v;
+ }
+
+ throw new InvalidTypeException();
+ })
+ ->end()
+ ->end()
+ ->end()
+ ;
+
+ $cache = $builder->root('cache');
+ $cache
+ ->canBeEnabled()
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('cache_pool')
+ ->info('This must be a service id to a service implementing '.CacheItemPoolInterface::class)
+ ->isRequired()
+ ->cannotBeEmpty()
+ ->end()
+ ->scalarNode('stream_factory')
+ ->info('This must be a service id to a service implementing '.StreamFactory::class)
+ ->defaultValue('httplug.stream_factory')
+ ->cannotBeEmpty()
+ ->end()
+ ->end()
+ ->append($config)
+ ;
+
+ return $cache;
+ }
}
diff --git a/Tests/Resources/Fixtures/config/full.php b/Tests/Resources/Fixtures/config/full.php
index 4b11230e..9b273542 100644
--- a/Tests/Resources/Fixtures/config/full.php
+++ b/Tests/Resources/Fixtures/config/full.php
@@ -80,8 +80,12 @@
'cache_pool' => 'my_cache_pool',
'stream_factory' => 'my_other_stream_factory',
'config' => [
+ 'cache_lifetime' => 2592000,
'default_ttl' => 42,
- 'respect_response_cache_directives' => ['X-Foo', 'X-Bar'],
+ 'hash_algo' => 'sha1',
+ 'methods' => ['GET'],
+ 'cache_key_generator' => null,
+ 'respect_response_cache_directives' => ['X-Foo'],
],
],
'cookie' => [
diff --git a/Tests/Resources/Fixtures/config/full.xml b/Tests/Resources/Fixtures/config/full.xml
index 67fffa64..9ef8e756 100644
--- a/Tests/Resources/Fixtures/config/full.xml
+++ b/Tests/Resources/Fixtures/config/full.xml
@@ -44,9 +44,9 @@
-
- X-Foo
- X-Bar
+
+ X-Foo
+ GET
diff --git a/Tests/Resources/Fixtures/config/full.yml b/Tests/Resources/Fixtures/config/full.yml
index 9fc902b5..460b472d 100644
--- a/Tests/Resources/Fixtures/config/full.yml
+++ b/Tests/Resources/Fixtures/config/full.yml
@@ -55,10 +55,14 @@ httplug:
cache_pool: my_cache_pool
stream_factory: my_other_stream_factory
config:
+ cache_lifetime: 2592000
default_ttl: 42
+ hash_algo: sha1
+ methods:
+ - GET
+ cache_key_generator: null
respect_response_cache_directives:
- X-Foo
- - X-Bar
cookie:
cookie_jar: my_cookie_jar
decoder:
diff --git a/Tests/Unit/DependencyInjection/ConfigurationTest.php b/Tests/Unit/DependencyInjection/ConfigurationTest.php
index 8c01ac53..a5e5758b 100644
--- a/Tests/Unit/DependencyInjection/ConfigurationTest.php
+++ b/Tests/Unit/DependencyInjection/ConfigurationTest.php
@@ -36,7 +36,7 @@ class ConfigurationTest extends AbstractExtensionConfigurationTestCase
'enabled' => false,
'stream_factory' => 'httplug.stream_factory',
'config' => [
- 'default_ttl' => 0,
+ 'methods' => ['GET', 'HEAD'],
],
],
'cookie' => [
@@ -194,8 +194,12 @@ public function testSupportsAllConfigFormats()
'cache_pool' => 'my_cache_pool',
'stream_factory' => 'my_other_stream_factory',
'config' => [
+ 'cache_lifetime' => 2592000,
'default_ttl' => 42,
- 'respect_response_cache_directives' => ['X-Foo', 'X-Bar'],
+ 'hash_algo' => 'sha1',
+ 'methods' => ['GET'],
+ 'cache_key_generator' => null,
+ 'respect_response_cache_directives' => ['X-Foo'],
],
],
'cookie' => [
@@ -317,7 +321,7 @@ public function testCacheConfigDeprecationCompatibility()
'enabled' => true,
'cache_pool' => 'my_cache_pool',
'config' => [
- 'default_ttl' => 0,
+ 'methods' => ['GET', 'HEAD'],
'respect_cache_headers' => true,
],
]);