From 2cf3aff5c4be5f40864f55f826af02b092f301f2 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Sat, 26 Dec 2015 00:35:25 +0100 Subject: [PATCH 1/2] Prefere the sync call if possible, fix #14 --- composer.json | 5 +++++ spec/LoopPlugin.php | 14 ++++++++++++++ spec/PluginClientSpec.php | 28 ++++++++++++++++++---------- spec/StubClient.php | 18 ++++++++++++++++++ src/PluginClient.php | 37 ++++++++++++++++++++++++++----------- 5 files changed, 81 insertions(+), 21 deletions(-) create mode 100644 spec/LoopPlugin.php create mode 100644 spec/StubClient.php diff --git a/composer.json b/composer.json index 4ca4a24..2f152eb 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,11 @@ "Http\\Client\\Plugin\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "spec\\Http\\Client\\Plugin\\": "spec/" + } + }, "suggest": { "php-http/message": "Allow to use Authentication and Encoding plugins", "php-http/cookie": "Allow to use CookiePlugin", diff --git a/spec/LoopPlugin.php b/spec/LoopPlugin.php new file mode 100644 index 0000000..2905f73 --- /dev/null +++ b/spec/LoopPlugin.php @@ -0,0 +1,14 @@ +sendRequest($request)->willReturn($response); - $this->sendRequest($request)->shouldReturnAnInstanceOf('Psr\Http\Message\ResponseInterface'); + $this->sendRequest($request)->shouldReturn($response); } function it_sends_async_request_with_underlying_client(HttpAsyncClient $asyncClient, RequestInterface $request, Promise $promise) @@ -55,9 +47,25 @@ function it_sends_async_request_with_underlying_client(HttpAsyncClient $asyncCli $this->sendAsyncRequest($request)->shouldReturn($promise); } + function it_sends_async_request_if_no_send_request(HttpAsyncClient $asyncClient, RequestInterface $request, ResponseInterface $response, Promise $promise) + { + $this->beConstructedWith($asyncClient->getWrappedObject()); + $asyncClient->sendAsyncRequest($request)->willReturn($promise); + $promise->wait()->willReturn($response); + + $this->sendRequest($request)->shouldReturn($response); + } + + function it_prefers_send_request(StubClient $client, RequestInterface $request, ResponseInterface $response) + { + $client->sendRequest($request)->willReturn($response); + + $this->sendRequest($request)->shouldReturn($response); + } + function it_throws_loop_exception(HttpClient $client, RequestInterface $request) { - $this->beConstructedWith($client, [new DefectuousPlugin()]); + $this->beConstructedWith($client, [new LoopPlugin()]); $this->shouldThrow('Http\Client\Plugin\Exception\LoopException')->duringSendRequest($request); } diff --git a/spec/StubClient.php b/spec/StubClient.php new file mode 100644 index 0000000..aecea99 --- /dev/null +++ b/spec/StubClient.php @@ -0,0 +1,18 @@ +sendAsyncRequest($request); + if (!($this->client instanceof HttpClient)) { + return $this->sendAsyncRequest($request)->wait(); + } + + $client = $this->client; + $pluginChain = $this->createPluginChain($this->plugins, function (RequestInterface $request) use ($client) { + try { + return new FulfilledPromise($client->sendRequest($request)); + } catch (Exception $exception) { + return new RejectedPromise($exception); + } + }); - return $promise->wait(); + return $pluginChain($request)->wait(); } /** @@ -72,7 +86,10 @@ public function sendRequest(RequestInterface $request) */ public function sendAsyncRequest(RequestInterface $request) { - $pluginChain = $this->createPluginChain($this->plugins); + $client = $this->client; + $pluginChain = $this->createPluginChain($this->plugins, function (RequestInterface $request) use ($client) { + return $client->sendAsyncRequest($request); + }); return $pluginChain($request); } @@ -95,20 +112,18 @@ protected function configure(array $options = []) } /** - * @param Plugin[] $pluginList + * Create the plugin chain. + * + * @param Plugin[] $pluginList A list of plugins + * @param callable $clientCallable Callable making the HTTP call * * @return callable */ - private function createPluginChain($pluginList) + private function createPluginChain($pluginList, callable $clientCallable) { - $client = $this->client; $options = $this->options; + $firstCallable = $lastCallable = $clientCallable; - $lastCallable = function (RequestInterface $request) use ($client) { - return $client->sendAsyncRequest($request); - }; - - $firstCallable = $lastCallable; while ($plugin = array_pop($pluginList)) { $lastCallable = function (RequestInterface $request) use ($plugin, $lastCallable, &$firstCallable) { return $plugin->handleRequest($request, $lastCallable, $firstCallable); From 8646f92606b96eda5b030620ec19fcbd76a4441c Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Sat, 26 Dec 2015 12:28:24 +0100 Subject: [PATCH 2/2] Use emulated client from client common --- composer.json | 2 +- src/EmulateAsyncClient.php | 24 ------------------------ src/PluginClient.php | 6 +++++- 3 files changed, 6 insertions(+), 26 deletions(-) delete mode 100644 src/EmulateAsyncClient.php diff --git a/composer.json b/composer.json index 2f152eb..920903c 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "php-http/httplug": "1.0.0-beta", "php-http/message-factory": "^1.0", "php-http/promise": "^0.1.1", - "php-http/client-common": "^0.1", + "php-http/client-common": "^0.2@dev", "symfony/options-resolver": "^2.6|^3.0" }, "require-dev": { diff --git a/src/EmulateAsyncClient.php b/src/EmulateAsyncClient.php deleted file mode 100644 index 2dc4c85..0000000 --- a/src/EmulateAsyncClient.php +++ /dev/null @@ -1,24 +0,0 @@ -httpClient = $httpClient; - } -} diff --git a/src/PluginClient.php b/src/PluginClient.php index 241008b..ba9242e 100644 --- a/src/PluginClient.php +++ b/src/PluginClient.php @@ -2,6 +2,7 @@ namespace Http\Client\Plugin; +use Http\Client\Common\EmulatedHttpAsyncClient; use Http\Client\Exception; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; @@ -51,7 +52,7 @@ public function __construct($client, array $plugins = [], array $options = []) if ($client instanceof HttpAsyncClient) { $this->client = $client; } elseif ($client instanceof HttpClient) { - $this->client = new EmulateAsyncClient($client); + $this->client = new EmulatedHttpAsyncClient($client); } else { throw new \RuntimeException('Client must be an instance of Http\\Client\\HttpClient or Http\\Client\\HttpAsyncClient'); } @@ -65,10 +66,13 @@ public function __construct($client, array $plugins = [], array $options = []) */ public function sendRequest(RequestInterface $request) { + // If we don't have an http client, use the async call if (!($this->client instanceof HttpClient)) { return $this->sendAsyncRequest($request)->wait(); } + // Else we want to use the synchronous call of the underlying client, and not the async one in the case + // we have both an async and sync call $client = $this->client; $pluginChain = $this->createPluginChain($this->plugins, function (RequestInterface $request) use ($client) { try {