From 9bced40343cf4066ee740d01747b32160ad896b4 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 18 Nov 2024 16:03:49 +0100 Subject: [PATCH 1/3] Store references in plugins array --- src/DependencyInjection/HttplugExtension.php | 27 ++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/DependencyInjection/HttplugExtension.php b/src/DependencyInjection/HttplugExtension.php index ac032e7..2851922 100644 --- a/src/DependencyInjection/HttplugExtension.php +++ b/src/DependencyInjection/HttplugExtension.php @@ -427,17 +427,29 @@ private function configureClient(ContainerBuilder $container, string $clientName switch ($pluginName) { case 'reference': - $plugins[] = $pluginConfig['id']; + $plugins[] = new Reference($pluginConfig['id']); break; case 'authentication': - $plugins = array_merge($plugins, $this->configureAuthentication($container, $pluginConfig, $serviceId.'.authentication')); + $plugins = array_merge( + $plugins, + array_map( + fn ($id) => new Reference($id), + $this->configureAuthentication($container, $pluginConfig, $serviceId.'.authentication') + ) + ); break; case 'vcr': $this->useVcrPlugin = true; - $plugins = array_merge($plugins, $this->configureVcrPlugin($container, $pluginConfig, $serviceId.'.vcr')); + $plugins = array_merge( + $plugins, + array_map( + fn ($id) => new Reference($id), + $this->configureVcrPlugin($container, $pluginConfig, $serviceId.'.vcr'), + ), + ); break; default: - $plugins[] = $this->configurePlugin($container, $serviceId, $pluginName, $pluginConfig); + $plugins[] = new Reference($this->configurePlugin($container, $serviceId, $pluginName, $pluginConfig)); } } @@ -456,12 +468,7 @@ private function configureClient(ContainerBuilder $container, string $clientName ->register($serviceId, PluginClient::class) ->setFactory([new Reference(PluginClientFactory::class), 'createClient']) ->addArgument(new Reference($serviceId.'.client')) - ->addArgument( - array_map( - fn ($id) => new Reference($id), - $plugins - ) - ) + ->addArgument($plugins) ->addArgument([ 'client_name' => $clientName, ]) From ec73a7650537e67e5178ec454ff6c2d51f3bec97 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 18 Nov 2024 15:57:41 +0100 Subject: [PATCH 2/3] Introduce PluginConfigurator This allows for configuring plugins via the normal config. When you have a plugin that does not require config, the old behavior is the easiest. But when you do want custom config per client, it will be cumbersome to create separate services and reference them everywhere. It would be easier to have the same type of configuration as the built-in clients. That's now possible with the PluginConfigurator. Define the plugins as follows: ```yaml 'plugins' => [ [ 'configurator' => [ 'id' => CustomPluginConfigurator::class, 'config' => [ 'name' => 'foo', ] ], ], ], ``` The `CustomPluginConfigurator` looks like this: ```php final class CustomPluginConfigurator implements PluginConfigurator { public static function getConfigTreeBuilder() : TreeBuilder { $treeBuilder = new TreeBuilder('custom_plugin'); $rootNode = $treeBuilder->getRootNode(); $rootNode ->children() ->scalarNode('name') ->isRequired() ->cannotBeEmpty() ->end() ->end(); return $treeBuilder; } public function create(array $config) : CustomPlugin { return new CustomPlugin($config['name']); } } ``` On compile time, the config will be evaluated. It will create the service definition by calling the `create` method with the given config. On runtime you will have the CustomPlugin instantiated with the custom config. --- CHANGELOG.md | 4 +++ src/DependencyInjection/Configuration.php | 16 +++++++++ src/DependencyInjection/HttplugExtension.php | 13 +++++++ src/PluginConfigurator.php | 20 +++++++++++ tests/Resources/CustomPlugin.php | 24 +++++++++++++ tests/Resources/CustomPluginConfigurator.php | 32 +++++++++++++++++ tests/Resources/Fixtures/config/full.php | 10 ++++++ tests/Resources/Fixtures/config/full.xml | 7 ++++ tests/Resources/Fixtures/config/full.yml | 5 +++ .../DependencyInjection/ConfigurationTest.php | 10 ++++++ .../HttplugExtensionTest.php | 36 +++++++++++++++++++ 11 files changed, 177 insertions(+) create mode 100644 src/PluginConfigurator.php create mode 100644 tests/Resources/CustomPlugin.php create mode 100644 tests/Resources/CustomPluginConfigurator.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e37bd31..bbd21e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ The change log describes what is "Added", "Removed", "Changed" or "Fixed" betwee # Version 2 +# 2.1.0 + +- Added PluginConfigurator + # 2.0.0 - 2024-09-16 - Increased min PHP version to 8.1 diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 8456049..f9d0fdb 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -275,6 +275,22 @@ private function createClientPluginNode(): ArrayNodeDefinition ->end() ->end() ->end() + ->arrayNode('configurator') + ->canBeEnabled() + ->info('Configure a plugin with a configurator') + ->children() + ->scalarNode('id') + ->info('Service id of a plugin configurator') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->arrayNode('config') + ->normalizeKeys(false) + ->prototype('variable') + ->end() + ->end() + ->end() + ->end() ->arrayNode('add_host') ->canBeEnabled() ->addDefaultsIfNotSet() diff --git a/src/DependencyInjection/HttplugExtension.php b/src/DependencyInjection/HttplugExtension.php index 2851922..d8c913c 100644 --- a/src/DependencyInjection/HttplugExtension.php +++ b/src/DependencyInjection/HttplugExtension.php @@ -16,6 +16,7 @@ use Http\Client\HttpAsyncClient; use Http\Client\Plugin\Vcr\RecordPlugin; use Http\Client\Plugin\Vcr\ReplayPlugin; +use Http\HttplugBundle\PluginConfigurator; use Http\Message\Authentication\BasicAuth; use Http\Message\Authentication\Bearer; use Http\Message\Authentication\Header; @@ -429,6 +430,18 @@ private function configureClient(ContainerBuilder $container, string $clientName case 'reference': $plugins[] = new Reference($pluginConfig['id']); break; + case 'configurator': + if (!is_a($pluginConfig['id'], PluginConfigurator::class, true)) { + throw new \LogicException(sprintf('The plugin "%s" is not a valid PluginConfigurator.', $pluginConfig['id'])); + } + + $config = $pluginConfig['id']::getConfigTreeBuilder()->buildTree()->finalize($pluginConfig['config']); + + $definition = new Definition(null, [$config]); + $definition->setFactory([new Reference($pluginConfig['id']), 'create']); + + $plugins[] = $definition; + break; case 'authentication': $plugins = array_merge( $plugins, diff --git a/src/PluginConfigurator.php b/src/PluginConfigurator.php new file mode 100644 index 0000000..ecad176 --- /dev/null +++ b/src/PluginConfigurator.php @@ -0,0 +1,20 @@ + $config + */ + public function create(array $config): Plugin; +} diff --git a/tests/Resources/CustomPlugin.php b/tests/Resources/CustomPlugin.php new file mode 100644 index 0000000..c5d639f --- /dev/null +++ b/tests/Resources/CustomPlugin.php @@ -0,0 +1,24 @@ +name = $name; + } + + public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise + { + return $next($request); + } +} diff --git a/tests/Resources/CustomPluginConfigurator.php b/tests/Resources/CustomPluginConfigurator.php new file mode 100644 index 0000000..1d9fa32 --- /dev/null +++ b/tests/Resources/CustomPluginConfigurator.php @@ -0,0 +1,32 @@ +getRootNode(); + + $rootNode + ->children() + ->scalarNode('name') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end(); + + return $treeBuilder; + } + + public function create(array $config): CustomPlugin + { + return new CustomPlugin($config['name']); + } +} diff --git a/tests/Resources/Fixtures/config/full.php b/tests/Resources/Fixtures/config/full.php index b468f17..3c4c81b 100644 --- a/tests/Resources/Fixtures/config/full.php +++ b/tests/Resources/Fixtures/config/full.php @@ -2,6 +2,8 @@ declare(strict_types=1); +use Http\HttplugBundle\Tests\Resources\CustomPluginConfigurator; + $container->loadFromExtension('httplug', [ 'default_client_autowiring' => false, 'main_alias' => [ @@ -27,6 +29,14 @@ 'http_methods_client' => true, 'plugins' => [ 'httplug.plugin.redirect', + [ + 'configurator' => [ + 'id' => CustomPluginConfigurator::class, + 'config' => [ + 'name' => 'foo', + ], + ], + ], [ 'add_host' => [ 'host' => 'http://localhost', diff --git a/tests/Resources/Fixtures/config/full.xml b/tests/Resources/Fixtures/config/full.xml index d47867d..a233cde 100644 --- a/tests/Resources/Fixtures/config/full.xml +++ b/tests/Resources/Fixtures/config/full.xml @@ -22,6 +22,13 @@ httplug.plugin.redirect + + + + foo + + + diff --git a/tests/Resources/Fixtures/config/full.yml b/tests/Resources/Fixtures/config/full.yml index 7e05459..5d71166 100644 --- a/tests/Resources/Fixtures/config/full.yml +++ b/tests/Resources/Fixtures/config/full.yml @@ -21,6 +21,11 @@ httplug: http_methods_client: true plugins: - 'httplug.plugin.redirect' + - + configurator: + id: Http\HttplugBundle\Tests\Resources\CustomPluginConfigurator + config: + name: foo - add_host: host: http://localhost diff --git a/tests/Unit/DependencyInjection/ConfigurationTest.php b/tests/Unit/DependencyInjection/ConfigurationTest.php index b765450..6ba3d3a 100644 --- a/tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/tests/Unit/DependencyInjection/ConfigurationTest.php @@ -7,6 +7,7 @@ use Http\Adapter\Guzzle7\Client; use Http\HttplugBundle\DependencyInjection\Configuration; use Http\HttplugBundle\DependencyInjection\HttplugExtension; +use Http\HttplugBundle\Tests\Resources\CustomPluginConfigurator; use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionConfigurationTestCase; use Nyholm\Psr7\Factory\Psr17Factory; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -155,6 +156,15 @@ public function testSupportsAllConfigFormats(): void 'id' => 'httplug.plugin.redirect', ], ], + [ + 'configurator' => [ + 'enabled' => true, + 'id' => CustomPluginConfigurator::class, + 'config' => [ + 'name' => 'foo', + ], + ], + ], [ 'add_host' => [ 'enabled' => true, diff --git a/tests/Unit/DependencyInjection/HttplugExtensionTest.php b/tests/Unit/DependencyInjection/HttplugExtensionTest.php index 8e10577..a1c51a2 100644 --- a/tests/Unit/DependencyInjection/HttplugExtensionTest.php +++ b/tests/Unit/DependencyInjection/HttplugExtensionTest.php @@ -7,8 +7,10 @@ use Http\Adapter\Guzzle7\Client; use Http\Client\Plugin\Vcr\Recorder\InMemoryRecorder; use Http\HttplugBundle\DependencyInjection\HttplugExtension; +use Http\HttplugBundle\Tests\Resources\CustomPluginConfigurator; use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase; use Psr\Http\Client\ClientInterface; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; /** @@ -203,6 +205,40 @@ public function testClientPlugins(): void $this->assertContainerBuilderHasService('httplug.client.mock'); } + public function testPluginConfiguratorConfig(): void + { + $config = [ + 'clients' => [ + 'acme' => [ + 'factory' => 'httplug.factory.curl', + 'plugins' => [ + [ + 'configurator' => [ + 'id' => CustomPluginConfigurator::class, + 'config' => [ + 'name' => 'foo', + ], + ], + ], + ], + ], + ], + ]; + + $this->load($config); + + $definition = new Definition(null, [ + ['name' => 'foo'], + ]); + $definition->setFactory([CustomPluginConfigurator::class, 'create']); + + $this->assertContainerBuilderHasService('httplug.client.acme'); + $this->assertContainerBuilderHasServiceDefinitionWithArgument('httplug.client.acme', 1, [ + $definition, + ]); + $this->assertContainerBuilderHasService('httplug.client.mock'); + } + public function testNoProfilingWhenNotInDebugMode(): void { $this->setParameter('kernel.debug', false); From b6d98d19480456530c751fdd7dafc4d8320f6a36 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sun, 24 Nov 2024 10:47:56 +0100 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbd21e5..1843819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The change log describes what is "Added", "Removed", "Changed" or "Fixed" betwee # 2.1.0 -- Added PluginConfigurator +- Added [PluginConfigurator](https://docs.php-http.org/en/latest/integrations/symfony-bundle.html#configure-a-custom-plugin) # 2.0.0 - 2024-09-16