From fadb51abcecdcb0d24ffc2b539f31f030dae1d20 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sun, 2 Dec 2018 09:11:06 +0100 Subject: [PATCH] mark classes as final and methods and properties as private We add interfaces for final classes so that they can be mocked in testing. We chose to use the Interface suffix here to avoid name clashes, rather than renaming the existing PHP classes. The interfaces are only relevant for unit testing, we do not expect people to provide their own implementations. HttpClientPoolItem is purely internal and we therefore don't want an interface for it. It is marked with @final and explained to not be meant to extend. --- CHANGELOG.md | 4 + .../HttpClientPoolItemSpec.php | 2 +- .../LeastUsedClientPoolSpec.php | 2 +- spec/HttpClientPool/RandomClientPoolSpec.php | 2 +- .../RoundRobinClientPoolSpec.php | 2 +- spec/HttpClientRouterSpec.php | 8 +- spec/HttpMethodsClientSpec.php | 123 ++++++------------ spec/Plugin/AddPathPluginSpec.php | 2 +- src/BatchClient.php | 26 +--- src/BatchClientInterface.php | 34 +++++ src/Deferred.php | 2 +- src/EmulatedHttpAsyncClient.php | 6 +- src/EmulatedHttpClient.php | 6 +- src/HttpClientPool.php | 45 +------ src/HttpClientPool/HttpClientPool.php | 61 +++++++++ .../HttpClientPoolItem.php | 57 ++++---- src/HttpClientPool/LeastUsedClientPool.php | 2 - src/HttpClientPool/RandomClientPool.php | 2 - src/HttpClientPool/RoundRobinClientPool.php | 2 - src/HttpClientRouter.php | 12 +- src/HttpClientRouterInterface.php | 24 ++++ src/HttpMethodsClient.php | 94 +------------ src/HttpMethodsClientInterface.php | 114 ++++++++++++++++ 23 files changed, 326 insertions(+), 306 deletions(-) rename spec/{ => HttpClientPool}/HttpClientPoolItemSpec.php (99%) create mode 100644 src/BatchClientInterface.php create mode 100644 src/HttpClientPool/HttpClientPool.php rename src/{ => HttpClientPool}/HttpClientPoolItem.php (73%) create mode 100644 src/HttpClientRouterInterface.php create mode 100644 src/HttpMethodsClientInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cbc9e0..f115d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - RetryPlugin will no longer retry requests when the response failed with a HTTP code < 500. - Abstract method `HttpClientPool::chooseHttpClient()` has now an explicit return type (`Http\Client\Common\HttpClientPoolItem`) - 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. + (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 - Deprecated option `debug_plugins` has been removed from `PluginClient` diff --git a/spec/HttpClientPoolItemSpec.php b/spec/HttpClientPool/HttpClientPoolItemSpec.php similarity index 99% rename from spec/HttpClientPoolItemSpec.php rename to spec/HttpClientPool/HttpClientPoolItemSpec.php index f44351b..22c0b7d 100644 --- a/spec/HttpClientPoolItemSpec.php +++ b/spec/HttpClientPool/HttpClientPoolItemSpec.php @@ -1,6 +1,6 @@ shouldHaveType(HttpClientRouter::class); } + public function it_is_an_http_client_router() + { + $this->shouldImplement(HttpClientRouterInterface::class); + } + public function it_is_an_http_client() { $this->shouldImplement(HttpClient::class); diff --git a/spec/HttpMethodsClientSpec.php b/spec/HttpMethodsClientSpec.php index 74e0810..68e124d 100644 --- a/spec/HttpMethodsClientSpec.php +++ b/spec/HttpMethodsClientSpec.php @@ -2,135 +2,88 @@ namespace spec\Http\Client\Common; -use GuzzleHttp\Psr7\Response; use Http\Client\Common\HttpMethodsClient; use Http\Client\HttpClient; -use Http\Message\MessageFactory; +use Http\Message\RequestFactory; use PhpSpec\ObjectBehavior; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; class HttpMethodsClientSpec extends ObjectBehavior { - public function let(HttpClient $client, MessageFactory $messageFactory) + private static $requestData = [ + 'uri' => '/uri', + 'headers' => [ + 'Content-Type' => 'text/plain', + ], + 'body' => 'body', + ]; + + public function let(HttpClient $client, RequestFactory $requestFactory) { $this->beAnInstanceOf( - HttpMethodsClientStub::class, [ + HttpMethodsClient::class, [ $client, - $messageFactory, + $requestFactory, ] ); } - public function it_sends_a_get_request() + public function it_sends_a_get_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->get($data['uri'], $data['headers'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'get'); } - public function it_sends_a_head_request() + public function it_sends_a_head_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->head($data['uri'], $data['headers'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'head'); } - public function it_sends_a_trace_request() + public function it_sends_a_trace_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->trace($data['uri'], $data['headers'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'trace'); } - public function it_sends_a_post_request() + public function it_sends_a_post_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->post($data['uri'], $data['headers'], $data['body'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'post', self::$requestData['body']); } - public function it_sends_a_put_request() + public function it_sends_a_put_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->put($data['uri'], $data['headers'], $data['body'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'put', self::$requestData['body']); } - public function it_sends_a_patch_request() + public function it_sends_a_patch_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->patch($data['uri'], $data['headers'], $data['body'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'patch', self::$requestData['body']); } - public function it_sends_a_delete_request() + public function it_sends_a_delete_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->delete($data['uri'], $data['headers'], $data['body'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'delete', self::$requestData['body']); } - public function it_sends_a_options_request() + public function it_sends_an_options_request(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response) { - $data = HttpMethodsClientStub::$requestData; - - $this->options($data['uri'], $data['headers'], $data['body'])->shouldReturnAnInstanceOf(ResponseInterface::class); + $this->assert($client, $requestFactory, $request, $response, 'options', self::$requestData['body']); } - public function it_sends_request_with_underlying_client(HttpClient $client, MessageFactory $messageFactory, RequestInterface $request, ResponseInterface $response) + /** + * Run the actual test. + * + * As there is no data provider in phpspec, we keep separate methods to get new mocks for each test. + */ + private function assert(HttpClient $client, RequestFactory $requestFactory, RequestInterface $request, ResponseInterface $response, string $method, string $body = null) { $client->sendRequest($request)->shouldBeCalled()->willReturn($response); + $this->mockFactory($requestFactory, $request, strtoupper($method), $body); - $this->beConstructedWith($client, $messageFactory); - $this->sendRequest($request)->shouldReturn($response); + $this->$method(self::$requestData['uri'], self::$requestData['headers'], self::$requestData['body'])->shouldReturnAnInstanceOf(ResponseInterface::class); } -} - -class HttpMethodsClientStub extends HttpMethodsClient -{ - public static $requestData = [ - 'uri' => '/uri', - 'headers' => [ - 'Content-Type' => 'text/plain', - ], - 'body' => 'body', - ]; - /** - * {@inheritdoc} - */ - public function send($method, $uri, array $headers = [], $body = null): ResponseInterface + private function mockFactory(RequestFactory $requestFactory, RequestInterface $request, string $method, string $body = null) { - if ($uri !== self::$requestData['uri']) { - throw new \InvalidArgumentException('Invalid URI: '.$uri); - } - - if ($headers !== self::$requestData['headers']) { - throw new \InvalidArgumentException('Invalid headers: '.print_r($headers, true)); - } - - switch ($method) { - case 'GET': - case 'HEAD': - case 'TRACE': - if (null !== $body) { - throw new \InvalidArgumentException('Non-empty body'); - } - - return new Response(); - case 'POST': - case 'PUT': - case 'PATCH': - case 'DELETE': - case 'OPTIONS': - if ($body !== self::$requestData['body']) { - throw new \InvalidArgumentException('Invalid body: '.print_r($body, true)); - } - - return new Response(); - default: - throw new \InvalidArgumentException('Invalid method: '.$method); - } + $requestFactory->createRequest($method, self::$requestData['uri'], self::$requestData['headers'], $body)->willReturn($request); } } diff --git a/spec/Plugin/AddPathPluginSpec.php b/spec/Plugin/AddPathPluginSpec.php index 414fa04..6491069 100644 --- a/spec/Plugin/AddPathPluginSpec.php +++ b/spec/Plugin/AddPathPluginSpec.php @@ -46,7 +46,7 @@ public function it_adds_path( $this->handleRequest($request, PluginStub::next(), function () {}); } - function it_removes_ending_slashes( + public function it_removes_ending_slashes( RequestInterface $request, UriInterface $host, UriInterface $host2, diff --git a/src/BatchClient.php b/src/BatchClient.php index 8dfeb81..09a83ff 100644 --- a/src/BatchClient.php +++ b/src/BatchClient.php @@ -8,14 +8,7 @@ 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 - */ -class BatchClient implements HttpClient +final class BatchClient implements BatchClientInterface { /** * @var HttpClient @@ -27,28 +20,11 @@ public function __construct(HttpClient $client) $this->client = $client; } - /** - * {@inheritdoc} - */ public function sendRequest(RequestInterface $request): ResponseInterface { return $this->client->sendRequest($request); } - /** - * 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 { $batchResult = new 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/Deferred.php b/src/Deferred.php index 7413451..c294a8d 100644 --- a/src/Deferred.php +++ b/src/Deferred.php @@ -9,7 +9,7 @@ /** * A deferred allow to return a promise which has not been resolved yet. */ -class Deferred implements Promise +final class Deferred implements Promise { private $value; diff --git a/src/EmulatedHttpAsyncClient.php b/src/EmulatedHttpAsyncClient.php index 64acd59..9d6c557 100644 --- a/src/EmulatedHttpAsyncClient.php +++ b/src/EmulatedHttpAsyncClient.php @@ -6,13 +6,11 @@ use Http\Client\HttpClient; /** - * Emulates an async HTTP client. - * - * This should be replaced by an anonymous class in PHP 7. + * Emulates an async HTTP client with the help of a synchronous client. * * @author Márk Sági-Kazár */ -class EmulatedHttpAsyncClient implements HttpClient, HttpAsyncClient +final class EmulatedHttpAsyncClient implements HttpClient, HttpAsyncClient { use HttpAsyncClientEmulator; use HttpClientDecorator; diff --git a/src/EmulatedHttpClient.php b/src/EmulatedHttpClient.php index 3635e9f..d99b4e4 100644 --- a/src/EmulatedHttpClient.php +++ b/src/EmulatedHttpClient.php @@ -6,13 +6,11 @@ use Http\Client\HttpClient; /** - * Emulates an HTTP client. - * - * This should be replaced by an anonymous class in PHP 7. + * Emulates a synchronous HTTP client with the help of an asynchronous client. * * @author Márk Sági-Kazár */ -class EmulatedHttpClient implements HttpClient, HttpAsyncClient +final class EmulatedHttpClient implements HttpClient, HttpAsyncClient { use HttpAsyncClientDecorator; use HttpClientEmulator; diff --git a/src/HttpClientPool.php b/src/HttpClientPool.php index 90a8464..a730f50 100644 --- a/src/HttpClientPool.php +++ b/src/HttpClientPool.php @@ -2,59 +2,20 @@ namespace Http\Client\Common; -use Http\Client\Common\Exception\HttpClientNotFoundException; +use Http\Client\Common\HttpClientPool\HttpClientPoolItem; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; -use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\ResponseInterface; /** * A http client pool allows to send requests on a pool of different http client using a specific strategy (least used, * round robin, ...). */ -abstract class HttpClientPool implements HttpAsyncClient, HttpClient +interface HttpClientPool extends HttpAsyncClient, HttpClient { - /** - * @var HttpClientPoolItem[] - */ - protected $clientPool = []; - /** * Add a client to the pool. * * @param HttpClient|HttpAsyncClient|HttpClientPoolItem $client */ - public function addHttpClient($client) - { - if (!$client instanceof HttpClientPoolItem) { - $client = new HttpClientPoolItem($client); - } - - $this->clientPool[] = $client; - } - - /** - * Return an http client given a specific strategy. - * - * @throws HttpClientNotFoundException When no http client has been found into the pool - * - * @return HttpClientPoolItem Return a http client that can do both sync or async - */ - abstract protected function chooseHttpClient(): HttpClientPoolItem; - - /** - * {@inheritdoc} - */ - public function sendAsyncRequest(RequestInterface $request) - { - return $this->chooseHttpClient()->sendAsyncRequest($request); - } - - /** - * {@inheritdoc} - */ - public function sendRequest(RequestInterface $request): ResponseInterface - { - return $this->chooseHttpClient()->sendRequest($request); - } + public function addHttpClient($client); } diff --git a/src/HttpClientPool/HttpClientPool.php b/src/HttpClientPool/HttpClientPool.php new file mode 100644 index 0000000..cbac805 --- /dev/null +++ b/src/HttpClientPool/HttpClientPool.php @@ -0,0 +1,61 @@ +clientPool[] = $client; + } + + /** + * Return an http client given a specific strategy. + * + * @throws HttpClientNotFoundException When no http client has been found into the pool + * + * @return HttpClientPoolItem Return a http client that can do both sync or async + */ + abstract protected function chooseHttpClient(): HttpClientPoolItem; + + /** + * {@inheritdoc} + */ + public function sendAsyncRequest(RequestInterface $request) + { + return $this->chooseHttpClient()->sendAsyncRequest($request); + } + + /** + * {@inheritdoc} + */ + public function sendRequest(RequestInterface $request): ResponseInterface + { + return $this->chooseHttpClient()->sendRequest($request); + } +} diff --git a/src/HttpClientPoolItem.php b/src/HttpClientPool/HttpClientPoolItem.php similarity index 73% rename from src/HttpClientPoolItem.php rename to src/HttpClientPool/HttpClientPoolItem.php index a46ee2f..4094502 100644 --- a/src/HttpClientPoolItem.php +++ b/src/HttpClientPool/HttpClientPoolItem.php @@ -1,7 +1,8 @@ */ @@ -29,7 +37,11 @@ class HttpClientPoolItem implements HttpClient, HttpAsyncClient private $disabledAt; /** - * @var int|null Number of seconds after this client is reenable, by default null: never reenable this client + * Number of seconds until this client is enabled again after an error. + * + * null: never reenable this client. + * + * @var int|null */ private $reenableAfter; @@ -40,7 +52,7 @@ class HttpClientPoolItem implements HttpClient, HttpAsyncClient /** * @param HttpClient|HttpAsyncClient $client - * @param null|int $reenableAfter Number of seconds after this client is reenable + * @param null|int $reenableAfter Number of seconds until this client is enabled again after an error */ public function __construct($client, $reenableAfter = null) { @@ -97,21 +109,16 @@ public function sendAsyncRequest(RequestInterface $request) /** * Whether this client is disabled or not. * - * Will also reactivate this client if possible - * - * @internal - * - * @return bool + * If the client was disabled, calling this method checks if the client can + * be reenabled and if so enables it. */ - public function isDisabled() + public function isDisabled(): bool { - $disabledAt = $this->getDisabledAt(); - - if (null !== $this->reenableAfter && null !== $disabledAt) { + if (null !== $this->reenableAfter && null !== $this->disabledAt) { // Reenable after a certain time $now = new \DateTime(); - if (($now->getTimestamp() - $disabledAt->getTimestamp()) >= $this->reenableAfter) { + if (($now->getTimestamp() - $this->disabledAt->getTimestamp()) >= $this->reenableAfter) { $this->enable(); return false; @@ -120,31 +127,17 @@ public function isDisabled() return true; } - return null !== $disabledAt; + return null !== $this->disabledAt; } /** - * Get current number of request that is send by the underlying http client. - * - * @internal - * - * @return int + * Get current number of request that are currently being sent by the underlying HTTP client. */ - public function getSendingRequestCount() + public function getSendingRequestCount(): int { return $this->sendingRequestCount; } - /** - * Return when this client has been disabled or null if it's enabled. - * - * @return \DateTime|null - */ - private function getDisabledAt() - { - return $this->disabledAt; - } - /** * Increment the request count. */ diff --git a/src/HttpClientPool/LeastUsedClientPool.php b/src/HttpClientPool/LeastUsedClientPool.php index 61eb670..e3c29b7 100644 --- a/src/HttpClientPool/LeastUsedClientPool.php +++ b/src/HttpClientPool/LeastUsedClientPool.php @@ -3,8 +3,6 @@ namespace Http\Client\Common\HttpClientPool; use Http\Client\Common\Exception\HttpClientNotFoundException; -use Http\Client\Common\HttpClientPool; -use Http\Client\Common\HttpClientPoolItem; /** * LeastUsedClientPool will choose the client with the less current request in the pool. diff --git a/src/HttpClientPool/RandomClientPool.php b/src/HttpClientPool/RandomClientPool.php index 2889ed7..3adf5fd 100644 --- a/src/HttpClientPool/RandomClientPool.php +++ b/src/HttpClientPool/RandomClientPool.php @@ -3,8 +3,6 @@ namespace Http\Client\Common\HttpClientPool; use Http\Client\Common\Exception\HttpClientNotFoundException; -use Http\Client\Common\HttpClientPool; -use Http\Client\Common\HttpClientPoolItem; /** * RoundRobinClientPool will choose the next client in the pool. diff --git a/src/HttpClientPool/RoundRobinClientPool.php b/src/HttpClientPool/RoundRobinClientPool.php index 3315b51..13cdf13 100644 --- a/src/HttpClientPool/RoundRobinClientPool.php +++ b/src/HttpClientPool/RoundRobinClientPool.php @@ -3,8 +3,6 @@ namespace Http\Client\Common\HttpClientPool; use Http\Client\Common\Exception\HttpClientNotFoundException; -use Http\Client\Common\HttpClientPool; -use Http\Client\Common\HttpClientPoolItem; /** * RoundRobinClientPool will choose the next client in the pool. diff --git a/src/HttpClientRouter.php b/src/HttpClientRouter.php index 00ca15f..56be0bf 100644 --- a/src/HttpClientRouter.php +++ b/src/HttpClientRouter.php @@ -10,11 +10,11 @@ use Psr\Http\Message\ResponseInterface; /** - * Route a request to a specific client in the stack based using a RequestMatcher. + * {@inheritdoc} * * @author Joel Wurtz */ -final class HttpClientRouter implements HttpClient, HttpAsyncClient +final class HttpClientRouter implements HttpClientRouterInterface { /** * @var array @@ -26,9 +26,7 @@ final class HttpClientRouter implements HttpClient, HttpAsyncClient */ public function sendRequest(RequestInterface $request): ResponseInterface { - $client = $this->chooseHttpClient($request); - - return $client->sendRequest($request); + return $this->chooseHttpClient($request)->sendRequest($request); } /** @@ -36,9 +34,7 @@ public function sendRequest(RequestInterface $request): ResponseInterface */ public function sendAsyncRequest(RequestInterface $request) { - $client = $this->chooseHttpClient($request); - - return $client->sendAsyncRequest($request); + return $this->chooseHttpClient($request)->sendAsyncRequest($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 bc02ef8..69e4df9 100644 --- a/src/HttpMethodsClient.php +++ b/src/HttpMethodsClient.php @@ -2,29 +2,12 @@ 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 - */ -class HttpMethodsClient implements HttpClient +final class HttpMethodsClient implements HttpMethodsClientInterface { /** * @var HttpClient @@ -46,116 +29,46 @@ public function __construct(HttpClient $httpClient, RequestFactory $requestFacto $this->requestFactory = $requestFactory; } - /** - * Sends a GET request. - * - * @param string|UriInterface $uri - * - * @throws Exception - */ public function get($uri, array $headers = []): ResponseInterface { return $this->send('GET', $uri, $headers, null); } - /** - * Sends an HEAD request. - * - * @param string|UriInterface $uri - * - * @throws Exception - */ public function head($uri, array $headers = []): ResponseInterface { return $this->send('HEAD', $uri, $headers, null); } - /** - * Sends a TRACE request. - * - * @param string|UriInterface $uri - * - * @throws Exception - */ public function trace($uri, array $headers = []): ResponseInterface { return $this->send('TRACE', $uri, $headers, null); } - /** - * Sends a POST request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ public function post($uri, array $headers = [], $body = null): ResponseInterface { return $this->send('POST', $uri, $headers, $body); } - /** - * Sends a PUT request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ public function put($uri, array $headers = [], $body = null): ResponseInterface { return $this->send('PUT', $uri, $headers, $body); } - /** - * Sends a PATCH request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ public function patch($uri, array $headers = [], $body = null): ResponseInterface { return $this->send('PATCH', $uri, $headers, $body); } - /** - * Sends a DELETE request. - * - * @param string|UriInterface $uri - * @param string|StreamInterface|null $body - * - * @throws Exception - */ public function delete($uri, array $headers = [], $body = null): ResponseInterface { return $this->send('DELETE', $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 { return $this->send('OPTIONS', $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 { return $this->sendRequest($this->requestFactory->createRequest( @@ -166,11 +79,6 @@ public function send($method, $uri, array $headers = [], $body = null): Response )); } - /** - * Forward to the underlying HttpClient. - * - * {@inheritdoc} - */ 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; +}