diff --git a/CHANGELOG.md b/CHANGELOG.md index ed2eba3..6dadec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.1.0] - 2017-08-17 +### Added +- feature to subscribe to new event "expert_sender_api.request.exception_thrown" +### Changed +- changed empty text of error message to more informative + ## [1.0.0] - 2017-08-16 ### Added - phpstan lvl 7 checks diff --git a/src/Event/RequestExceptionThrown.php b/src/Event/RequestExceptionThrown.php new file mode 100644 index 0000000..6161bde --- /dev/null +++ b/src/Event/RequestExceptionThrown.php @@ -0,0 +1,58 @@ + + */ +class RequestExceptionThrown extends Event +{ + /** + * @var RequestInterface Request + */ + private $request; + + /** + * @var RequestException $exception + */ + private $exception; + + /** + * Constructor + * + * @param RequestInterface $apiRequest Api request + * @param RequestException $exception Thrown exception + */ + public function __construct(RequestInterface $apiRequest, RequestException $exception) + { + $this->request = $apiRequest; + $this->exception = $exception; + } + + /** + * Get api request + * + * @return RequestInterface Api request + */ + public function getRequest(): RequestInterface + { + return $this->request; + } + + /** + * Get thrown exception + * + * @return RequestException Thrown exception + */ + public function getException(): RequestException + { + return $this->exception; + } +} diff --git a/src/RequestSender.php b/src/RequestSender.php index f2a8940..d2a6051 100644 --- a/src/RequestSender.php +++ b/src/RequestSender.php @@ -4,6 +4,7 @@ namespace Citilink\ExpertSenderApi; use Citilink\ExpertSenderApi\Enum\HttpMethod; +use Citilink\ExpertSenderApi\Event\RequestExceptionThrown; use Citilink\ExpertSenderApi\Event\ResponseReceivedEvent; use GuzzleHttp\ClientInterface; use GuzzleHttp\Exception\RequestException; @@ -72,7 +73,36 @@ public function send(RequestInterface $request): ResponseInterface try { $httpResponse = $this->httpClient->request($request->getMethod()->getValue(), $request->getUri(), $options); } catch (RequestException $e) { - $httpResponse = $e->getResponse() !== null ? $e->getResponse() : new \GuzzleHttp\Psr7\Response(400); + $this->eventDispatcher->dispatch( + 'expert_sender_api.request.exception_thrown', + new RequestExceptionThrown($request, $e) + ); + + if ($e->getResponse() !== null) { + $httpResponse = $e->getResponse(); + } else { + $errorMessage = sprintf( + 'ES API ARTIFICIAL ERROR: "%s":"%s". Please note, that this error ' + . 'indicates about exception without response. You can subscribe for ' + . '"expert_sender_api.request.exception_thrown" event and get more information about exception', + get_class($e), + $e->getMessage() + ); + + $xml = ' + + 400 + ' . $errorMessage . ' + + '; + + $httpResponse = new \GuzzleHttp\Psr7\Response( + 400, + ['Content-Type' => 'text/xml', 'Content-Length' => strlen($xml)], + $xml + ); + } } $apiResponse = new Response($httpResponse); diff --git a/tests/RequestSenderTest.php b/tests/RequestSenderTest.php index 2230c4a..2f2a358 100644 --- a/tests/RequestSenderTest.php +++ b/tests/RequestSenderTest.php @@ -4,13 +4,16 @@ namespace Citilink\ExpertSenderApi\Tests; use Citilink\ExpertSenderApi\Enum\SubscribersGetRequest\DataOption; +use Citilink\ExpertSenderApi\Event\RequestExceptionThrown; use Citilink\ExpertSenderApi\Event\ResponseReceivedEvent; +use Citilink\ExpertSenderApi\Model\ErrorMessage; use Citilink\ExpertSenderApi\Model\SubscribersPostRequest\Identifier; use Citilink\ExpertSenderApi\Model\SubscribersPostRequest\SubscriberInfo; use Citilink\ExpertSenderApi\Request\SubscribersGetRequest; use Citilink\ExpertSenderApi\Request\SubscribersPostRequest; use Citilink\ExpertSenderApi\RequestSender; use GuzzleHttp\Client; +use GuzzleHttp\Exception\ConnectException; use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\HandlerStack; @@ -116,4 +119,59 @@ function (ResponseReceivedEvent $event) use (&$receivedEventHasBeenSent) { Assert::assertEquals(null, $apiResponse->getErrorCode()); Assert::assertCount(0, $apiResponse->getErrorMessages()); } + + public function testThrowExceptionWithoutResponse() + { + $mockHandler = new MockHandler( + [ + new ConnectException( + 'cURL error 28: SSL connection timeout (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)', + new Request('GET', '/Api/Subscribers') + ), + ] + ); + + $handler = HandlerStack::create($mockHandler); + $client = new Client(['handler' => $handler]); + $eventDispatcher = new EventDispatcher(); + $receivedEventHasBeenSent = false; + $thrownExceptionEventHasBeenSent = false; + $eventDispatcher->addListener( + 'expert_sender_api.response.received', + function (ResponseReceivedEvent $event) use (&$receivedEventHasBeenSent) { + $receivedEventHasBeenSent = true; + Assert::assertInstanceOf(ResponseReceivedEvent::class, $event); + } + ); + + $eventDispatcher->addListener( + 'expert_sender_api.request.exception_thrown', + function (RequestExceptionThrown $event) use (&$thrownExceptionEventHasBeenSent) { + $thrownExceptionEventHasBeenSent = true; + Assert::assertInstanceOf(RequestExceptionThrown::class, $event); + Assert::assertNotNull($event->getRequest()); + Assert::assertNotNull($event->getException()); + } + ); + + $requestSender = new RequestSender($client, 'api-key', $eventDispatcher); + $response = $requestSender->send(new SubscribersGetRequest('mail@mail.com', DataOption::SHORT())); + + Assert::assertTrue($thrownExceptionEventHasBeenSent); + Assert::assertTrue($receivedEventHasBeenSent); + Assert::assertFalse($response->isOk()); + Assert::assertEquals(400, $response->getErrorCode()); + $errorMessages = $response->getErrorMessages(); + Assert::assertCount(1, $errorMessages); + /** @var ErrorMessage $firstErrorMessage */ + $firstErrorMessage = reset($errorMessages); + Assert::assertEquals( + 'ES API ARTIFICIAL ERROR: "GuzzleHttp\Exception\ConnectException":"cURL error 28: SSL connection ' + . 'timeout (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)". Please note, that this error ' + . 'indicates about exception without response. You can subscribe for ' + . '"expert_sender_api.request.exception_thrown" event and get more information about exception', + $firstErrorMessage->getMessage() + ); + Assert::assertEquals([], $firstErrorMessage->getOptions()); + } }