diff --git a/src/Client/Exception/ClientException.php b/src/Client/Exception/ClientException.php new file mode 100644 index 0000000..5c8fdcd --- /dev/null +++ b/src/Client/Exception/ClientException.php @@ -0,0 +1,12 @@ +getCode()) { + case 400: + self::handleClient400Exception($exception); + } + + throw new IzettleClientException($exception->getMessage()); + } + + public static function handleRequestException(RequestException $exception): void + { + $responseData = json_decode($exception->getResponse()->getBody()->getContents(), true); + switch ($exception->getCode()) { + case 404: + throw new NotFoundException($responseData['developerMessage']); + } + + throw new IzettleClientException($exception->getMessage()); + } + + private static function handleClient400Exception(ClientException $exception): void + { + $responseData = json_decode($exception->getResponse()->getBody()->getContents(), true); + switch ($responseData['error']) { + case 'invalid_grant': + self::handleInvalidGrantException($responseData); + case 'invalid_client': + self::handleInvalidClientException($responseData); + case 'unauthorized_client': + throw new InvalidClientException($responseData['error_description']); + default: + throw new InvalidClientException($responseData['error_description']); + } + } + + private static function handleInvalidGrantException(array $responseData): void + { + switch ($responseData['error_description']) { + case 'INCORRECT_PASSWORD_OR_USERNAME': + throw new InvalidUsernameOrPasswordException(); + case 'TOO_MANY_FAILED_ATTEMPTS': + throw new TooManyFailedAttemptsException(); + default: + throw new InvalidGrantException($responseData['error_description']); + } + } + + private static function handleInvalidClientException(array $responseData): void + { + switch ($responseData['error_description']) { + case 'Invalid client_id': + throw new InvalidClientIdException(); + default: + throw new InvalidClientException($responseData['error_description']); + } + } +} diff --git a/src/Client/Exception/InvalidClient/InvalidClientIdException.php b/src/Client/Exception/InvalidClient/InvalidClientIdException.php new file mode 100644 index 0000000..d1a5a1c --- /dev/null +++ b/src/Client/Exception/InvalidClient/InvalidClientIdException.php @@ -0,0 +1,11 @@ +setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REQUEST_URL, $options)); + try { + $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REQUEST_URL, $options)); + } catch (ClientException $exception){ + GuzzleClientExceptionHandler::handleClientException($exception); + } return $this->accessToken; } @@ -102,8 +108,8 @@ public function get(string $url, ?array $queryParameters = null): ResponseInterf try { $response = $this->guzzleClient->get($url, $options); - } catch (RequestException $e) { - throw new NotFoundException($e->getMessage()); + } catch (RequestException $exception) { + GuzzleClientExceptionHandler::handleRequestException($exception); } return $response; diff --git a/tests/Integration/Client/PurchaseClientTest.php b/tests/Integration/Client/PurchaseClientTest.php index ba70889..180249b 100644 --- a/tests/Integration/Client/PurchaseClientTest.php +++ b/tests/Integration/Client/PurchaseClientTest.php @@ -57,21 +57,18 @@ public function getPurchase(): void /** * @test - * @expectedException \LauLamanApps\IzettleApi\Client\Exception\PurchaseNotFoundException + * @expectedException \LauLamanApps\IzettleApi\Client\Purchase\Exception\PurchaseNotFoundException */ public function getPurchase_404ShouldThrowException(): void { - $iZettleClient = $this->getGuzzleIzettleClient(404, ''); + $iZettleClient = $this->getGuzzleIzettleClient(404, '{"developerMessage":"XXX not found","errorType":null,"violations":[]}'); $purchaseClient = IzettleClientFactory::getPurchaseClient($iZettleClient); - $purchaseHistory = $purchaseClient->getPurchase(Uuid::uuid1()); - - self::assertInstanceOf(Purchase::class, $purchaseHistory); + $purchaseClient->getPurchase(Uuid::uuid1()); } - private function assertPurchase($purchase, $data): void + private function assertPurchase(Purchase $purchase, $data): void { - self::assertInstanceOf(Purchase::class, $purchase); self::assertSame($data['purchaseUUID'], $purchase->getUuid()); self::assertSame($data['purchaseUUID1'], (string) $purchase->getUuid1()); self::assertSame($data["amount"], (int) $purchase->getAmount()->getAmount()); diff --git a/tests/Unit/Client/Exception/GuzzleClientExceptionHandlerTest.php b/tests/Unit/Client/Exception/GuzzleClientExceptionHandlerTest.php new file mode 100644 index 0000000..90ced71 --- /dev/null +++ b/tests/Unit/Client/Exception/GuzzleClientExceptionHandlerTest.php @@ -0,0 +1,110 @@ + [new GuzzleClientException(0, Mockery::mock(RequestInterface::class)), ClientException::class], + 'INCORRECT_PASSWORD_OR_USERNAME' => [$this->getClientException(400, 'invalid_grant', 'INCORRECT_PASSWORD_OR_USERNAME'), InvalidUsernameOrPasswordException::class], + 'TOO_MANY_FAILED_ATTEMPTS' => [$this->getClientException(400, 'invalid_grant', 'TOO_MANY_FAILED_ATTEMPTS'), TooManyFailedAttemptsException::class], + 'InvalidGrantException' => [$this->getClientException(400, 'invalid_grant', '[fallback]'), InvalidGrantException::class], + 'Invalid client_id' => [$this->getClientException(400, 'invalid_client', 'Invalid client_id'), InvalidClientIdException::class], + 'Invalid client' => [$this->getClientException(400, 'invalid_client', '[fallback]'), InvalidClientException::class], + 'unauthorized_client' => [$this->getClientException(400, 'unauthorized_client', '[does not mather]'), InvalidClientException::class], + 'InvalidClientException' => [$this->getClientException(400, 'fallback', '[does not mather]'), InvalidClientException::class], + + ]; + } + + /** + * @test + * @dataProvider getRequestExceptions + */ + public function handleRequestException(GuzzleRequestException $exception, string $expectedException): void + { + self::expectException($expectedException); + GuzzleClientExceptionHandler::handleRequestException($exception); + } + + /** + * @return GuzzleRequestException[] + */ + public function getRequestExceptions(): array + { + return [ + 'undefined' => [$this->getRequestException(0, '[fallback]'), ClientException::class], + 'not found' => [$this->getRequestException(404, 'not found'), NotFoundException::class], + ]; + } + + private function getClientException(int $code ,string $error, string $errorDescription): GuzzleClientException + { + /** @var RequestInterface|MockInterface $request */ + $request = Mockery::mock(RequestInterface::class); + $response = $this->getResponse($code, ['error'=> $error, 'error_description' => $errorDescription]); + + return new GuzzleClientException('', $request, $response); + } + + private function getRequestException(int $code, string $developerMessage): GuzzleRequestException + { + /** @var RequestInterface|MockInterface $request */ + $request = Mockery::mock(RequestInterface::class); + $response = $this->getResponse($code, ['developerMessage' => $developerMessage]); + + return new GuzzleRequestException('', $request, $response); + } + + private function getResponse(int $code, array $returnData): ResponseInterface + { + /** @var ResponseInterface|MockInterface $response */ + $response = Mockery::mock(ResponseInterface::class); + $response->shouldReceive('getStatusCode')->once()->andReturn($code); + $response->shouldReceive('getBody')->once()->andReturnSelf(); + $response->shouldReceive('getContents')->once()->andReturn(json_encode($returnData)); + + return $response; + } + +} diff --git a/tests/Unit/Client/Purchase/PaymentBuilderTest.php b/tests/Unit/Client/Purchase/PaymentBuilderTest.php index bcbf060..c49b898 100644 --- a/tests/Unit/Client/Purchase/PaymentBuilderTest.php +++ b/tests/Unit/Client/Purchase/PaymentBuilderTest.php @@ -196,7 +196,7 @@ public function getPaymentData(): array /** * @test - * @expectedException \LauLamanApps\IzettleApi\Client\Exception\PaymentTypeNotConfiguredException + * @expectedException \LauLamanApps\IzettleApi\Client\Purchase\Exception\PaymentTypeNotConfiguredException */ public function parseNonConfiguredPaymentType(): void {