diff --git a/composer.json b/composer.json index bbf75a0..19bc629 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "post-install-cmd": "cghooks add --ignore-lock", "post-update-cmd": "cghooks update", "phpunit": "./vendor/bin/phpunit -c phpunit.xml.dist", - "phpmd": "./vendor/bin/phpmd src text controversial,design,./phpmd.xml", + "phpmd": "./vendor/bin/phpmd src text controversial,./phpmd.xml", "phpcs": "./vendor/bin/phpcs -p src --runtime-set testVersion 7.3", "lint": "composer run-script phpcs && composer run-script phpmd", "ci": "composer run-script lint && composer run-script phpunit" @@ -51,7 +51,6 @@ "extra": { "hooks": { "pre-commit": [ - "echo => Running code quality tools...", "composer run-script lint" ] } diff --git a/phpmd.xml b/phpmd.xml index fee5306..65f6fc3 100644 --- a/phpmd.xml +++ b/phpmd.xml @@ -19,11 +19,19 @@ + + + + + + + + diff --git a/src/Component/Exception/TopApiException.php b/src/Component/Exception/TopApiException.php new file mode 100644 index 0000000..463295a --- /dev/null +++ b/src/Component/Exception/TopApiException.php @@ -0,0 +1,70 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +namespace RetailCrm\Component\Exception; + +use Exception; +use RetailCrm\Model\Response\Body\ErrorResponseBody; +use Throwable; + +/** + * Class TopApiException + * + * @category TopApiException + * @package RetailCrm\Component\Exception + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +class TopApiException extends Exception +{ + /** + * @var string $subCode + */ + private $subCode; + + /** + * @var string $requestId + */ + private $requestId; + + /** + * TopApiException constructor. + * + * @param \RetailCrm\Model\Response\Body\ErrorResponseBody $responseBody + * @param \Throwable|null $previous + */ + public function __construct(ErrorResponseBody $responseBody, Throwable $previous = null) + { + parent::__construct($responseBody->msg, $responseBody->code, $previous); + + $this->subCode = $responseBody->subCode; + $this->requestId = $responseBody->requestId; + } + + /** + * @return string + */ + public function getSubCode(): string + { + return $this->subCode; + } + + /** + * @return string + */ + public function getRequestId(): string + { + return $this->requestId; + } +} diff --git a/src/Component/Exception/TopClientException.php b/src/Component/Exception/TopClientException.php new file mode 100644 index 0000000..3c8d87d --- /dev/null +++ b/src/Component/Exception/TopClientException.php @@ -0,0 +1,29 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +namespace RetailCrm\Component\Exception; + +use Exception; + +/** + * Class TopClientException + * + * @category TopClientException + * @package RetailCrm\Component\Exception + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +class TopClientException extends Exception +{ +} diff --git a/src/Model/Request/HttpDnsGetRequest.php b/src/Model/Request/HttpDnsGetRequest.php index ee1b1a6..fe12595 100644 --- a/src/Model/Request/HttpDnsGetRequest.php +++ b/src/Model/Request/HttpDnsGetRequest.php @@ -12,6 +12,8 @@ */ namespace RetailCrm\Model\Request; +use RetailCrm\Model\Response\BaseResponse; + /** * Class HttpDnsGetRequest * @@ -42,6 +44,6 @@ class HttpDnsGetRequest extends BaseRequest public function getExpectedResponse(): string { // TODO: Implement getExpectedResponse() method. - return ''; + return BaseResponse::class; } } diff --git a/src/Model/Response/BaseResponse.php b/src/Model/Response/BaseResponse.php new file mode 100644 index 0000000..9a96e93 --- /dev/null +++ b/src/Model/Response/BaseResponse.php @@ -0,0 +1,36 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +namespace RetailCrm\Model\Response; + +use JMS\Serializer\Annotation as JMS; + +/** + * Class BaseResponse + * + * @category BaseResponse + * @package RetailCrm\Model\Response + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +class BaseResponse +{ + /** + * @var \RetailCrm\Model\Response\Body\ErrorResponseBody + * + * @JMS\Type("RetailCrm\Model\Response\Body\ErrorResponseBody") + * @JMS\SerializedName("error_response") + */ + public $errorResponse; +} diff --git a/src/Model/Response/Body/ErrorResponseBody.php b/src/Model/Response/Body/ErrorResponseBody.php new file mode 100644 index 0000000..9547773 --- /dev/null +++ b/src/Model/Response/Body/ErrorResponseBody.php @@ -0,0 +1,60 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +namespace RetailCrm\Model\Response\Body; + +use JMS\Serializer\Annotation as JMS; + +/** + * Class ErrorResponseBody + * + * @category ErrorResponseBody + * @package RetailCrm\Model\Response\Body + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +class ErrorResponseBody +{ + /** + * @var int $code + * + * @JMS\Type("int") + * @JMS\SerializedName("code") + */ + public $code; + + /** + * @var string $msg + * + * @JMS\Type("string") + * @JMS\SerializedName("msg") + */ + public $msg; + + /** + * @var string $subCode + * + * @JMS\Type("string") + * @JMS\SerializedName("sub_code") + */ + public $subCode; + + /** + * @var string $requestId + * + * @JMS\Type("string") + * @JMS\SerializedName("request_id") + */ + public $requestId; +} diff --git a/src/TopClient/Client.php b/src/TopClient/Client.php index 6fb6263..2983c93 100644 --- a/src/TopClient/Client.php +++ b/src/TopClient/Client.php @@ -14,11 +14,14 @@ namespace RetailCrm\TopClient; use JMS\Serializer\SerializerInterface; use Psr\Http\Client\ClientInterface; +use RetailCrm\Component\Exception\TopApiException; +use RetailCrm\Component\Exception\TopClientException; use RetailCrm\Component\ServiceLocator; use RetailCrm\Interfaces\AppDataInterface; use RetailCrm\Interfaces\AuthenticatorInterface; use RetailCrm\Interfaces\RequestFactoryInterface; use RetailCrm\Model\Request\BaseRequest; +use RetailCrm\Model\Response\BaseResponse; use RetailCrm\Traits\ValidatorAwareTrait; use Symfony\Component\Validator\Constraints as Assert; @@ -138,17 +141,32 @@ class Client /** * @param \RetailCrm\Model\Request\BaseRequest $request * - * @return void + * @return \RetailCrm\Model\Response\BaseResponse * @throws \Psr\Http\Client\ClientExceptionInterface * @throws \RetailCrm\Component\Exception\ValidationException * @throws \RetailCrm\Component\Exception\FactoryException - * - * @todo Implement this method and remove tag below. - * @SuppressWarnings(PHPMD) + * @throws \RetailCrm\Component\Exception\TopClientException + * @throws \RetailCrm\Component\Exception\TopApiException */ public function sendRequest(BaseRequest $request) { $httpRequest = $this->requestFactory->fromModel($request, $this->appData, $this->authenticator); - $response = $this->httpClient->sendRequest($httpRequest); + $httpResponse = $this->httpClient->sendRequest($httpRequest); + /** @var BaseResponse $response */ + $response = $this->serializer->deserialize( + $httpResponse->getBody()->getContents(), + $request->getExpectedResponse(), + $request->format + ); + + if (!($response instanceof BaseResponse) && !is_subclass_of($response, BaseResponse::class)) { + throw new TopClientException(sprintf('Invalid response class: %s', get_class($response))); + } + + if (null !== $response->errorResponse) { + throw new TopApiException($response->errorResponse); + } + + return $response; } } diff --git a/tests/RetailCrm/Tests/TopClient/ClientTest.php b/tests/RetailCrm/Tests/TopClient/ClientTest.php index a4d8235..37de4c8 100644 --- a/tests/RetailCrm/Tests/TopClient/ClientTest.php +++ b/tests/RetailCrm/Tests/TopClient/ClientTest.php @@ -32,7 +32,7 @@ class ClientTest extends TestCase { public function testClientRequest() { - self::markTestSkipped('Not implemented yet'); + self::markTestSkipped('Should be mocked!'); $client = ClientBuilder::create() ->setContainer($this->getContainer())