diff --git a/CHANGELOG.md b/CHANGELOG.md index f24c2c4..f115d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ - Interface method `Plugin::handleRequest(...)` has now an explicit return type (`Http\Promise\Promise`) - Made classes final that are not intended to be extended. Added interfaces for BatchClient, HttpClientRouter and HttpMethodsClient. - The implementations of those utilities have been renamed with an `Impl` suffix. + (These interfaces use the `Interface` suffix to avoid name collisions.) - Added an interface for HttpClientPool and moved the abstract class to the HttpClientPool sub namespace. ### Removed diff --git a/spec/BatchClientImplSpec.php b/spec/BatchClientSpec.php similarity index 88% rename from spec/BatchClientImplSpec.php rename to spec/BatchClientSpec.php index 84df29f..86c6c8b 100644 --- a/spec/BatchClientImplSpec.php +++ b/spec/BatchClientSpec.php @@ -6,16 +6,16 @@ use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use PhpSpec\ObjectBehavior; -use Http\Client\Common\BatchClientImpl; +use Http\Client\Common\BatchClient; use Http\Client\Common\BatchResult; use Http\Client\Exception\HttpException; use Http\Client\Common\Exception\BatchException; -class BatchClientImplSpec extends ObjectBehavior +class BatchClientSpec extends ObjectBehavior { public function let(HttpClient $client) { - $this->beAnInstanceOf(BatchClientImpl::class, [$client]); + $this->beAnInstanceOf(BatchClient::class, [$client]); } public function it_send_multiple_request_using_send_request(HttpClient $client, RequestInterface $request1, RequestInterface $request2, ResponseInterface $response1, ResponseInterface $response2) diff --git a/spec/HttpClientRouterImplSpec.php b/spec/HttpClientRouterSpec.php similarity index 90% rename from spec/HttpClientRouterImplSpec.php rename to spec/HttpClientRouterSpec.php index afb0591..a409203 100644 --- a/spec/HttpClientRouterImplSpec.php +++ b/spec/HttpClientRouterSpec.php @@ -2,7 +2,7 @@ namespace spec\Http\Client\Common; -use Http\Client\Common\HttpClientRouterImpl; +use Http\Client\Common\HttpClientRouter; use Http\Message\RequestMatcher; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; @@ -10,19 +10,19 @@ use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use PhpSpec\ObjectBehavior; -use Http\Client\Common\HttpClientRouter; +use Http\Client\Common\HttpClientRouterInterface; use Http\Client\Exception\RequestException; -class HttpClientRouterImplSpec extends ObjectBehavior +class HttpClientRouterSpec extends ObjectBehavior { public function it_is_initializable() { - $this->shouldHaveType(HttpClientRouterImpl::class); + $this->shouldHaveType(HttpClientRouter::class); } public function it_is_an_http_client_router() { - $this->shouldImplement(HttpClientRouter::class); + $this->shouldImplement(HttpClientRouterInterface::class); } public function it_is_an_http_client() diff --git a/spec/HttpMethodsClientImplSpec.php b/spec/HttpMethodsClientSpec.php similarity index 96% rename from spec/HttpMethodsClientImplSpec.php rename to spec/HttpMethodsClientSpec.php index 8ca90ab..68e124d 100644 --- a/spec/HttpMethodsClientImplSpec.php +++ b/spec/HttpMethodsClientSpec.php @@ -2,14 +2,14 @@ namespace spec\Http\Client\Common; -use Http\Client\Common\HttpMethodsClientImpl; +use Http\Client\Common\HttpMethodsClient; use Http\Client\HttpClient; use Http\Message\RequestFactory; use PhpSpec\ObjectBehavior; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -class HttpMethodsClientImplSpec extends ObjectBehavior +class HttpMethodsClientSpec extends ObjectBehavior { private static $requestData = [ 'uri' => '/uri', @@ -22,7 +22,7 @@ class HttpMethodsClientImplSpec extends ObjectBehavior public function let(HttpClient $client, RequestFactory $requestFactory) { $this->beAnInstanceOf( - HttpMethodsClientImpl::class, [ + HttpMethodsClient::class, [ $client, $requestFactory, ] diff --git a/src/BatchClient.php b/src/BatchClient.php index 56677b1..09a83ff 100644 --- a/src/BatchClient.php +++ b/src/BatchClient.php @@ -6,29 +6,42 @@ use Http\Client\HttpClient; use Http\Client\Common\Exception\BatchException; use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; -/** - * BatchClient allow to sends multiple request and retrieve a Batch Result. - * - * This implementation simply loops over the requests and uses sendRequest with each of them. - * - * @author Joel Wurtz - */ -interface BatchClient extends HttpClient +final class BatchClient implements BatchClientInterface { /** - * Send several requests. - * - * You may not assume that the requests are executed in a particular order. If the order matters - * for your application, use sendRequest sequentially. - * - * @param RequestInterface[] The requests to send - * - * @return BatchResult Containing one result per request - * - * @throws BatchException If one or more requests fails. The exception gives access to the - * BatchResult with a map of request to result for success, request to - * exception for failures + * @var HttpClient */ - public function sendRequests(array $requests): BatchResult; + private $client; + + public function __construct(HttpClient $client) + { + $this->client = $client; + } + + public function sendRequest(RequestInterface $request): ResponseInterface + { + return $this->client->sendRequest($request); + } + + public function sendRequests(array $requests): BatchResult + { + $batchResult = new BatchResult(); + + foreach ($requests as $request) { + try { + $response = $this->sendRequest($request); + $batchResult = $batchResult->addResponse($request, $response); + } catch (Exception $e) { + $batchResult = $batchResult->addException($request, $e); + } + } + + if ($batchResult->hasExceptions()) { + throw new BatchException($batchResult); + } + + return $batchResult; + } } diff --git a/src/BatchClientImpl.php b/src/BatchClientImpl.php deleted file mode 100644 index dbf78ee..0000000 --- a/src/BatchClientImpl.php +++ /dev/null @@ -1,47 +0,0 @@ -client = $client; - } - - public function sendRequest(RequestInterface $request): ResponseInterface - { - return $this->client->sendRequest($request); - } - - public function sendRequests(array $requests): BatchResult - { - $batchResult = new BatchResult(); - - foreach ($requests as $request) { - try { - $response = $this->sendRequest($request); - $batchResult = $batchResult->addResponse($request, $response); - } catch (Exception $e) { - $batchResult = $batchResult->addException($request, $e); - } - } - - if ($batchResult->hasExceptions()) { - throw new BatchException($batchResult); - } - - return $batchResult; - } -} diff --git a/src/BatchClientInterface.php b/src/BatchClientInterface.php new file mode 100644 index 0000000..ce6c3c7 --- /dev/null +++ b/src/BatchClientInterface.php @@ -0,0 +1,34 @@ + + */ +interface BatchClientInterface extends HttpClient +{ + /** + * Send several requests. + * + * You may not assume that the requests are executed in a particular order. If the order matters + * for your application, use sendRequest sequentially. + * + * @param RequestInterface[] The requests to send + * + * @return BatchResult Containing one result per request + * + * @throws BatchException If one or more requests fails. The exception gives access to the + * BatchResult with a map of request to result for success, request to + * exception for failures + */ + public function sendRequests(array $requests): BatchResult; +} diff --git a/src/HttpClientRouter.php b/src/HttpClientRouter.php index 403efa8..56be0bf 100644 --- a/src/HttpClientRouter.php +++ b/src/HttpClientRouter.php @@ -2,23 +2,67 @@ namespace Http\Client\Common; +use Http\Client\Exception\RequestException; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; use Http\Message\RequestMatcher; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; /** - * Route a request to a specific client in the stack based using a RequestMatcher. - * - * This is not a HttpClientPool client because it uses a matcher to select the client. + * {@inheritdoc} * * @author Joel Wurtz */ -interface HttpClientRouter extends HttpClient, HttpAsyncClient +final class HttpClientRouter implements HttpClientRouterInterface { + /** + * @var array + */ + private $clients = []; + + /** + * {@inheritdoc} + */ + public function sendRequest(RequestInterface $request): ResponseInterface + { + return $this->chooseHttpClient($request)->sendRequest($request); + } + + /** + * {@inheritdoc} + */ + public function sendAsyncRequest(RequestInterface $request) + { + return $this->chooseHttpClient($request)->sendAsyncRequest($request); + } + /** * Add a client to the router. * * @param HttpClient|HttpAsyncClient $client */ - public function addClient($client, RequestMatcher $requestMatcher); + public function addClient($client, RequestMatcher $requestMatcher) + { + $this->clients[] = [ + 'matcher' => $requestMatcher, + 'client' => new FlexibleHttpClient($client), + ]; + } + + /** + * Choose an HTTP client given a specific request. + * + * @return HttpClient|HttpAsyncClient + */ + private function chooseHttpClient(RequestInterface $request) + { + foreach ($this->clients as $client) { + if ($client['matcher']->matches($request)) { + return $client['client']; + } + } + + throw new RequestException('No client found for the specified request', $request); + } } diff --git a/src/HttpClientRouterImpl.php b/src/HttpClientRouterImpl.php deleted file mode 100644 index 9e11bbc..0000000 --- a/src/HttpClientRouterImpl.php +++ /dev/null @@ -1,68 +0,0 @@ - - */ -final class HttpClientRouterImpl implements HttpClientRouter -{ - /** - * @var array - */ - private $clients = []; - - /** - * {@inheritdoc} - */ - public function sendRequest(RequestInterface $request): ResponseInterface - { - return $this->chooseHttpClient($request)->sendRequest($request); - } - - /** - * {@inheritdoc} - */ - public function sendAsyncRequest(RequestInterface $request) - { - return $this->chooseHttpClient($request)->sendAsyncRequest($request); - } - - /** - * Add a client to the router. - * - * @param HttpClient|HttpAsyncClient $client - */ - public function addClient($client, RequestMatcher $requestMatcher) - { - $this->clients[] = [ - 'matcher' => $requestMatcher, - 'client' => new FlexibleHttpClient($client), - ]; - } - - /** - * Choose an HTTP client given a specific request. - * - * @return HttpClient|HttpAsyncClient - */ - private function chooseHttpClient(RequestInterface $request) - { - foreach ($this->clients as $client) { - if ($client['matcher']->matches($request)) { - return $client['client']; - } - } - - throw new RequestException('No client found for the specified request', $request); - } -} diff --git a/src/HttpClientRouterInterface.php b/src/HttpClientRouterInterface.php new file mode 100644 index 0000000..67fb822 --- /dev/null +++ b/src/HttpClientRouterInterface.php @@ -0,0 +1,24 @@ + + */ +interface HttpClientRouterInterface extends HttpClient, HttpAsyncClient +{ + /** + * Add a client to the router. + * + * @param HttpClient|HttpAsyncClient $client + */ + public function addClient($client, RequestMatcher $requestMatcher); +} diff --git a/src/HttpMethodsClient.php b/src/HttpMethodsClient.php index 7960d35..69e4df9 100644 --- a/src/HttpMethodsClient.php +++ b/src/HttpMethodsClient.php @@ -2,113 +2,85 @@ namespace Http\Client\Common; -use Http\Client\Exception; use Http\Client\HttpClient; +use Http\Message\RequestFactory; +use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; -use Psr\Http\Message\UriInterface; -/** - * Convenience HTTP client that integrates the MessageFactory in order to send - * requests in the following form:. - * - * $client - * ->get('/foo') - * ->post('/bar') - * ; - * - * The client also exposes the sendRequest methods of the wrapped HttpClient. - * - * @author Márk Sági-Kazár - * @author David Buchmann - */ -interface HttpMethodsClient extends HttpClient +final class HttpMethodsClient implements HttpMethodsClientInterface { /** - * Sends a GET request. - * - * @param string|UriInterface $uri - * - * @throws Exception + * @var HttpClient */ - public function get($uri, array $headers = []): ResponseInterface; + private $httpClient; /** - * Sends an HEAD request. - * - * @param string|UriInterface $uri - * - * @throws Exception + * @var RequestFactory */ - public function head($uri, array $headers = []): ResponseInterface; + private $requestFactory; /** - * Sends a TRACE request. - * - * @param string|UriInterface $uri - * - * @throws Exception + * @param HttpClient $httpClient The client to send requests with + * @param RequestFactory $requestFactory The message factory to create requests */ - public function trace($uri, array $headers = []): ResponseInterface; + public function __construct(HttpClient $httpClient, RequestFactory $requestFactory) + { + $this->httpClient = $httpClient; + $this->requestFactory = $requestFactory; + } - /** - * Sends a POST request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ - public function post($uri, array $headers = [], $body = null): ResponseInterface; + public function get($uri, array $headers = []): ResponseInterface + { + return $this->send('GET', $uri, $headers, null); + } - /** - * Sends a PUT request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ - public function put($uri, array $headers = [], $body = null): ResponseInterface; + public function head($uri, array $headers = []): ResponseInterface + { + return $this->send('HEAD', $uri, $headers, null); + } - /** - * Sends a PATCH request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ - public function patch($uri, array $headers = [], $body = null): ResponseInterface; + public function trace($uri, array $headers = []): ResponseInterface + { + return $this->send('TRACE', $uri, $headers, null); + } - /** - * Sends a DELETE request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ - public function delete($uri, array $headers = [], $body = null): ResponseInterface; + public function post($uri, array $headers = [], $body = null): ResponseInterface + { + return $this->send('POST', $uri, $headers, $body); + } - /** - * Sends an OPTIONS request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ - public function options($uri, array $headers = [], $body = null): ResponseInterface; + public function put($uri, array $headers = [], $body = null): ResponseInterface + { + return $this->send('PUT', $uri, $headers, $body); + } - /** - * Sends a request with any HTTP method. - * - * @param string $method HTTP method to use - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ - public function send($method, $uri, array $headers = [], $body = null): ResponseInterface; + public function patch($uri, array $headers = [], $body = null): ResponseInterface + { + return $this->send('PATCH', $uri, $headers, $body); + } + + public function delete($uri, array $headers = [], $body = null): ResponseInterface + { + return $this->send('DELETE', $uri, $headers, $body); + } + + public function options($uri, array $headers = [], $body = null): ResponseInterface + { + return $this->send('OPTIONS', $uri, $headers, $body); + } + + public function send($method, $uri, array $headers = [], $body = null): ResponseInterface + { + return $this->sendRequest($this->requestFactory->createRequest( + $method, + $uri, + $headers, + $body + )); + } + + public function sendRequest(RequestInterface $request): ResponseInterface + { + return $this->httpClient->sendRequest($request); + } } diff --git a/src/HttpMethodsClientImpl.php b/src/HttpMethodsClientImpl.php deleted file mode 100644 index 44c4cc5..0000000 --- a/src/HttpMethodsClientImpl.php +++ /dev/null @@ -1,86 +0,0 @@ -httpClient = $httpClient; - $this->requestFactory = $requestFactory; - } - - public function get($uri, array $headers = []): ResponseInterface - { - return $this->send('GET', $uri, $headers, null); - } - - public function head($uri, array $headers = []): ResponseInterface - { - return $this->send('HEAD', $uri, $headers, null); - } - - public function trace($uri, array $headers = []): ResponseInterface - { - return $this->send('TRACE', $uri, $headers, null); - } - - public function post($uri, array $headers = [], $body = null): ResponseInterface - { - return $this->send('POST', $uri, $headers, $body); - } - - public function put($uri, array $headers = [], $body = null): ResponseInterface - { - return $this->send('PUT', $uri, $headers, $body); - } - - public function patch($uri, array $headers = [], $body = null): ResponseInterface - { - return $this->send('PATCH', $uri, $headers, $body); - } - - public function delete($uri, array $headers = [], $body = null): ResponseInterface - { - return $this->send('DELETE', $uri, $headers, $body); - } - - public function options($uri, array $headers = [], $body = null): ResponseInterface - { - return $this->send('OPTIONS', $uri, $headers, $body); - } - - public function send($method, $uri, array $headers = [], $body = null): ResponseInterface - { - return $this->sendRequest($this->requestFactory->createRequest( - $method, - $uri, - $headers, - $body - )); - } - - public function sendRequest(RequestInterface $request): ResponseInterface - { - return $this->httpClient->sendRequest($request); - } -} diff --git a/src/HttpMethodsClientInterface.php b/src/HttpMethodsClientInterface.php new file mode 100644 index 0000000..6bc409f --- /dev/null +++ b/src/HttpMethodsClientInterface.php @@ -0,0 +1,114 @@ +get('/foo') + * ->post('/bar') + * ; + * + * The client also exposes the sendRequest methods of the wrapped HttpClient. + * + * @author Márk Sági-Kazár + * @author David Buchmann + */ +interface HttpMethodsClientInterface extends HttpClient +{ + /** + * Sends a GET request. + * + * @param string|UriInterface $uri + * + * @throws Exception + */ + public function get($uri, array $headers = []): ResponseInterface; + + /** + * Sends an HEAD request. + * + * @param string|UriInterface $uri + * + * @throws Exception + */ + public function head($uri, array $headers = []): ResponseInterface; + + /** + * Sends a TRACE request. + * + * @param string|UriInterface $uri + * + * @throws Exception + */ + public function trace($uri, array $headers = []): ResponseInterface; + + /** + * Sends a POST request. + * + * @param string|UriInterface $uri + * @param string|StreamInterface|null $body + * + * @throws Exception + */ + public function post($uri, array $headers = [], $body = null): ResponseInterface; + + /** + * Sends a PUT request. + * + * @param string|UriInterface $uri + * @param string|StreamInterface|null $body + * + * @throws Exception + */ + public function put($uri, array $headers = [], $body = null): ResponseInterface; + + /** + * Sends a PATCH request. + * + * @param string|UriInterface $uri + * @param string|StreamInterface|null $body + * + * @throws Exception + */ + public function patch($uri, array $headers = [], $body = null): ResponseInterface; + + /** + * Sends a DELETE request. + * + * @param string|UriInterface $uri + * @param string|StreamInterface|null $body + * + * @throws Exception + */ + public function delete($uri, array $headers = [], $body = null): ResponseInterface; + + /** + * Sends an OPTIONS request. + * + * @param string|UriInterface $uri + * @param string|StreamInterface|null $body + * + * @throws Exception + */ + public function options($uri, array $headers = [], $body = null): ResponseInterface; + + /** + * Sends a request with any HTTP method. + * + * @param string $method HTTP method to use + * @param string|UriInterface $uri + * @param string|StreamInterface|null $body + * + * @throws Exception + */ + public function send($method, $uri, array $headers = [], $body = null): ResponseInterface; +}