diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 1147711b..8db08e1c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -15,6 +15,7 @@ * sections are normalized, and merged. * * @author David Buchmann + * @author Tobias Nyholm */ class Configuration implements ConfigurationInterface { @@ -27,6 +28,7 @@ public function getConfigTreeBuilder() $rootNode = $treeBuilder->root('httplug'); $this->configureClients($rootNode); + $this->configurePlugins($rootNode); $rootNode ->validate() @@ -108,4 +110,129 @@ protected function configureClients(ArrayNodeDefinition $root) ->end() ->end(); } + + /** + * @param ArrayNodeDefinition $root + */ + protected function configurePlugins(ArrayNodeDefinition $root) + { + $root->children() + ->arrayNode('plugins') + ->addDefaultsIfNotSet() + ->children() + + ->arrayNode('authentication') + ->canBeEnabled() + ->children() + ->scalarNode('authentication') + ->info('This must be a service id to a service implementing Http\Message\Authentication') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() + ->end() // End authentication plugin + + ->arrayNode('cache') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('cache_pool') + ->info('This must be a service id to a service implementing Psr\Cache\CacheItemPoolInterface') + ->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() + ->children() + ->scalarNode('default_ttl')->defaultNull()->end() + ->scalarNode('respect_cache_headers')->defaultTrue()->end() + ->end() + ->end() + ->end() + ->end() // End cache plugin + + ->arrayNode('cookie') + ->canBeEnabled() + ->children() + ->scalarNode('cookie_jar') + ->info('This must be a service id to a service implementing Http\Message\CookieJar') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() + ->end() // End cookie plugin + + ->arrayNode('decoder') + ->canBeDisabled() + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('use_content_encoding')->defaultTrue()->end() + ->end() + ->end() // End decoder plugin + + ->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 + + ->arrayNode('logger') + ->canBeDisabled() + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('logger') + ->info('This must be a service id to a service implementing Psr\Log\LoggerInterface') + ->defaultValue('logger') + ->cannotBeEmpty() + ->end() + ->scalarNode('formatter') + ->info('This must be a service id to a service implementing Http\Message\Formatter') + ->defaultNull() + ->end() + ->end() + ->end() // End logger plugin + + ->arrayNode('redirect') + ->canBeDisabled() + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('preserve_header')->defaultTrue()->end() + ->scalarNode('use_default_for_multiple')->defaultTrue()->end() + ->end() + ->end() // End redirect plugin + + ->arrayNode('retry') + ->canBeDisabled() + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('retry')->defaultValue(1)->end() + ->end() + ->end() // End retry plugin + + ->arrayNode('stopwatch') + ->canBeDisabled() + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('stopwatch') + ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch') + ->defaultValue('debug.stopwatch') + ->cannotBeEmpty() + ->end() + ->end() + ->end() // End stopwatch plugin + + ->end() + ->end() + ->end(); + } } diff --git a/DependencyInjection/HttplugExtension.php b/DependencyInjection/HttplugExtension.php index 740c880d..8909a91f 100644 --- a/DependencyInjection/HttplugExtension.php +++ b/DependencyInjection/HttplugExtension.php @@ -6,12 +6,14 @@ use Http\HttplugBundle\ClientFactory\DummyClient; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** * @author David Buchmann + * @author Tobias Nyholm */ class HttplugExtension extends Extension { @@ -50,6 +52,7 @@ public function load(array $configs, ContainerBuilder $container) foreach ($config['main_alias'] as $type => $id) { $container->setAlias(sprintf('httplug.%s', $type), $id); } + $this->configurePlugins($container, $config['plugins']); $this->configureClients($container, $config); } @@ -59,7 +62,7 @@ public function load(array $configs, ContainerBuilder $container) * @param ContainerBuilder $container * @param array $config */ - protected function configureClients(ContainerBuilder $container, array $config) + private function configureClients(ContainerBuilder $container, array $config) { $first = isset($config['clients']['default']) ? 'default' : null; foreach ($config['clients'] as $name => $arguments) { @@ -96,4 +99,67 @@ protected function configureClients(ContainerBuilder $container, array $config) ->addArgument([new Reference('httplug.collector.history_plugin')]); } } + + /** + * @param ContainerBuilder $container + * @param array $config + */ + private function configurePlugins(ContainerBuilder $container, array $config) + { + foreach ($config as $name => $pluginConfig) { + $pluginId = 'httplug.plugin.'.$name; + if ($pluginConfig['enabled']) { + $def = $container->getDefinition($pluginId); + $this->configurePluginByName($name, $def, $pluginConfig); + } else { + $container->removeDefinition($pluginId); + } + } + } + + /** + * @param string $name + * @param Definition $definition + * @param array $config + */ + private function configurePluginByName($name, Definition $definition, array $config) + { + switch ($name) { + case 'authentication': + $definition->replaceArgument(0, new Reference($config['authentication'])); + break; + case 'cache': + $definition + ->replaceArgument(0, new Reference($config['cache_pool'])) + ->replaceArgument(1, new Reference($config['stream_factory'])) + ->replaceArgument(2, $config['config']); + break; + case 'cookie': + $definition->replaceArgument(0, new Reference($config['cookie_jar'])); + break; + case 'decoder': + $definition->addArgument($config['use_content_encoding']); + break; + case 'history': + $definition->replaceArgument(0, new Reference($config['journal'])); + break; + case 'logger': + $definition->replaceArgument(0, new Reference($config['logger'])); + if (!empty($config['formatter'])) { + $definition->replaceArgument(1, new Reference($config['formatter'])); + } + break; + case 'redirect': + $definition + ->addArgument($config['preserve_header']) + ->addArgument($config['use_default_for_multiple']); + break; + case 'retry': + $definition->addArgument($config['retry']); + break; + case 'stopwatch': + $definition->replaceArgument(0, new Reference($config['stopwatch'])); + break; + } + } } diff --git a/HttplugBundle.php b/HttplugBundle.php index edd1df1e..082d32f4 100644 --- a/HttplugBundle.php +++ b/HttplugBundle.php @@ -6,6 +6,7 @@ /** * @author David Buchmann + * @author Tobias Nyholm */ class HttplugBundle extends Bundle { diff --git a/README.md b/README.md index a16fddfd..d373aa44 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,8 @@ For information how to write applications with the services provided by this bun | httplug.stream_factory | Service* that provides the `Http\Message\StreamFactory` | httplug.client.[name] | This is your Httpclient that you have configured. With the configuration below the name would be `acme_client`. | httplug.client | This is the first client configured or a client named `default`. -| httplug.plugin.content_length
httplug.plugin.decoder
httplug.plugin.error
httplug.plugin.logger
httplug.plugin.redirect
httplug.plugin.retry | These are built in plugins that live in the `php-http/plugins` package. These servcies are not public and may only be used when configure HttpClients or services. +| httplug.plugin.content_length
httplug.plugin.decoder
httplug.plugin.error
httplug.plugin.logger
httplug.plugin.redirect
httplug.plugin.retry
httplug.plugin.stopwatch | These are plugins that are enabled by default. These services are not public and may only be used when configure HttpClients or other services. +| httplug.plugin.authentication
httplug.plugin.cache
httplug.plugin.cookie
httplug.plugin.history | These are plugins that are disabled by default. They need to be configured before they can be used. These services are not public and may only be used when configure HttpClients or other services. \* *These services are always an alias to another service. You can specify your own service or leave the default, which is the same name with `.default` appended. The default services in turn use the service discovery mechanism to provide the best available implementation. You can specify a class for each of the default services to use instead of discovery, as long as those classes can be instantiated without arguments.* @@ -122,10 +123,13 @@ acme_plugin: ```yaml // config.yml httpug: + plugins: + cache: + cache_pool: 'my_cache_pool' clients: acme: factory: 'httplug.factory.guzzle6' - plugins: ['acme_plugin' , 'httplug.plugin.logger'] + plugins: ['acme_plugin', 'httplug.plugin.cache', ''httplug.plugin.retry'] config: base_uri: 'http://google.se/' ``` diff --git a/Resources/config/plugins.xml b/Resources/config/plugins.xml index a23f4a31..e99fbe2e 100644 --- a/Resources/config/plugins.xml +++ b/Resources/config/plugins.xml @@ -4,13 +4,31 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + + + + + + + + + + + + + + - + + null + + + diff --git a/Tests/Unit/DependencyInjection/ConfigurationTest.php b/Tests/Unit/DependencyInjection/ConfigurationTest.php index 84a64eac..a1d37aa9 100644 --- a/Tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/Tests/Unit/DependencyInjection/ConfigurationTest.php @@ -41,6 +41,47 @@ public function testEmptyConfiguration() 'enabled' => 'auto', 'formatter' => null, ], + 'plugins' => [ + 'authentication' => [ + 'enabled' => false, + ], + 'cache' => [ + 'enabled' => false, + 'stream_factory' => 'httplug.stream_factory', + 'config' => [ + 'default_ttl' => null, + 'respect_cache_headers' => true, + ], + ], + 'cookie' => [ + 'enabled' => false, + ], + 'decoder' => [ + 'enabled' => true, + 'use_content_encoding' => true, + ], + 'history' => [ + 'enabled' => false, + ], + 'logger' => [ + 'enabled' => true, + 'logger' => 'logger', + 'formatter' => null, + ], + 'redirect' => [ + 'enabled' => true, + 'preserve_header' => true, + 'use_default_for_multiple' => true, + ], + 'retry' => [ + 'enabled' => true, + 'retry' => 1, + ], + 'stopwatch' => [ + 'enabled' => true, + 'stopwatch' => 'debug.stopwatch', + ], + ], ]; $formats = array_map(function ($path) { @@ -76,6 +117,47 @@ public function testSupportsAllConfigFormats() 'enabled' => 'auto', 'formatter' => null, ], + 'plugins' => [ + 'authentication' => [ + 'enabled' => false, + ], + 'cache' => [ + 'enabled' => false, + 'stream_factory' => 'httplug.stream_factory', + 'config' => [ + 'default_ttl' => null, + 'respect_cache_headers' => true, + ], + ], + 'cookie' => [ + 'enabled' => false, + ], + 'decoder' => [ + 'enabled' => true, + 'use_content_encoding' => true, + ], + 'history' => [ + 'enabled' => false, + ], + 'logger' => [ + 'enabled' => true, + 'logger' => 'logger', + 'formatter' => null, + ], + 'redirect' => [ + 'enabled' => true, + 'preserve_header' => true, + 'use_default_for_multiple' => true, + ], + 'retry' => [ + 'enabled' => true, + 'retry' => 1, + ], + 'stopwatch' => [ + 'enabled' => true, + 'stopwatch' => 'debug.stopwatch', + ], + ], ]; $formats = array_map(function ($path) {