diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index c575252..2b8d36c 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -2,9 +2,7 @@ name: PHP Test on: push: - branches: [ "master" ] pull_request: - branches: [ "master" ] permissions: contents: read @@ -21,7 +19,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: 8.2 - + - name: Validate composer.json and composer.lock run: composer validate --strict diff --git a/README.md b/README.md index f55b55e..0665808 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# tempnumber-api-client +# TempNumber Api Client An API client for Temp-Number service ( https://temp-number.org/ ) written in PHP. @@ -7,7 +7,7 @@ If you encounter a bug or have an idea to improve the code, feel free to open an ## Installation ```` -$ Composer require ahmedghanem00/tempnumber-api-client +$ composer require ahmedghanem00/tempnumber-api-client ```` ## Usage @@ -64,7 +64,7 @@ In case you have specific activation that needs to be retried ````php try { - $client->retryActivation($newActivation->getId()); + $client->retryActivation(181822); } catch (Exception $e) { echo $e->getMessage(); } @@ -139,5 +139,6 @@ foreach ($result->activations() as $activation) { } ```` +## LICENSE -## +Package is licensed under the [MIT License](http://opensource.org/licenses/MIT). diff --git a/composer.json b/composer.json index a0dcc99..4b8fe13 100644 --- a/composer.json +++ b/composer.json @@ -45,5 +45,5 @@ "phpstan": "@php vendor/bin/phpstan analyse src tests" }, - "minimum-stability": "dev" + "minimum-stability": "stable" } diff --git a/src/Client.php b/src/Client.php index a223be1..7e045c3 100644 --- a/src/Client.php +++ b/src/Client.php @@ -14,19 +14,7 @@ use ahmedghanem00\TempNumberClient\Enum\Country; use ahmedghanem00\TempNumberClient\Enum\Service; use ahmedghanem00\TempNumberClient\Enum\TempNumberServer; -use ahmedghanem00\TempNumberClient\Exception\Api\AccountOnHoldException; -use ahmedghanem00\TempNumberClient\Exception\Api\ApiException; -use ahmedghanem00\TempNumberClient\Exception\Api\ExpectedPriceException; -use ahmedghanem00\TempNumberClient\Exception\Api\GoneException; -use ahmedghanem00\TempNumberClient\Exception\Api\InvalidRequestParamsException; -use ahmedghanem00\TempNumberClient\Exception\Api\LowSuccessRateException; -use ahmedghanem00\TempNumberClient\Exception\Api\PaymentRequiredException; -use ahmedghanem00\TempNumberClient\Exception\Api\ResourceBadStateException; -use ahmedghanem00\TempNumberClient\Exception\Api\ResourceNotFoundException; -use ahmedghanem00\TempNumberClient\Exception\Api\ServiceUnavailableException; -use ahmedghanem00\TempNumberClient\Exception\Api\TooManyActivationsPendingException; -use ahmedghanem00\TempNumberClient\Exception\Api\TooManyRequestsException; -use ahmedghanem00\TempNumberClient\Exception\Api\UnauthorizedServiceException; +use ahmedghanem00\TempNumberClient\Exception\API\APIException; use ahmedghanem00\TempNumberClient\Exception\ClientException; use ahmedghanem00\TempNumberClient\Result\ActivationHistoryResult; use ahmedghanem00\TempNumberClient\Result\ActivationResult; @@ -162,41 +150,12 @@ private function checkAndGetResultDataFromResponse(ResponseInterface $response): $resultData = $response->toArray(false); if (@$errorName = $resultData['errorName']) { - $this->handleApiError($errorName, $resultData, $response); + throw APIException::newFromErrorName($errorName, $response); } return $resultData; } - /** - * @param string $errorName - * @param array $resultData - * @param ResponseInterface $response - * @return void - */ - private function handleApiError(string $errorName, array $resultData, ResponseInterface $response): void - { - $exception = match ($errorName) { - 'UnauthorizedException' => new UnauthorizedServiceException(), - 'InvalidRequestParamsException' => new InvalidRequestParamsException(), - 'paymentRequired' => new PaymentRequiredException(), - 'AccountOnHoldException' => new AccountOnHoldException(), - 'ResourceNotFoundException' => new ResourceNotFoundException(), - 'ResourceBadStateException' => new ResourceBadStateException(), - 'TooManyActivationsPendingException' => new TooManyActivationsPendingException(), - 'TooManyRequestsException' => new TooManyRequestsException(), - 'expectedPriceErrorException' => new ExpectedPriceException($resultData['newPrice']), - 'GoneException' => new GoneException(), - 'lowSuccessRateException' => new LowSuccessRateException(), - 'ServiceUnavailableException' => new ServiceUnavailableException(), - default => new ApiException() - }; - - $exception->setResponse($response); - - throw $exception; - } - /** * @throws TransportExceptionInterface * @throws ServerExceptionInterface diff --git a/src/Exception/API/APIException.php b/src/Exception/API/APIException.php new file mode 100644 index 0000000..257f7fe --- /dev/null +++ b/src/Exception/API/APIException.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +use ahmedghanem00\TempNumberClient\Exception\ClientException; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * + */ +class APIException extends ClientException +{ + public const Description = "API Failed Action"; + + /** + * @param ResponseInterface $response + */ + public function __construct( + private ResponseInterface $response + ) + { + parent::__construct(static::Description); + } + + /** + * @param string $errorName + * @param ResponseInterface $response + * @return static + */ + public static function newFromErrorName(string $errorName, ResponseInterface $response): self + { + $exceptionClass = match (strtolower($errorName)) { + 'unauthorizedexception' => UnauthorizedServiceException::class, + 'invalidrequestparamsexception' => InvalidRequestParamsException::class, + 'paymentrequired' => PaymentRequiredException::class, + 'accountonholdexception' => AccountOnHoldException::class, + 'resourcenotfoundexception' => ResourceNotFoundException::class, + 'resourcebadstateexception' => ResourceBadStateException::class, + 'toomanyactivationspendingexception' => TooManyActivationsPendingException::class, + 'toomanyrequestsexception' => TooManyRequestsException::class, + 'expectedpriceerrorexception' => ExpectedPriceException::class, + 'goneexception' => GoneException::class, + 'lowsuccessrateexception' => LowSuccessRateException::class, + 'serviceunavailableexception' => ServiceUnavailableException::class, + + default => self::class + }; + + return new $exceptionClass($response); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function getResultData(): array + { + return $this->getResponse()->toArray(false); + } + + /** + * @return ResponseInterface + */ + public function getResponse(): ResponseInterface + { + return $this->response; + } +} diff --git a/src/Exception/API/AccountOnHoldException.php b/src/Exception/API/AccountOnHoldException.php new file mode 100644 index 0000000..b4da218 --- /dev/null +++ b/src/Exception/API/AccountOnHoldException.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +class AccountOnHoldException extends APIException +{ +} diff --git a/src/Exception/API/ExpectedPriceException.php b/src/Exception/API/ExpectedPriceException.php new file mode 100644 index 0000000..9a691de --- /dev/null +++ b/src/Exception/API/ExpectedPriceException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +class ExpectedPriceException extends APIException +{ + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function getNewPrice(): float + { + return (float)$this->getResultData()['newPrice']; + } +} diff --git a/src/Exception/API/GoneException.php b/src/Exception/API/GoneException.php new file mode 100644 index 0000000..005de7e --- /dev/null +++ b/src/Exception/API/GoneException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +class GoneException extends APIException +{ + public const Description = "The target resource is no longer available"; +} diff --git a/src/Exception/API/InvalidRequestParamsException.php b/src/Exception/API/InvalidRequestParamsException.php new file mode 100644 index 0000000..5a90cf4 --- /dev/null +++ b/src/Exception/API/InvalidRequestParamsException.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +class InvalidRequestParamsException extends APIException +{ +} diff --git a/src/Exception/Api/LowSuccessRateException.php b/src/Exception/API/LowSuccessRateException.php similarity index 58% rename from src/Exception/Api/LowSuccessRateException.php rename to src/Exception/API/LowSuccessRateException.php index 90c64f1..c69d872 100644 --- a/src/Exception/Api/LowSuccessRateException.php +++ b/src/Exception/API/LowSuccessRateException.php @@ -8,26 +8,16 @@ * file that was distributed with this source code. */ -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; +namespace ahmedghanem00\TempNumberClient\Exception\API; /** * * Example: 100 activations requested for Whatsapp in Germany but only 1 activation got sms. - * This is 1% delivery success rate. No more activations allowed in 24 hours to Whatsapp in the Netherlands. + * This is 1% delivery success rate. No more activations allowed in 24 hours to Whatsapp in the Germany. * */ -class LowSuccessRateException extends ApiException implements TemporaryExceptionInterface +class LowSuccessRateException extends APIException implements TemporaryErrorInterface { - /** - * - */ - public function __construct() - { - ClientException::__construct("Activations low success rate"); - } - /** * @return int */ diff --git a/src/Exception/API/PaymentRequiredException.php b/src/Exception/API/PaymentRequiredException.php new file mode 100644 index 0000000..74087b5 --- /dev/null +++ b/src/Exception/API/PaymentRequiredException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +/** + * + */ +class PaymentRequiredException extends APIException +{ +} diff --git a/src/Exception/Api/ResourceNotFoundException.php b/src/Exception/API/ResourceBadStateException.php similarity index 53% rename from src/Exception/Api/ResourceNotFoundException.php rename to src/Exception/API/ResourceBadStateException.php index 6587eab..5bfc955 100644 --- a/src/Exception/Api/ResourceNotFoundException.php +++ b/src/Exception/API/ResourceBadStateException.php @@ -8,20 +8,18 @@ * file that was distributed with this source code. */ -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; +namespace ahmedghanem00\TempNumberClient\Exception\API; /** * */ -class ResourceNotFoundException extends ApiException +class ResourceBadStateException extends APIException implements TemporaryErrorInterface { /** - * + * @return int */ - public function __construct() + public function retryAfter(): int { - ClientException::__construct("Resource not found"); + return 10 * 60; } } diff --git a/src/Exception/API/ResourceNotFoundException.php b/src/Exception/API/ResourceNotFoundException.php new file mode 100644 index 0000000..8dbb9b5 --- /dev/null +++ b/src/Exception/API/ResourceNotFoundException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +/** + * + */ +class ResourceNotFoundException extends APIException +{ +} diff --git a/src/Exception/Api/ServiceUnavailableException.php b/src/Exception/API/ServiceUnavailableException.php similarity index 53% rename from src/Exception/Api/ServiceUnavailableException.php rename to src/Exception/API/ServiceUnavailableException.php index 88f20a8..fbaa24f 100644 --- a/src/Exception/Api/ServiceUnavailableException.php +++ b/src/Exception/API/ServiceUnavailableException.php @@ -8,23 +8,13 @@ * file that was distributed with this source code. */ -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; +namespace ahmedghanem00\TempNumberClient\Exception\API; /** * */ -class ServiceUnavailableException extends ApiException implements TemporaryExceptionInterface +class ServiceUnavailableException extends APIException implements TemporaryErrorInterface { - /** - * - */ - public function __construct() - { - ClientException::__construct('Service Unavailable'); - } - /** * @return int */ diff --git a/src/Exception/Api/TemporaryExceptionInterface.php b/src/Exception/API/TemporaryErrorInterface.php similarity index 80% rename from src/Exception/Api/TemporaryExceptionInterface.php rename to src/Exception/API/TemporaryErrorInterface.php index 83b5a4d..7b3bebf 100644 --- a/src/Exception/Api/TemporaryExceptionInterface.php +++ b/src/Exception/API/TemporaryErrorInterface.php @@ -8,17 +8,15 @@ * file that was distributed with this source code. */ -namespace ahmedghanem00\TempNumberClient\Exception\Api; +namespace ahmedghanem00\TempNumberClient\Exception\API; /** * */ -interface TemporaryExceptionInterface +interface TemporaryErrorInterface { - /** * @return int Seconds to wait before making next retry */ public function retryAfter(): int; - } diff --git a/src/Exception/Api/TooManyActivationsPendingException.php b/src/Exception/API/TooManyActivationsPendingException.php similarity index 52% rename from src/Exception/Api/TooManyActivationsPendingException.php rename to src/Exception/API/TooManyActivationsPendingException.php index 06721db..1e0a5c1 100644 --- a/src/Exception/Api/TooManyActivationsPendingException.php +++ b/src/Exception/API/TooManyActivationsPendingException.php @@ -8,23 +8,13 @@ * file that was distributed with this source code. */ -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; +namespace ahmedghanem00\TempNumberClient\Exception\API; /** * */ -class TooManyActivationsPendingException extends ApiException implements TemporaryExceptionInterface +class TooManyActivationsPendingException extends APIException implements TemporaryErrorInterface { - /** - * - */ - public function __construct() - { - ClientException::__construct("Too many activations pending"); - } - /** * @return int */ diff --git a/src/Exception/Api/AccountOnHoldException.php b/src/Exception/API/TooManyRequestsException.php similarity index 51% rename from src/Exception/Api/AccountOnHoldException.php rename to src/Exception/API/TooManyRequestsException.php index 5cfb8ed..a0ae066 100644 --- a/src/Exception/Api/AccountOnHoldException.php +++ b/src/Exception/API/TooManyRequestsException.php @@ -8,14 +8,12 @@ * file that was distributed with this source code. */ -namespace ahmedghanem00\TempNumberClient\Exception\Api; +namespace ahmedghanem00\TempNumberClient\Exception\API; -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -class AccountOnHoldException extends ApiException +class TooManyRequestsException extends APIException implements TemporaryErrorInterface { - public function __construct() + public function retryAfter(): int { - ClientException::__construct("Account is in hold state"); + return 0; } } diff --git a/src/Exception/API/UnauthorizedServiceException.php b/src/Exception/API/UnauthorizedServiceException.php new file mode 100644 index 0000000..a789c81 --- /dev/null +++ b/src/Exception/API/UnauthorizedServiceException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ahmedghanem00\TempNumberClient\Exception\API; + +/** + * + */ +class UnauthorizedServiceException extends APIException +{ +} diff --git a/src/Exception/Api/ApiException.php b/src/Exception/Api/ApiException.php deleted file mode 100644 index 5e9c91f..0000000 --- a/src/Exception/Api/ApiException.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; -use Symfony\Contracts\HttpClient\ResponseInterface; - -class ApiException extends ClientException -{ - private ResponseInterface $response; - - public function __construct() - { - parent::__construct('API Error'); - } - - public function getResponse(): ResponseInterface - { - return $this->response; - } - - public function setResponse(ResponseInterface $response): void - { - $this->response = $response; - } -} diff --git a/src/Exception/Api/ExpectedPriceException.php b/src/Exception/Api/ExpectedPriceException.php deleted file mode 100644 index 1bad3fa..0000000 --- a/src/Exception/Api/ExpectedPriceException.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -class ExpectedPriceException extends ApiException -{ - public function __construct( - private readonly float $newPrice - ) - { - ClientException::__construct("Activation price has changed to ( $newPrice ) which is greater than the expected"); - } - - public function getNewPrice(): float - { - return $this->newPrice; - } -} diff --git a/src/Exception/Api/GoneException.php b/src/Exception/Api/GoneException.php deleted file mode 100644 index ec0e5c0..0000000 --- a/src/Exception/Api/GoneException.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -class GoneException extends ApiException -{ - public function __construct() - { - ClientException::__construct("The target resource is no longer available"); - } -} diff --git a/src/Exception/Api/InvalidRequestParamsException.php b/src/Exception/Api/InvalidRequestParamsException.php deleted file mode 100644 index 988cf67..0000000 --- a/src/Exception/Api/InvalidRequestParamsException.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -class InvalidRequestParamsException extends ApiException -{ - public function __construct() - { - ClientException::__construct("Invalid request params"); - } -} diff --git a/src/Exception/Api/PaymentRequiredException.php b/src/Exception/Api/PaymentRequiredException.php deleted file mode 100644 index 6cd542f..0000000 --- a/src/Exception/Api/PaymentRequiredException.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -/** - * - */ -class PaymentRequiredException extends ApiException -{ - /** - * - */ - public function __construct() - { - ClientException::__construct("Looks like the current balance is not enough to perform this request"); - } -} diff --git a/src/Exception/Api/ResourceBadStateException.php b/src/Exception/Api/ResourceBadStateException.php deleted file mode 100644 index 71ff146..0000000 --- a/src/Exception/Api/ResourceBadStateException.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -/** - * - */ -class ResourceBadStateException extends ApiException implements TemporaryExceptionInterface -{ - /** - * - */ - public function __construct() - { - ClientException::__construct("Resource is in a bad state"); - } - - /** - * @return int - */ - public function retryAfter(): int - { - return 10 * 60; - } -} diff --git a/src/Exception/Api/TooManyRequestsException.php b/src/Exception/Api/TooManyRequestsException.php deleted file mode 100644 index d0d25e0..0000000 --- a/src/Exception/Api/TooManyRequestsException.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -class TooManyRequestsException extends ApiException implements TemporaryExceptionInterface -{ - /** - * - */ - public function __construct() - { - ClientException::__construct("Too many requests"); - } - - public function retryAfter(): int - { - return 0; - } -} diff --git a/src/Exception/Api/UnauthorizedServiceException.php b/src/Exception/Api/UnauthorizedServiceException.php deleted file mode 100644 index 18eb668..0000000 --- a/src/Exception/Api/UnauthorizedServiceException.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ahmedghanem00\TempNumberClient\Exception\Api; - -use ahmedghanem00\TempNumberClient\Exception\ClientException; - -/** - * - */ -class UnauthorizedServiceException extends ApiException -{ - /** - * - */ - public function __construct() - { - ClientException::__construct('Unauthorized access to this resource. Please recheck the configured api token'); - } -} diff --git a/src/Exception/ClientException.php b/src/Exception/ClientException.php index 4fa2bea..c7055d7 100644 --- a/src/Exception/ClientException.php +++ b/src/Exception/ClientException.php @@ -20,6 +20,7 @@ class ClientException extends RuntimeException public function __construct(string $message = "", int $code = 0, Throwable $previous = null, array $additionalData = []) { $this->additionalData = $additionalData; + parent::__construct($message, $code, $previous); } diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index bf95336..2f70969 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -103,7 +103,7 @@ public function testRetryActivation() $this->client->retryActivation(7378322); $this->assertTrue(true); } catch (Exception $e) { - $this->fail($e->getMessage()); + throw $e; } } @@ -229,7 +229,7 @@ protected function setUp(): void $this->client = new Client(getenv('API_KEY'), null, $backendServer); $this->client->applyHttpClientOptions([ - #'proxy' => '127.0.0.1:9090', 'verify_peer' => false, + # 'proxy' => '127.0.0.1:9090', 'verify_peer' => false, ]); } }