diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index ad3ff11..d31c148 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -68,7 +68,7 @@ jobs:
if: contains(matrix.symfony, '@dev')
- run: composer update --no-interaction --no-progress --ansi ${{ matrix.composer_option }}
- run: |
- sed -ri 's/"symfony\/(.+)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony }}'"/' composer.json;
+ sed -ri 's/"symfony\/(config|dependency-injection|form|http-kernel|validator)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony }}'"/' composer.json;
if: matrix.symfony
- run: composer update --no-interaction --no-progress --ansi ${{ matrix.composer_option }}
- name: Run tests
diff --git a/composer.json b/composer.json
index 5368778..39c49fd 100644
--- a/composer.json
+++ b/composer.json
@@ -26,6 +26,7 @@
},
"require-dev": {
"phpunit/phpunit": "^9.6",
+ "symfony/http-client-contracts": "^3.5",
"symfony/phpunit-bridge": "^7.2"
},
"suggest": {
diff --git a/config/services.xml b/config/services.xml
index 7350148..ae280fa 100644
--- a/config/services.xml
+++ b/config/services.xml
@@ -10,6 +10,11 @@
%beelab_recaptcha2.secret%
+
+
+
+
+
%beelab_recaptcha2.site_key%
diff --git a/docs/index.md b/docs/index.md
index 16dc829..82d4ba1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -40,18 +40,22 @@ beelab_recaptcha2:
If your PHP environment has restrictions about `file_get_contents()` making HTTP requests,
you can use another `RequestMethod` from Google's Recaptcha library.
-Currently, this bundle supports the default `Post` and `CurlPost` methods.
-You can use the latter by adding in your `config.yml`:
+Currently, this bundle supports the default `Post` and `CurlPost` methods, and an additional
+method leveraging the [Symfony HTTP Client][1].
+You can define it by adding in your configuration:
```yaml
# config/packages/beelab_recaptcha2.yaml
beelab_recaptcha2:
- request_method: curl_post
+ request_method: curl_post # or http_client
```
Otherwise, the default value `post` will be used.
+If you want to use the `http_client` request method, you need to require `symfony/http-client`.
+
+
## 3. Usage
In your form, use `Beelab\Recaptcha2Bundle\Form\Type\RecaptchaType` form type, as any other Symfony form type.
@@ -125,3 +129,4 @@ You can add to your `_form_theme.html.twig` file the following lines:
{%- endblock %}
```
+[1]: https://symfony.com/doc/current/http_client.html
diff --git a/src/DependencyInjection/BeelabRecaptcha2Extension.php b/src/DependencyInjection/BeelabRecaptcha2Extension.php
index 2760b58..7f7d1ee 100644
--- a/src/DependencyInjection/BeelabRecaptcha2Extension.php
+++ b/src/DependencyInjection/BeelabRecaptcha2Extension.php
@@ -2,6 +2,7 @@
namespace Beelab\Recaptcha2Bundle\DependencyInjection;
+use Beelab\Recaptcha2Bundle\Recaptcha\SymfonyClientRequestMethod;
use ReCaptcha\RequestMethod\CurlPost;
use ReCaptcha\RequestMethod\Post;
use Symfony\Component\Config\FileLocator;
@@ -30,6 +31,7 @@ private function getRequestMethod(string $requestMethod): string
{
return match ($requestMethod) {
'curl_post' => CurlPost::class,
+ 'http_client' => SymfonyClientRequestMethod::class,
default => Post::class,
};
}
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 8d0dafd..714e24e 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -14,7 +14,7 @@ public function getConfigTreeBuilder(): TreeBuilder
$rootNode
->children()
->enumNode('request_method')
- ->values(['curl_post', 'post'])
+ ->values(['curl_post', 'post', 'http_client'])
->defaultValue('post')
->end()
->scalarNode('site_key')
diff --git a/src/Recaptcha/SymfonyClientRequestMethod.php b/src/Recaptcha/SymfonyClientRequestMethod.php
new file mode 100644
index 0000000..62e74ed
--- /dev/null
+++ b/src/Recaptcha/SymfonyClientRequestMethod.php
@@ -0,0 +1,43 @@
+client = $client;
+ }
+
+ public function submit(RequestParameters $params): string
+ {
+ if (null === $this->client) {
+ throw new \UnexpectedValueException('Needed service is not injected.');
+ }
+
+ $response = $this->client->request('POST', $this->siteVerifyUrl, [
+ 'body' => $params->toQueryString(),
+ 'headers' => [
+ 'Content-Type' => 'application/x-www-form-urlencoded',
+ ],
+ ]);
+
+ if (200 !== $response->getStatusCode()) {
+ return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}';
+ }
+
+ return $response->getContent();
+ }
+}
diff --git a/tests/Recaptcha/SymfonyClientRequestMethodTest.php b/tests/Recaptcha/SymfonyClientRequestMethodTest.php
new file mode 100644
index 0000000..9b40f8a
--- /dev/null
+++ b/tests/Recaptcha/SymfonyClientRequestMethodTest.php
@@ -0,0 +1,51 @@
+client = $this->createMock(HttpClientInterface::class);
+ }
+
+ public function testServiceNotInjected(): void
+ {
+ $method = new SymfonyClientRequestMethod();
+ $this->expectException(\UnexpectedValueException::class);
+
+ $method->submit(new RequestParameters('', ''));
+ }
+
+ public function testRequestFailure(): void
+ {
+ $method = new SymfonyClientRequestMethod();
+ $method->setClient($this->client);
+ $response = $this->createMock(ResponseInterface::class);
+ $response->expects($this->once())->method('getStatusCode')->willReturn(404);
+ $this->client->expects($this->once())->method('request')->willReturn($response);
+ $content = $method->submit(new RequestParameters('', ''));
+ self::assertEquals('{"success": false, "error-codes": ["connection-failed"]}', $content);
+ }
+
+ public function testRequestSuccess(): void
+ {
+ $method = new SymfonyClientRequestMethod();
+ $method->setClient($this->client);
+ $response = $this->createMock(ResponseInterface::class);
+ $response->expects($this->once())->method('getStatusCode')->willReturn(200);
+ $response->expects($this->once())->method('getContent')->willReturn('"OK"');
+ $this->client->expects($this->once())->method('request')->willReturn($response);
+ $content = $method->submit(new RequestParameters('', ''));
+ self::assertEquals('"OK"', $content);
+ }
+}