Skip to content

Commit b36ddb5

Browse files
authored
Merge pull request #566 from FriendsOfSymfony/psr-http
use psr17 and psr18 factories
2 parents 4b4751b + b98accf commit b36ddb5

File tree

11 files changed

+110
-104
lines changed

11 files changed

+110
-104
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ See also the [GitHub releases page](https://github.com/FriendsOfSymfony/FOSHttpC
1313
* Drop support for Symfony < 6.4
1414
* Test with PHP 8.2 and 8.3
1515
* Drop support for PHP < 8.1
16+
* Switched to PSR-17 message factories
17+
* Switched some places to PSR-18 HTTP client. The main functionality needs the Httplug Async Client specification. There is no PSR for asynchronous clients.
1618
* Parameter and return type declarations where possible.
1719
* Ignore empty tag lists passed to `TagCapable::invalidateTags` so you don't need to check if there are tags or not.
1820

composer.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
"php": "^8.1",
2525
"symfony/event-dispatcher": "^6.4 || ^7.0",
2626
"symfony/options-resolver": "^6.4 || ^7.0",
27-
"php-http/client-implementation": "^1.0 || ^2.0",
2827
"php-http/client-common": "^1.1.0 || ^2.0",
29-
"php-http/message": "^1.0 || ^2.0",
30-
"php-http/message-factory": "^1.0",
31-
"php-http/discovery": "^1.12"
28+
"php-http/discovery": "^1.12",
29+
"php-http/async-client-implementation": "^1.1.0 || ^2.0",
30+
"psr/http-client-implementation": "^1.0 || ^2.0",
31+
"psr/http-factory": "^1.0"
3232
},
3333
"require-dev": {
3434
"mockery/mockery": "^1.6.0",
@@ -41,7 +41,8 @@
4141
},
4242
"conflict": {
4343
"toflar/psr6-symfony-http-cache-store": "<2.2.1",
44-
"phpunit/phpunit": "<10"
44+
"phpunit/phpunit": "<10",
45+
"guzzlehttp/psr7": "<2"
4546
},
4647
"suggest": {
4748
"friendsofsymfony/http-cache-bundle": "For integration with the Symfony framework",

doc/installation.rst

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,15 @@ and its dependencies using Composer_:
99

1010
.. code-block:: bash
1111
12-
$ composer require friendsofsymfony/http-cache
13-
14-
The library relies on HTTPlug_ for sending invalidation requests over HTTP, so
15-
you need to install an HTTPlug-compatible client or adapter first:
16-
17-
.. code-block:: bash
18-
19-
$ composer require php-http/guzzle6-adapter
20-
21-
You also need a `PSR-7 message implementation`_. If you use Guzzle 6, Guzzle’s
22-
implementation is already included. If you use another client, you need to
23-
install one of the message implementations. Recommended:
24-
25-
.. code-block:: bash
26-
27-
$ composer require guzzlehttp/psr7
12+
$ composer require friendsofsymfony/http-cache
2813
29-
Alternatively:
14+
The library relies on HTTPlug_ for asynchronously sending invalidation requests
15+
over HTTP. There is no PSR for asynchronous HTTP client, you need to install an
16+
HTTPlug-compatible client or adapter:
3017

3118
.. code-block:: bash
3219
33-
$ composer require zendframework/zend-diactoros
20+
$ composer require php-http/guzzle7-adapter
3421
3522
Then install the FOSHttpCache library itself:
3623

@@ -73,6 +60,5 @@ invalidation requests:
7360

7461
.. _Packagist: https://packagist.org/packages/friendsofsymfony/http-cache
7562
.. _Composer: http://getcomposer.org
76-
.. _PSR-7 message implementation: https://packagist.org/providers/psr/http-message-implementation
7763
.. _Semantic Versioning: http://semver.org/
7864
.. _HTTPlug: http://httplug.io

doc/proxy-clients.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,9 @@ all requests together, reducing the performance impact of sending invalidation
447447
requests.
448448

449449
.. _HTTPlug: http://httplug.io/
450-
.. _HTTPlug discovery: http://php-http.readthedocs.io/en/latest/discovery.html
451-
.. _in the HTTPlug documentation: http://php-http.readthedocs.io/en/latest/clients.html
452-
.. _HTTPlug plugins: http://php-http.readthedocs.io/en/latest/plugins/index.html
453-
.. _message factory and URI factory: http://php-http.readthedocs.io/en/latest/message/message-factory.html
450+
.. _HTTPlug discovery: https://docs.php-http.org/en/latest/discovery.html
451+
.. _in the HTTPlug documentation: https://docs.php-http.org/en/latest/clients.html
452+
.. _HTTPlug plugins: https://docs.php-http.org/en/latest/plugins/index.html
454453
.. _Toflar Psr6Store: https://github.com/Toflar/psr6-symfony-http-cache-store
455454
.. _Fastly Purge API: https://docs.fastly.com/api/purge
456455
.. _Cloudflare: https://developers.cloudflare.com/cache/

src/ProxyClient/Cloudflare.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use FOS\HttpCache\ProxyClient\Invalidation\ClearCapable;
1515
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
1616
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
17-
use Http\Message\RequestFactory;
17+
use Psr\Http\Message\RequestFactoryInterface;
1818
use Psr\Http\Message\UriInterface;
1919
use Symfony\Component\OptionsResolver\OptionsResolver;
2020

@@ -54,13 +54,13 @@ class Cloudflare extends HttpProxyClient implements ClearCapable, PurgeCapable,
5454
public function __construct(
5555
Dispatcher $dispatcher,
5656
array $options = [],
57-
?RequestFactory $messageFactory = null
57+
?RequestFactoryInterface $requestFactory = null
5858
) {
5959
if (!function_exists('json_encode')) {
6060
throw new \Exception('ext-json is required for cloudflare invalidation');
6161
}
6262

63-
parent::__construct($dispatcher, $options, $messageFactory);
63+
parent::__construct($dispatcher, $options, $requestFactory);
6464
}
6565

6666
/**

src/ProxyClient/Fastly.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
1616
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
1717
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
18-
use Http\Message\RequestFactory;
18+
use Psr\Http\Message\RequestFactoryInterface;
1919
use Psr\Http\Message\UriInterface;
2020
use Symfony\Component\OptionsResolver\OptionsResolver;
2121

@@ -50,13 +50,13 @@ class Fastly extends HttpProxyClient implements ClearCapable, PurgeCapable, Refr
5050
public function __construct(
5151
Dispatcher $dispatcher,
5252
array $options = [],
53-
?RequestFactory $messageFactory = null
53+
?RequestFactoryInterface $requestFactory = null
5454
) {
5555
if (!function_exists('json_encode')) {
5656
throw new \Exception('ext-json is required for fastly invalidation');
5757
}
5858

59-
parent::__construct($dispatcher, $options, $messageFactory);
59+
parent::__construct($dispatcher, $options, $requestFactory);
6060
}
6161

6262
/**
@@ -81,7 +81,7 @@ public function invalidateTags(array $tags): static
8181
$url,
8282
$headers,
8383
false,
84-
json_encode(['surrogate_keys' => $tagChunk])
84+
json_encode(['surrogate_keys' => $tagChunk], JSON_THROW_ON_ERROR)
8585
);
8686
}
8787

src/ProxyClient/HttpDispatcher.php

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
use Http\Client\Exception\NetworkException;
2424
use Http\Client\HttpAsyncClient;
2525
use Http\Discovery\HttpAsyncClientDiscovery;
26-
use Http\Discovery\UriFactoryDiscovery;
27-
use Http\Message\UriFactory;
26+
use Http\Discovery\Psr17FactoryDiscovery;
2827
use Http\Promise\Promise;
2928
use Psr\Http\Message\RequestInterface;
29+
use Psr\Http\Message\UriFactoryInterface;
3030
use Psr\Http\Message\UriInterface;
3131

3232
/**
@@ -37,7 +37,7 @@
3737
class HttpDispatcher implements Dispatcher
3838
{
3939
private HttpAsyncClient $httpClient;
40-
private UriFactory $uriFactory;
40+
private UriFactoryInterface $uriFactory;
4141

4242
/**
4343
* Queued requests.
@@ -66,24 +66,24 @@ class HttpDispatcher implements Dispatcher
6666
* class and overwrite getServers. Be sure to have some caching in
6767
* getServers.
6868
*
69-
* @param string[] $servers Caching proxy server hostnames or IP
70-
* addresses, including port if not port 80.
71-
* E.g. ['127.0.0.1:6081']
72-
* @param string $baseUri Default application hostname, optionally
73-
* including base URL, for purge and refresh
74-
* requests (optional). This is required if
75-
* you purge and refresh paths instead of
76-
* absolute URLs
77-
* @param HttpAsyncClient|null $httpClient Client capable of sending HTTP requests. If no
78-
* client is supplied, a default one is created
79-
* @param UriFactory|null $uriFactory Factory for PSR-7 URIs. If not specified, a
80-
* default one is created
69+
* @param string[] $servers Caching proxy server hostnames or IP
70+
* addresses, including port if not port 80.
71+
* E.g. ['127.0.0.1:6081']
72+
* @param string $baseUri Default application hostname, optionally
73+
* including base URL, for purge and refresh
74+
* requests (optional). This is required if
75+
* you purge and refresh paths instead of
76+
* absolute URLs
77+
* @param HttpAsyncClient|null $httpClient Client capable of sending HTTP requests. If no
78+
* client is supplied, a default one is created
79+
* @param UriFactoryInterface|null $uriFactory Factory for PSR-7 URIs. If not specified, a
80+
* default one is created
8181
*/
8282
public function __construct(
8383
array $servers,
8484
string $baseUri = '',
8585
?HttpAsyncClient $httpClient = null,
86-
?UriFactory $uriFactory = null
86+
?UriFactoryInterface $uriFactory = null,
8787
) {
8888
if (!$httpClient) {
8989
$httpClient = new PluginClient(
@@ -92,7 +92,7 @@ public function __construct(
9292
);
9393
}
9494
$this->httpClient = $httpClient;
95-
$this->uriFactory = $uriFactory ?: UriFactoryDiscovery::find();
95+
$this->uriFactory = $uriFactory ?: Psr17FactoryDiscovery::findUriFactory();
9696

9797
$this->setServers($servers);
9898
$this->setBaseUri($baseUri);
@@ -286,7 +286,7 @@ private function filterUri(string $uriString, array $allowedParts = []): UriInte
286286

287287
try {
288288
$uri = $this->uriFactory->createUri($uriString);
289-
} catch (\InvalidArgumentException $e) {
289+
} catch (\InvalidArgumentException) {
290290
throw InvalidUrlException::invalidUrl($uriString);
291291
}
292292

src/ProxyClient/HttpProxyClient.php

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111

1212
namespace FOS\HttpCache\ProxyClient;
1313

14-
use Http\Discovery\MessageFactoryDiscovery;
15-
use Http\Message\RequestFactory;
14+
use Http\Discovery\Psr17FactoryDiscovery;
15+
use Psr\Http\Message\RequestFactoryInterface;
16+
use Psr\Http\Message\StreamFactoryInterface;
1617
use Psr\Http\Message\StreamInterface;
1718
use Psr\Http\Message\UriInterface;
1819
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -29,7 +30,8 @@ abstract class HttpProxyClient implements ProxyClient
2930
*/
3031
private Dispatcher $httpDispatcher;
3132

32-
private RequestFactory $requestFactory;
33+
private RequestFactoryInterface $requestFactory;
34+
private StreamFactoryInterface $streamFactory;
3335

3436
/**
3537
* The options configured in the constructor argument or default values.
@@ -41,19 +43,23 @@ abstract class HttpProxyClient implements ProxyClient
4143
/**
4244
* The base class has no options.
4345
*
44-
* @param Dispatcher $dispatcher Helper to send instructions to the caching proxy
45-
* @param array $options Options for this client
46-
* @param RequestFactory|null $messageFactory Factory for PSR-7 messages. If none supplied,
47-
* a default one is created
46+
* @param Dispatcher $dispatcher Helper to send instructions to the caching proxy
47+
* @param array $options Options for this client
48+
* @param RequestFactoryInterface|null $requestFactory Factory for PSR-7 messages. If none supplied,
49+
* a default one is created
50+
* @param StreamFactoryInterface|null $streamFactory Factory for PSR-7 streams. If none supplied,
51+
* a default one is created
4852
*/
4953
public function __construct(
5054
Dispatcher $dispatcher,
5155
array $options = [],
52-
?RequestFactory $messageFactory = null
56+
?RequestFactoryInterface $requestFactory = null,
57+
?StreamFactoryInterface $streamFactory = null,
5358
) {
5459
$this->httpDispatcher = $dispatcher;
5560
$this->options = $this->configureOptions()->resolve($options);
56-
$this->requestFactory = $messageFactory ?: MessageFactoryDiscovery::find();
61+
$this->requestFactory = $requestFactory ?: Psr17FactoryDiscovery::findRequestFactory();
62+
$this->streamFactory = $streamFactory ?: Psr17FactoryDiscovery::findStreamFactory();
5763
}
5864

5965
public function flush(): int
@@ -78,10 +84,20 @@ protected function configureOptions(): OptionsResolver
7884
*/
7985
protected function queueRequest(string $method, UriInterface|string $url, array $headers, bool $validateHost = true, $body = null): void
8086
{
81-
$this->httpDispatcher->invalidate(
82-
$this->requestFactory->createRequest($method, $url, $headers, $body),
83-
$validateHost
84-
);
87+
$request = $this->requestFactory->createRequest($method, $url);
88+
foreach ($headers as $name => $value) {
89+
$request = $request->withHeader($name, $value);
90+
}
91+
if ($body) {
92+
if (is_string($body)) {
93+
$body = $this->streamFactory->createStream($body);
94+
} elseif (is_resource($body)) {
95+
$body = $this->streamFactory->createStreamFromResource($body);
96+
}
97+
$request = $request->withBody($body);
98+
}
99+
100+
$this->httpDispatcher->invalidate($request, $validateHost);
85101
}
86102

87103
/**

src/Test/HttpClient.php

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111

1212
namespace FOS\HttpCache\Test;
1313

14-
use Http\Client\HttpClient as PhpHttpClient;
15-
use Http\Discovery\HttpClientDiscovery;
16-
use Http\Discovery\MessageFactoryDiscovery;
17-
use Http\Discovery\UriFactoryDiscovery;
14+
use Http\Discovery\Psr17FactoryDiscovery;
15+
use Http\Discovery\Psr18ClientDiscovery;
16+
use Psr\Http\Client\ClientInterface;
1817
use Psr\Http\Message\RequestInterface;
1918
use Psr\Http\Message\ResponseInterface;
2019
use Psr\Http\Message\UriInterface;
@@ -27,7 +26,7 @@ class HttpClient
2726
/**
2827
* HTTP client for requests to the application.
2928
*/
30-
private PhpHttpClient $httpClient;
29+
private ClientInterface $httpClient;
3130

3231
private string $hostname;
3332

@@ -72,10 +71,10 @@ public function sendRequest(RequestInterface $request): ResponseInterface
7271
/**
7372
* Get HTTP client for your application.
7473
*/
75-
private function getHttpClient(): PhpHttpClient
74+
private function getHttpClient(): ClientInterface
7675
{
7776
if (!isset($this->httpClient)) {
78-
$this->httpClient = HttpClientDiscovery::find();
77+
$this->httpClient = Psr18ClientDiscovery::find();
7978
}
8079

8180
return $this->httpClient;
@@ -102,18 +101,22 @@ private function createRequest(string $method, string $uri, array $headers): Req
102101
$uri = $uri->withScheme('http');
103102
}
104103

105-
return MessageFactoryDiscovery::find()->createRequest(
104+
$request = Psr17FactoryDiscovery::findRequestFactory()->createRequest(
106105
$method,
107-
$uri,
108-
$headers
106+
$uri
109107
);
108+
foreach ($headers as $name => $value) {
109+
$request = $request->withHeader($name, $value);
110+
}
111+
112+
return $request;
110113
}
111114

112115
/**
113116
* Create PSR-7 URI object from URI string.
114117
*/
115118
private function createUri(string $uriString): UriInterface
116119
{
117-
return UriFactoryDiscovery::find()->createUri($uriString);
120+
return Psr17FactoryDiscovery::findUriFactory()->createUri($uriString);
118121
}
119122
}

tests/Functional/ProxyClient/HttpDispatcherTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
use FOS\HttpCache\Exception\ProxyResponseException;
1616
use FOS\HttpCache\Exception\ProxyUnreachableException;
1717
use FOS\HttpCache\ProxyClient\HttpDispatcher;
18-
use Http\Discovery\MessageFactoryDiscovery;
18+
use Http\Discovery\Psr17FactoryDiscovery;
1919
use PHPUnit\Framework\TestCase;
2020

2121
class HttpDispatcherTest extends TestCase
2222
{
2323
public function testNetworkError(): void
2424
{
25-
$requestFactory = MessageFactoryDiscovery::find();
25+
$requestFactory = Psr17FactoryDiscovery::findRequestFactory();
2626
$dispatcher = new HttpDispatcher(['localhost:1']);
2727
$dispatcher->invalidate($requestFactory->createRequest('GET', 'http://fos.test/foobar'));
2828

@@ -36,7 +36,7 @@ public function testNetworkError(): void
3636

3737
public function testClientError(): void
3838
{
39-
$requestFactory = MessageFactoryDiscovery::find();
39+
$requestFactory = Psr17FactoryDiscovery::findRequestFactory();
4040
$dispatcher = new HttpDispatcher(['http://foshttpcache.readthedocs.io']);
4141
$dispatcher->invalidate($requestFactory->createRequest('GET', 'http://fos.test/this-url-should-not-exist'));
4242

0 commit comments

Comments
 (0)