diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index df0d692ebdf7a..3355a0f52824c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -51,6 +51,7 @@ CHANGELOG
6.4
---
+ * Add support for setting mock_response_factory per scoped http client
* Add `HttpClientAssertionsTrait`
* Add `AbstractController::renderBlock()` and `renderBlockView()`
* Add native return type to `Translator` and to `Application::reset()`
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 92c20d139da6e..5011a7ecaaf67 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -1866,8 +1866,13 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->append($this->createHttpClientRetrySection())
->end()
->end()
+ ->booleanNode('mock_client')
+ ->info('Inject a mock client.')
+ ->defaultFalse()
+ ->end()
->scalarNode('mock_response_factory')
- ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable.')
+ ->defaultNull()
+ ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable. Requires mock_client = true')
->end()
->arrayNode('scoped_clients')
->useAttributeAsKey('name')
@@ -2006,6 +2011,12 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->variableNode('md5')->end()
->end()
->end()
+ ->booleanNode('mock_client')
+ ->info('Inject a mock client.')
+ ->end()
+ ->scalarNode('mock_response_factory')
+ ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable')
+ ->end()
->arrayNode('extra')
->info('Extra options for specific HTTP client')
->normalizeKeys(false)
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 86355e5ca1e93..0a6f509aa5d14 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -2456,6 +2456,14 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder
->getDefinition('http_client.uri_template')
->setArgument(2, $defaultUriTemplateVars);
+ $mockByDefault = $config['mock_client'] ?? false;
+ $defaultMockResponseFactory = $config['mock_response_factory'] ?? null;
+ if ($mockByDefault) {
+ $container->register('http_client.mock_client', MockHttpClient::class)
+ ->setDecoratedService('http_client.transport', null, -10) // lower priority than TraceableHttpClient (5)
+ ->setArguments($defaultMockResponseFactory === null ? [] : [new Reference($defaultMockResponseFactory)]);
+ }
+
foreach ($config['scoped_clients'] as $name => $scopeConfig) {
if ($container->has($name)) {
throw new InvalidArgumentException(sprintf('Invalid scope name: "%s" is reserved.', $name));
@@ -2468,18 +2476,28 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder
$retryOptions = $scopeConfig['retry_failed'] ?? ['enabled' => false];
unset($scopeConfig['retry_failed']);
+ $httpClientTransport = new Reference('http_client.transport');
+
+ if ($scopeConfig['mock_client'] ?? $mockByDefault) {
+ $mockResponseFactory = $scopeConfig['mock_response_factory'] ?? $defaultMockResponseFactory;
+ $mockClientArguments = ($mockResponseFactory) ? [new Reference($mockResponseFactory)]: [];
+ $container->register('http_client.mock_client.'.$name, MockHttpClient::class)
+ ->setDecoratedService($httpClientTransport, null, -10) // lower priority than TraceableHttpClient (5)
+ ->setArguments($mockClientArguments);
+ }
+
if (null === $scope) {
$baseUri = $scopeConfig['base_uri'];
unset($scopeConfig['base_uri']);
$container->register($name, ScopingHttpClient::class)
->setFactory([ScopingHttpClient::class, 'forBaseUri'])
- ->setArguments([new Reference('http_client.transport'), $baseUri, $scopeConfig])
+ ->setArguments([$httpClientTransport, $baseUri, $scopeConfig])
->addTag('http_client.client')
;
} else {
$container->register($name, ScopingHttpClient::class)
- ->setArguments([new Reference('http_client.transport'), [$scope => $scopeConfig], $scope])
+ ->setArguments([$httpClientTransport, [$scope => $scopeConfig], $scope])
->addTag('http_client.client')
;
}
@@ -2501,6 +2519,7 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder
$defaultUriTemplateVars,
]);
+
$container->registerAliasForArgument($name, HttpClientInterface::class);
if ($hasPsr18) {
@@ -2518,11 +2537,7 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder
}
}
- if ($responseFactoryId = $config['mock_response_factory'] ?? null) {
- $container->register('http_client.mock_client', MockHttpClient::class)
- ->setDecoratedService('http_client.transport', null, -10) // lower priority than TraceableHttpClient (5)
- ->setArguments([new Reference($responseFactoryId)]);
- }
+
}
private function registerThrottlingHttpClient(string $rateLimiter, string $name, ContainerBuilder $container): void
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index d8d23168d1887..fe856463e1187 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -640,6 +640,7 @@
+
@@ -697,6 +698,8 @@
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
index b32d8681b43b3..9ac71623c98e9 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -808,6 +808,8 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
'disallow_search_engine_index' => true,
'http_client' => [
'enabled' => !class_exists(FullStack::class) && class_exists(HttpClient::class),
+ 'mock_client' => false,
+ 'mock_response_factory' => null,
'scoped_clients' => [],
],
'mailer' => [
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock.php
new file mode 100644
index 0000000000000..0496fd4e21bf0
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock.php
@@ -0,0 +1,26 @@
+dloadFromExtension('framework', [
+ 'annotations' => false,
+ 'http_method_override' => false,
+ 'handle_all_throwables' => true,
+ 'php_errors' => ['log' => true],
+ 'http_client' => [
+ 'default_options' => null,
+ 'mock_client' => true,
+ 'scoped_clients' => [
+ 'notMocked' => [
+ 'base_uri' => 'https://symfony.com',
+ 'mock_client' => false,
+ ],
+ 'mocked' => [
+ 'base_uri' => 'https://symfony.com'
+ ],
+ 'mocked_with_factory' => [
+ 'base_uri' => 'https://symfony.com',
+ 'mock_response_factory' => 'my_response_factory'
+ ],
+
+ ]
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php
index 326f0d25db503..57cc4290d2559 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php
@@ -7,6 +7,20 @@
'php_errors' => ['log' => true],
'http_client' => [
'default_options' => null,
- 'mock_response_factory' => 'my_response_factory',
+ 'mock_client' => true,
+ 'mock_response_factory' => 'my_factory',
+ 'scoped_clients' => [
+ 'notMocked' => [
+ 'base_uri' => 'https://symfony.com',
+ 'mock_client' => false,
+ ],
+ 'mocked' => [
+ 'base_uri' => 'https://symfony.com'
+ ],
+ 'mocked_custom_factory' => [
+ 'base_uri' => 'https://symfony.com',
+ 'mock_response_factory' => 'my_other_factory'
+ ]
+ ]
],
]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock.xml
new file mode 100644
index 0000000000000..0dd3d74ee002f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml
index d2bc058fb17ea..b99a4ed206f36 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml
@@ -8,8 +8,12 @@
-
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock.yml
new file mode 100644
index 0000000000000..a6365674c3487
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock.yml
@@ -0,0 +1,18 @@
+framework:
+ annotations: false
+ http_method_override: false
+ handle_all_throwables: true
+ php_errors:
+ log: true
+ http_client:
+ default_options: ~
+ mock_client: true
+ scoped_clients:
+ notMocked:
+ base_uri : https://symfony.com
+ mock_client : false
+ mocked:
+ base_uri: https://symfony.com
+ mocked_with_factory:
+ base_uri: https://symfony.com
+ mock_response_factory: 'my_response_factory'
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml
index 92c40b4591b1f..6283b80d26fc1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml
@@ -6,4 +6,14 @@ framework:
log: true
http_client:
default_options: ~
- mock_response_factory: my_response_factory
+ mock_client: true
+ mock_response_factory: 'my_factory'
+ scoped_clients:
+ notMocked:
+ base_uri : https://symfony.com
+ mock_client : false
+ mocked:
+ base_uri: https://symfony.com
+ mocked_custom_factory:
+ base_uri: https://symfony.com
+ mock_response_factory: 'my_other_factory'
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory.yml
new file mode 100644
index 0000000000000..c8c74e103be05
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory.yml
@@ -0,0 +1,16 @@
+framework:
+ annotations: false
+ http_method_override: false
+ handle_all_throwables: true
+ php_errors:
+ log: true
+ http_client:
+ default_options: ~
+ mock_response_factory: ~
+
+ scoped_clients:
+ notMocked:
+ base_uri: https://symfony.com
+ mocked:
+ base_uri: https://symfony.com
+ mock_response_factory: true
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory_service.yml
new file mode 100644
index 0000000000000..b0a1500b0e5b5
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory_service.yml
@@ -0,0 +1,16 @@
+framework:
+ annotations: false
+ http_method_override: false
+ handle_all_throwables: true
+ php_errors:
+ log: true
+ http_client:
+ default_options: ~
+ mock_response_factory: ~
+
+ scoped_clients:
+ notMocked:
+ base_uri: https://symfony.com
+ mocked:
+ base_uri: https://symfony.com
+ mock_response_factory: "my_response_factory"
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
index 2a26e786b436a..540be789d0bf5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
@@ -2095,20 +2095,63 @@ public function testMailerWithSpecificMessageBus()
$this->assertEquals(new Reference('app.another_bus'), $container->getDefinition('mailer.mailer')->getArgument(1));
}
+ public function testHttpClientNoMock()
+ {
+ $container = $this->createContainerFromFile('http_client_scoped_without_query_option');
+
+ $this->assertFalse($container->hasDefinition('http_client.mock_client.foo'));
+ $this->assertFalse($container->hasDefinition('http_client.mock_client'));
+
+ }
+
public function testHttpClientMockResponseFactory()
{
$container = $this->createContainerFromFile('http_client_mock_response_factory');
- $definition = $container->getDefinition('http_client.mock_client');
+ $this->assertFalse($container->hasDefinition('http_client.mock_client.notMocked'));
+
+ $definition = $container->getDefinition('http_client.mock_client.mocked');
$this->assertSame(MockHttpClient::class, $definition->getClass());
$this->assertCount(1, $definition->getArguments());
$argument = $definition->getArgument(0);
+ $this->assertInstanceOf(Reference::class, $argument);
+ $this->assertSame('http_client.transport', current($definition->getDecoratedService()));
+ $this->assertSame('my_factory', (string) $argument);
+
+ $definition = $container->getDefinition('http_client.mock_client.mocked_custom_factory');
+
+ $this->assertSame(MockHttpClient::class, $definition->getClass());
+ $this->assertCount(1, $definition->getArguments());
+ $argument = $definition->getArgument(0);
$this->assertInstanceOf(Reference::class, $argument);
$this->assertSame('http_client.transport', current($definition->getDecoratedService()));
- $this->assertSame('my_response_factory', (string) $argument);
+ $this->assertSame('my_other_factory', (string) $argument);
+ }
+
+ public function testHttpClientUseMockClientButOverrideInScopedClientsAndEnableFactories()
+ {
+ $container = $this->createContainerFromFile('http_client_mock');
+
+ $definition = $container->getDefinition('http_client.mock_client');
+
+ $this->assertSame(MockHttpClient::class, $definition->getClass());
+ $this->assertCount(0, $definition->getArguments());
+
+ $this->assertFalse($container->hasDefinition('http_client.mock_client.notMocked'));
+
+ $definition = $container->getDefinition('http_client.mock_client.mocked');
+
+ $this->assertSame(MockHttpClient::class, $definition->getClass());
+ $this->assertCount(0, $definition->getArguments());
+
+ $definition = $container->getDefinition('http_client.mock_client.mocked_with_factory');
+
+ $this->assertSame(MockHttpClient::class, $definition->getClass());
+ $this->assertCount(1, $definition->getArguments());
+
}
public function testRegisterParameterCollectingBehaviorDescribingTags()