diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ca311b..2068a35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,27 @@ jobs: - name: Run friendsofphp/php-cs-fixer run: composer php-cs + type-checker: + name: Type Checker + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.0 + coverage: none + + - name: Install composer dependencies + uses: ramsey/composer-install@v1 + + - name: Run vimeo/psalm + run: composer psalm + tests: name: Tests diff --git a/composer.json b/composer.json index 7c87bd4..9be5435 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ "php-http/mock-client": "^1.4", "phpunit/phpunit": "^8.5", "symfony/http-client": "^5.3", - "symfony/var-dumper": "^5.3" + "symfony/var-dumper": "^5.3", + "vimeo/psalm": "^4.8" }, "config": { "sort-packages": true @@ -41,6 +42,7 @@ "minimum-stability": "dev", "prefer-stable": true, "scripts": { + "psalm": "@php vendor/bin/psalm --no-progress", "php-cs": "@php vendor/bin/php-cs-fixer fix --dry-run", "php-cs-fix": "@php vendor/bin/php-cs-fixer fix", "test": "@php vendor/bin/phpunit --configuration phpunit.dist.xml", diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..f6529b3 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Client.php b/src/Client.php index c977472..9f29fe0 100644 --- a/src/Client.php +++ b/src/Client.php @@ -4,12 +4,12 @@ namespace BlueMedia; +use BlueMedia\Common\ValueObject\HashableInterface; use BlueMedia\Confirmation\Builder\ConfirmationVOBuilder; use BlueMedia\HttpClient\HttpClientInterface; use BlueMedia\Hash\HashChecker; use BlueMedia\Itn\Builder\ItnVOBuilder; use BlueMedia\Itn\Decoder\ItnDecoder; -use BlueMedia\Serializer\SerializableInterface; use BlueMedia\Transaction\View; use BlueMedia\Itn\ValueObject\Itn; use BlueMedia\HttpClient\HttpClient; @@ -40,7 +40,7 @@ final class Client private $configuration; /** - * @var HttpClientInterface|null + * @var HttpClientInterface */ private $httpClient; @@ -126,11 +126,9 @@ public function doItnIn(string $itn): Response /** * Returns response for ITN IN request. * - * @return Response - * * @api */ - public function doItnInResponse(Itn $itn, bool $transactionConfirmed = true) + public function doItnInResponse(Itn $itn, bool $transactionConfirmed = true): Response { return new Response(ItnResponseBuilder::build($itn, $transactionConfirmed, $this->configuration)); } @@ -196,7 +194,7 @@ public function getRegulationList(string $gatewayUrl): Response * * @api */ - public function checkHash(SerializableInterface $data): bool + public function checkHash(HashableInterface $data): bool { return HashChecker::checkHash($data, $this->configuration); } diff --git a/src/Common/Builder/ServiceDtoBuilder.php b/src/Common/Builder/ServiceDtoBuilder.php index 32c02e0..c8da477 100644 --- a/src/Common/Builder/ServiceDtoBuilder.php +++ b/src/Common/Builder/ServiceDtoBuilder.php @@ -11,6 +11,12 @@ final class ServiceDtoBuilder { + /** + * @template T of AbstractDto + * @psalm-param class-string $type + * + * @return T + */ public static function build(array $data, string $type, Configuration $configuration): AbstractDto { $serializer = new Serializer(); diff --git a/src/Common/Dto/AbstractDto.php b/src/Common/Dto/AbstractDto.php index f860d0c..6aa1369 100644 --- a/src/Common/Dto/AbstractDto.php +++ b/src/Common/Dto/AbstractDto.php @@ -4,8 +4,8 @@ namespace BlueMedia\Common\Dto; +use BlueMedia\Common\ValueObject\AbstractValueObject; use BlueMedia\HttpClient\ValueObject\Request; -use BlueMedia\Serializer\SerializableInterface; use JMS\Serializer\Annotation\Type; abstract class AbstractDto @@ -39,5 +39,5 @@ public function getRequest(): ?Request return $this->request; } - abstract public function getRequestData(): SerializableInterface; + abstract public function getRequestData(): AbstractValueObject; } diff --git a/src/Common/Parser/ServiceResponseParser.php b/src/Common/Parser/ServiceResponseParser.php index e9535d9..9d014db 100644 --- a/src/Common/Parser/ServiceResponseParser.php +++ b/src/Common/Parser/ServiceResponseParser.php @@ -9,6 +9,12 @@ final class ServiceResponseParser extends ResponseParser { + /** + * @template T + * @psalm-param class-string $type + * + * @return T + */ public function parseListResponse(string $type): SerializableInterface { $this->isErrorResponse(); diff --git a/src/Common/ValueObject/HashableInterface.php b/src/Common/ValueObject/HashableInterface.php new file mode 100644 index 0000000..9cb5cd2 --- /dev/null +++ b/src/Common/ValueObject/HashableInterface.php @@ -0,0 +1,10 @@ +toArray(), diff --git a/src/Itn/Builder/ItnDtoBuilder.php b/src/Itn/Builder/ItnDtoBuilder.php index 1699114..52bf57e 100644 --- a/src/Itn/Builder/ItnDtoBuilder.php +++ b/src/Itn/Builder/ItnDtoBuilder.php @@ -5,18 +5,18 @@ namespace BlueMedia\Itn\Builder; use BlueMedia\Itn\Dto\ItnDto; -use BlueMedia\Serializer\SerializableInterface; use BlueMedia\Serializer\Serializer; use BlueMedia\Common\Util\XMLParser; final class ItnDtoBuilder { - public static function build(string $itnData): SerializableInterface + public static function build(string $itnData): ItnDto { $serializer = new Serializer(); $xmlData = XMLParser::parse($itnData); $xmlTransaction = $xmlData->transactions->transaction->asXML(); + /** @var ItnDto $itnDto */ $itnDto = $serializer->deserializeXml($xmlTransaction, ItnDto::class); $itnDto->getItn()->setServiceID((string) $xmlData->serviceID); diff --git a/src/Itn/Dto/ItnDto.php b/src/Itn/Dto/ItnDto.php index 8152655..96bbbe0 100644 --- a/src/Itn/Dto/ItnDto.php +++ b/src/Itn/Dto/ItnDto.php @@ -5,6 +5,7 @@ namespace BlueMedia\Itn\Dto; use BlueMedia\Common\Dto\AbstractDto; +use BlueMedia\Common\ValueObject\AbstractValueObject; use BlueMedia\Itn\ValueObject\Itn; use BlueMedia\Serializer\SerializableInterface; use JMS\Serializer\Annotation\XmlList; @@ -24,7 +25,7 @@ public function getItn(): Itn return $this->itn; } - public function getRequestData(): SerializableInterface + public function getRequestData(): AbstractValueObject { return $this->getItn(); } diff --git a/src/PaywayList/Dto/PaywayListDto.php b/src/PaywayList/Dto/PaywayListDto.php index 89c9147..4819251 100644 --- a/src/PaywayList/Dto/PaywayListDto.php +++ b/src/PaywayList/Dto/PaywayListDto.php @@ -5,8 +5,8 @@ namespace BlueMedia\PaywayList\Dto; use BlueMedia\Common\Dto\AbstractDto; +use BlueMedia\Common\ValueObject\AbstractValueObject; use JMS\Serializer\Annotation\Type; -use BlueMedia\Serializer\SerializableInterface; use BlueMedia\PaywayList\ValueObject\PaywayList; final class PaywayListDto extends AbstractDto @@ -22,7 +22,7 @@ public function getPaywayList(): PaywayList return $this->paywayList; } - public function getRequestData(): SerializableInterface + public function getRequestData(): AbstractValueObject { return $this->getPaywayList(); } diff --git a/src/RegulationList/Dto/RegulationListDto.php b/src/RegulationList/Dto/RegulationListDto.php index b6e0986..013534f 100644 --- a/src/RegulationList/Dto/RegulationListDto.php +++ b/src/RegulationList/Dto/RegulationListDto.php @@ -4,9 +4,9 @@ namespace BlueMedia\RegulationList\Dto; +use BlueMedia\Common\ValueObject\AbstractValueObject; use JMS\Serializer\Annotation\Type; use BlueMedia\Common\Dto\AbstractDto; -use BlueMedia\Serializer\SerializableInterface; use BlueMedia\RegulationList\ValueObject\RegulationList; final class RegulationListDto extends AbstractDto @@ -22,7 +22,7 @@ public function getRegulationList(): RegulationList return $this->regulationList; } - public function getRequestData(): SerializableInterface + public function getRequestData(): AbstractValueObject { return $this->getRegulationList(); } diff --git a/src/Serializer/Serializer.php b/src/Serializer/Serializer.php index d2d2d2b..e75ea40 100644 --- a/src/Serializer/Serializer.php +++ b/src/Serializer/Serializer.php @@ -4,7 +4,6 @@ namespace BlueMedia\Serializer; -use BlueMedia\Common\Dto\AbstractDto; use JMS\Serializer\SerializerBuilder; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; @@ -13,6 +12,9 @@ final class Serializer implements SerializerInterface { private const XML_TYPE = 'xml'; + /** + * @var \JMS\Serializer\Serializer + */ private $serializer; public function __construct() @@ -26,7 +28,13 @@ public function __construct() ->build(); } - public function serializeDataToDto(array $data, string $type): AbstractDto + /** + * @template T + * @psalm-param class-string $type + * + * @return T + */ + public function serializeDataToDto(array $data, string $type) { return $this->serializer->fromArray($data, $type); } @@ -36,12 +44,24 @@ public function toArray(object $object): array return $this->serializer->toArray($object); } + /** + * @template T + * @psalm-param class-string $type + * + * @return T + */ public function fromArray(array $data, string $type) { return $this->serializer->fromArray($data, $type); } - public function deserializeXml(string $xml, string $type): SerializableInterface + /** + * @template T + * @psalm-param class-string $type + * + * @return T + */ + public function deserializeXml(string $xml, string $type) { return $this->serializer->deserialize($xml, $type, self::XML_TYPE); } diff --git a/src/Serializer/SerializerInterface.php b/src/Serializer/SerializerInterface.php index 5807679..2a8fd7f 100644 --- a/src/Serializer/SerializerInterface.php +++ b/src/Serializer/SerializerInterface.php @@ -4,17 +4,33 @@ namespace BlueMedia\Serializer; -use BlueMedia\Common\Dto\AbstractDto; - interface SerializerInterface { - public function serializeDataToDto(array $data, string $type): AbstractDto; + /** + * @template T + * @psalm-param class-string $type + * + * @return T + */ + public function serializeDataToDto(array $data, string $type); public function toArray(object $object): array; + /** + * @template T + * @psalm-param class-string $type + * + * @return T + */ public function fromArray(array $data, string $type); - public function deserializeXml(string $xml, string $type): SerializableInterface; + /** + * @template T + * @psalm-param class-string $type + * + * @return T + */ + public function deserializeXml(string $xml, string $type); public function toXml($data): string; } diff --git a/src/Transaction/Builder/TransactionDtoBuilder.php b/src/Transaction/Builder/TransactionDtoBuilder.php index 285dc67..85dacaf 100644 --- a/src/Transaction/Builder/TransactionDtoBuilder.php +++ b/src/Transaction/Builder/TransactionDtoBuilder.php @@ -4,7 +4,6 @@ namespace BlueMedia\Transaction\Builder; -use BlueMedia\Common\Dto\AbstractDto; use BlueMedia\Configuration; use BlueMedia\Hash\HashGenerator; use BlueMedia\Serializer\Serializer; @@ -12,9 +11,10 @@ final class TransactionDtoBuilder { - public static function build(array $transactionData, Configuration $configuration): AbstractDto + public static function build(array $transactionData, Configuration $configuration): TransactionDto { $serializer = new Serializer(); + /** @var TransactionDto $transactionDto */ $transactionDto = $serializer->serializeDataToDto($transactionData, TransactionDto::class); $transactionDto->getTransaction()->setServiceId($configuration->getServiceId()); diff --git a/src/Transaction/Dto/TransactionDto.php b/src/Transaction/Dto/TransactionDto.php index 7cdc88e..3b3397b 100644 --- a/src/Transaction/Dto/TransactionDto.php +++ b/src/Transaction/Dto/TransactionDto.php @@ -5,7 +5,7 @@ namespace BlueMedia\Transaction\Dto; use BlueMedia\Common\Dto\AbstractDto; -use BlueMedia\Serializer\SerializableInterface; +use BlueMedia\Common\ValueObject\AbstractValueObject; use BlueMedia\Transaction\ValueObject\Transaction; use JMS\Serializer\Annotation\Type; @@ -44,7 +44,7 @@ public function setHtmlFormLanguage(string $htmlFormLanguage): self return $this; } - public function getRequestData(): SerializableInterface + public function getRequestData(): AbstractValueObject { return $this->getTransaction(); } diff --git a/src/Transaction/ValueObject/Transaction.php b/src/Transaction/ValueObject/Transaction.php index b8956c7..252d796 100644 --- a/src/Transaction/ValueObject/Transaction.php +++ b/src/Transaction/ValueObject/Transaction.php @@ -4,6 +4,7 @@ namespace BlueMedia\Transaction\ValueObject; +use BlueMedia\Common\ValueObject\HashableInterface; use BlueMedia\Serializer\SerializableInterface; use BlueMedia\Common\ValueObject\AbstractValueObject; use JMS\Serializer\Annotation\Type; @@ -43,7 +44,7 @@ * "hash" * }) */ -class Transaction extends AbstractValueObject implements SerializableInterface +class Transaction extends AbstractValueObject implements SerializableInterface, HashableInterface { /** * Transaction service id. diff --git a/src/Transaction/View.php b/src/Transaction/View.php index 555cf2f..4ac5a15 100644 --- a/src/Transaction/View.php +++ b/src/Transaction/View.php @@ -4,13 +4,13 @@ namespace BlueMedia\Transaction; -use BlueMedia\Common\Dto\AbstractDto; use BlueMedia\Common\Enum\ClientEnum; use BlueMedia\Common\Util\Translations; +use BlueMedia\Transaction\Dto\TransactionDto; final class View { - public static function createRedirectHtml(AbstractDto $transactionDto): string + public static function createRedirectHtml(TransactionDto $transactionDto): string { $translation = (new Translations())->getTranslation( $transactionDto->getHtmlFormLanguage()