Skip to content

Commit 745b8ab

Browse files
[HttpClient] add HttplugClient for compat with libs that need httplug v1 or v2
1 parent cdaa4d6 commit 745b8ab

File tree

5 files changed

+222
-0
lines changed

5 files changed

+222
-0
lines changed

src/Symfony/Component/HttpClient/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* added `$response->cancel()`
8+
* added `HttplugClient`
89

910
4.3.0
1011
-----
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpClient;
13+
14+
use Http\Client\HttpClient;
15+
use Http\Message\RequestFactory;
16+
use Http\Message\StreamFactory;
17+
use Http\Message\UriFactory;
18+
use Nyholm\Psr7\Request;
19+
use Nyholm\Psr7\Response;
20+
use Nyholm\Psr7\Stream;
21+
use Nyholm\Psr7\Uri;
22+
use Psr\Http\Client\ClientInterface;
23+
use Psr\Http\Message\ResponseFactoryInterface;
24+
use Psr\Http\Message\StreamFactoryInterface;
25+
use Psr\Http\Message\UriInterface;
26+
use Symfony\Contracts\HttpClient\HttpClientInterface;
27+
28+
if (!interface_exists(ClientInterface::class)) {
29+
throw new \LogicException('You cannot use "Symfony\Component\HttpClient\HttplugClient" as the "psr/http-client" package is not installed. Try running "composer require nyholm/psr7".');
30+
}
31+
32+
if (!interface_exists(RequestFactory::class)) {
33+
throw new \LogicException('You cannot use "Symfony\Component\HttpClient\HttplugClient" as the "php-http/message-factory" package is not installed. Try running "composer require nyholm/psr7".');
34+
}
35+
36+
/**
37+
* An adapter to turn a Symfony HttpClientInterface into an Httplug client.
38+
*
39+
* Run "composer require nyholm/psr7" to install an efficient implementation of response
40+
* and stream factories with flex-provided autowiring aliases.
41+
*
42+
* @author Nicolas Grekas <p@tchwork.com>
43+
*/
44+
final class HttplugClient implements HttpClient, RequestFactory, StreamFactory, UriFactory
45+
{
46+
use Internal\HttplugClientTrait;
47+
48+
private $client;
49+
50+
public function __construct(HttpClientInterface $client = null, ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null)
51+
{
52+
$this->client = new Psr18Client($client, $responseFactory, $streamFactory);
53+
}
54+
55+
/**
56+
* {@inheritdoc}
57+
*/
58+
public function createRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1')
59+
{
60+
if (!class_exists(Request::class)) {
61+
throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__));
62+
}
63+
64+
return new Request($method, $uri, $headers, $body, $protocolVersion);
65+
}
66+
67+
/**
68+
* {@inheritdoc}
69+
*/
70+
public function createStream($body = null)
71+
{
72+
if (!class_exists(Stream::class)) {
73+
throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__));
74+
}
75+
76+
return Stream::create($body ?? '');
77+
}
78+
79+
/**
80+
* {@inheritdoc}
81+
*/
82+
public function createUri($uri = ''): UriInterface
83+
{
84+
if ($uri instanceof UriInterface) {
85+
return $uri;
86+
}
87+
88+
if (!class_exists(Uri::class)) {
89+
throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__));
90+
}
91+
92+
return new Uri($uri);
93+
}
94+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpClient\Internal;
13+
14+
use Http\Client\HttpClient;
15+
use Http\Client\Exception\NetworkException;
16+
use Http\Client\Exception\RequestException;
17+
use Psr\Http\Client\ClientInterface;
18+
use Psr\Http\Client\NetworkExceptionInterface;
19+
use Psr\Http\Client\RequestExceptionInterface;
20+
use Psr\Http\Message\RequestInterface;
21+
use Psr\Http\Message\ResponseInterface;
22+
23+
if (is_subclass_of(HttpClient::class, ClientInterface::class)) {
24+
trait HttplugClientTrait
25+
{
26+
public function sendRequest(RequestInterface $request): ResponseInterface
27+
{
28+
try {
29+
return $this->client->sendRequest($request);
30+
} catch (RequestExceptionInterface $e) {
31+
throw new RequestException($e->getMessage(), $request, $e);
32+
} catch (NetworkExceptionInterface $e) {
33+
throw new NetworkException($e->getMessage(), $request, $e);
34+
}
35+
}
36+
}
37+
} else {
38+
trait HttplugClientTrait
39+
{
40+
/**
41+
* @return ResponseInterface
42+
*/
43+
public function sendRequest(RequestInterface $request)
44+
{
45+
try {
46+
return $this->client->sendRequest($request);
47+
} catch (RequestExceptionInterface $e) {
48+
throw new RequestException($e->getMessage(), $request, $e);
49+
} catch (NetworkExceptionInterface $e) {
50+
throw new NetworkException($e->getMessage(), $request, $e);
51+
}
52+
}
53+
}
54+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpClient\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Http\Client\Exception\NetworkException;
16+
use Http\Client\Exception\RequestException;
17+
use Symfony\Component\HttpClient\NativeHttpClient;
18+
use Symfony\Component\HttpClient\HttplugClient;
19+
use Symfony\Contracts\HttpClient\Test\TestHttpServer;
20+
21+
class HttplugClientTest extends TestCase
22+
{
23+
private static $server;
24+
25+
public static function setUpBeforeClass()
26+
{
27+
TestHttpServer::start();
28+
}
29+
30+
public function testSendRequest()
31+
{
32+
$client = new HttplugClient(new NativeHttpClient());
33+
34+
$response = $client->sendRequest($client->createRequest('GET', 'http://localhost:8057'));
35+
36+
$this->assertSame(200, $response->getStatusCode());
37+
$this->assertSame('application/json', $response->getHeaderLine('content-type'));
38+
39+
$body = json_decode((string) $response->getBody(), true);
40+
41+
$this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']);
42+
}
43+
44+
public function testPostRequest()
45+
{
46+
$client = new HttplugClient(new NativeHttpClient());
47+
48+
$request = $client->createRequest('POST', 'http://localhost:8057/post')
49+
->withBody($client->createStream('foo=0123456789'));
50+
51+
$response = $client->sendRequest($request);
52+
$body = json_decode((string) $response->getBody(), true);
53+
54+
$this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body);
55+
}
56+
57+
public function testNetworkException()
58+
{
59+
$client = new HttplugClient(new NativeHttpClient());
60+
61+
$this->expectException(NetworkException::class);
62+
$client->sendRequest($client->createRequest('GET', 'http://localhost:8058'));
63+
}
64+
65+
public function testRequestException()
66+
{
67+
$client = new HttplugClient(new NativeHttpClient());
68+
69+
$this->expectException(RequestException::class);
70+
$client->sendRequest($client->createRequest('BAD.METHOD', 'http://localhost:8057'));
71+
}
72+
}

src/Symfony/Component/HttpClient/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
}
1616
],
1717
"provide": {
18+
"php-http/client-implementation": "*",
1819
"psr/http-client-implementation": "1.0",
1920
"symfony/http-client-implementation": "1.1"
2021
},

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy