From 26670b95e57a1ed1356e350a63909d227c7723fa Mon Sep 17 00:00:00 2001 From: MustangGB Date: Sun, 25 Feb 2024 17:26:52 +0000 Subject: [PATCH] Fix psalm errors --- .../CurrencyToArrayTransformerTest.php | 2 +- .../RatioProvider/ECBRatioProviderTest.php | 2 +- .../ExchangerAdapterRatioProviderTest.php | 4 +--- src/Command/RatioListCommand.php | 6 ++--- .../CurrencyToArrayTransformer.php | 23 ++++++++++++++---- .../MoneyToArrayTransformer.php | 24 +++++++++++++++---- .../SimpleMoneyToArrayTransformer.php | 14 +++++++---- src/Money/MoneyManager.php | 11 ++++++++- src/Pair/PairManager.php | 17 +++++++++++++ src/Pair/PairManagerInterface.php | 2 +- src/Pair/RatioProvider/ECBRatioProvider.php | 5 ++-- .../ExchangerAdapterRatioProvider.php | 4 ++++ src/Pair/Storage/CsvStorage.php | 4 ++++ src/Pair/Storage/DoctrineStorage.php | 16 +++++++++---- src/Pair/Storage/DocumentStorage.php | 16 +++++++++---- src/TbbcMoneyBundle.php | 3 +++ src/Type/MoneyType.php | 12 +++++++--- 17 files changed, 128 insertions(+), 37 deletions(-) diff --git a/Tests/Form/DataTransformer/CurrencyToArrayTransformerTest.php b/Tests/Form/DataTransformer/CurrencyToArrayTransformerTest.php index a8247562..310e1d0d 100644 --- a/Tests/Form/DataTransformer/CurrencyToArrayTransformerTest.php +++ b/Tests/Form/DataTransformer/CurrencyToArrayTransformerTest.php @@ -70,7 +70,7 @@ public function testReverseFormValueIsNotArray(): void public function testReverseThrowExceptionIfCurrencyCodeNotValid(): void { - $this->expectException(TransformationFailedException::class); + $this->expectException(UnexpectedTypeException::class); $value = ['tbbc_name' => 123]; $transformer = new CurrencyToArrayTransformer(); $transformer->reverseTransform($value); diff --git a/Tests/Pair/RatioProvider/ECBRatioProviderTest.php b/Tests/Pair/RatioProvider/ECBRatioProviderTest.php index 4341886a..00ab5318 100644 --- a/Tests/Pair/RatioProvider/ECBRatioProviderTest.php +++ b/Tests/Pair/RatioProvider/ECBRatioProviderTest.php @@ -55,7 +55,7 @@ public function testNotCorrectReferenceCode(): void public function testUnknownCurrency(): void { $this->expectException(MoneyException::class); - $this->expectExceptionMessage('The currency code "" does not exist'); + $this->expectExceptionMessage('The currency code is an empty string'); $this->ratio->fetchRatio('EUR', ''); } diff --git a/Tests/Pair/RatioProvider/ExchangerAdapterRatioProviderTest.php b/Tests/Pair/RatioProvider/ExchangerAdapterRatioProviderTest.php index 9b0ebba2..7d39c8b9 100644 --- a/Tests/Pair/RatioProvider/ExchangerAdapterRatioProviderTest.php +++ b/Tests/Pair/RatioProvider/ExchangerAdapterRatioProviderTest.php @@ -32,9 +32,7 @@ protected function getRatioProvider(): RatioProviderInterface public function testInvalidCurrencyCode(): void { $this->expectException(MoneyException::class); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The currency pair must be in the form "EUR/USD".'); - //$this->expectExceptionMessage('The currency code "" does not exist'); + $this->expectExceptionMessage('The currency code is an empty string'); $ratiosSetup['EUR/123'] = $this->randomRatio(1, 3, 1); $service = new PhpArray($ratiosSetup); diff --git a/src/Command/RatioListCommand.php b/src/Command/RatioListCommand.php index fd098705..16d3d28e 100644 --- a/src/Command/RatioListCommand.php +++ b/src/Command/RatioListCommand.php @@ -35,7 +35,7 @@ protected function configure(): void } /** - * @param array $ratioList + * @param array $ratioList */ protected function displayTxt(array $ratioList, OutputInterface $output, SymfonyStyle $io): int { @@ -49,7 +49,7 @@ protected function displayTxt(array $ratioList, OutputInterface $output, Symfony } /** - * @param array $ratioList + * @param array $ratioList */ protected function displayTable(array $ratioList, OutputInterface $output, SymfonyStyle $io): int { @@ -67,7 +67,7 @@ protected function displayTable(array $ratioList, OutputInterface $output, Symfo } /** - * @param array $ratioList + * @param array $ratioList * @throws \JsonException */ protected function displayJson(array $ratioList, OutputInterface $output): int diff --git a/src/Form/DataTransformer/CurrencyToArrayTransformer.php b/src/Form/DataTransformer/CurrencyToArrayTransformer.php index 6b3af87a..fc1695cb 100644 --- a/src/Form/DataTransformer/CurrencyToArrayTransformer.php +++ b/src/Form/DataTransformer/CurrencyToArrayTransformer.php @@ -12,14 +12,18 @@ use TypeError; /** - * Transforms between a Currency and a string. + * Transforms between a Currency and an array. + * + * @implements DataTransformerInterface */ class CurrencyToArrayTransformer implements DataTransformerInterface { /** * {@inheritdoc} + * + * @psalm-param Currency|null $value */ - public function transform($value): ?array + public function transform(mixed $value): ?array { if (null === $value) { return null; @@ -33,15 +37,16 @@ public function transform($value): ?array /** * {@inheritdoc} - * - * @psalm-suppress MixedArgument + * + * @psalm-param array|null $value */ - public function reverseTransform($value): ?Currency + public function reverseTransform(mixed $value): ?Currency { if (null === $value) { return null; } + /** @psalm-suppress DocblockTypeContradiction */ if (!is_array($value)) { throw new UnexpectedTypeException($value, 'array'); } @@ -50,6 +55,14 @@ public function reverseTransform($value): ?Currency return null; } + if (!is_string($value['tbbc_name'])) { + throw new UnexpectedTypeException($value, 'string'); + } + + if ('' === $value['tbbc_name']) { + throw new TransformationFailedException('name can not be an empty string'); + } + try { return new Currency($value['tbbc_name']); } catch (InvalidArgumentException|TypeError $e) { diff --git a/src/Form/DataTransformer/MoneyToArrayTransformer.php b/src/Form/DataTransformer/MoneyToArrayTransformer.php index 61243902..cd6bef98 100644 --- a/src/Form/DataTransformer/MoneyToArrayTransformer.php +++ b/src/Form/DataTransformer/MoneyToArrayTransformer.php @@ -7,11 +7,14 @@ use Money\Currency; use Money\Money; use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer; /** - * Transforms between a Money instance and an array. + * Transforms between a Money and an array. + * + * @implements DataTransformerInterface */ class MoneyToArrayTransformer implements DataTransformerInterface { @@ -24,10 +27,12 @@ public function __construct(protected int $decimals = 2) /** * {@inheritdoc} - * - * @psalm-return array{tbbc_amount: string, tbbc_currency: Currency}|null + * + * @psalm-param Money|null $value + * + * @psalm-return array{tbbc_amount: string, tbbc_currency: Currency}|array{tbbc_amount: string}|null */ - public function transform($value): ?array + public function transform(mixed $value): ?array { if (null === $value) { return null; @@ -47,16 +52,20 @@ public function transform($value): ?array /** * {@inheritdoc} + * + * @psalm-param array|null $value */ - public function reverseTransform($value): ?Money + public function reverseTransform(mixed $value): ?Money { if (null === $value) { return null; } + /** @psalm-suppress DocblockTypeContradiction */ if (!is_array($value)) { throw new UnexpectedTypeException($value, 'array'); } + if (!isset($value['tbbc_amount']) || !isset($value['tbbc_currency'])) { return null; } @@ -69,6 +78,11 @@ public function reverseTransform($value): ?Money /** @var string|Currency $currency */ $currency = $value['tbbc_currency']; + + if ('' === $currency) { + throw new TransformationFailedException('currency can not be an empty string'); + } + if (!$currency instanceof Currency) { $currency = new Currency($currency); } diff --git a/src/Form/DataTransformer/SimpleMoneyToArrayTransformer.php b/src/Form/DataTransformer/SimpleMoneyToArrayTransformer.php index d23dcd2c..fdcfd99f 100644 --- a/src/Form/DataTransformer/SimpleMoneyToArrayTransformer.php +++ b/src/Form/DataTransformer/SimpleMoneyToArrayTransformer.php @@ -7,21 +7,25 @@ use Money\Money; /** - * Transforms between a Money instance and an array. + * Transforms between a Money and an array. */ class SimpleMoneyToArrayTransformer extends MoneyToArrayTransformer { protected string $currency = ''; - public function __construct(int $decimals) + public function __construct(protected int $decimals) { parent::__construct($decimals); } /** * {@inheritdoc} + * + * @psalm-param Money|null $value + * + * @psalm-return array{tbbc_amount: string}|null */ - public function transform($value): ?array + public function transform(mixed $value): ?array { if (!$tab = parent::transform($value)) { return null; @@ -34,8 +38,10 @@ public function transform($value): ?array /** * {@inheritdoc} + * + * @psalm-param array|null $value */ - public function reverseTransform($value): ?Money + public function reverseTransform(mixed $value): ?Money { if (is_array($value)) { $value['tbbc_currency'] = $this->currency; diff --git a/src/Money/MoneyManager.php b/src/Money/MoneyManager.php index 7a6d4f78..37c6e308 100644 --- a/src/Money/MoneyManager.php +++ b/src/Money/MoneyManager.php @@ -6,6 +6,7 @@ use Money\Currency; use Money\Money; +use Tbbc\MoneyBundle\MoneyException; /** * @author levan @@ -14,6 +15,9 @@ class MoneyManager implements MoneyManagerInterface { public function __construct(protected string $referenceCurrencyCode, protected int $decimals = 2) { + if ('' === $referenceCurrencyCode) { + throw new MoneyException('reference currency can not be an empty string'); + } } /** @@ -21,9 +25,14 @@ public function __construct(protected string $referenceCurrencyCode, protected i */ public function createMoneyFromFloat(float $floatAmount, ?string $currencyCode = null): Money { - if (is_null($currencyCode)) { + if (null === $currencyCode) { $currencyCode = $this->referenceCurrencyCode; } + + if ('' === $currencyCode) { + throw new MoneyException('currency can not be an empty string'); + } + $currency = new Currency($currencyCode); $amountAsInt = $floatAmount * 10 ** $this->decimals; $amountAsInt = round($amountAsInt); diff --git a/src/Pair/PairManager.php b/src/Pair/PairManager.php index ce4fe89a..c2357b99 100644 --- a/src/Pair/PairManager.php +++ b/src/Pair/PairManager.php @@ -26,6 +26,7 @@ class PairManager implements PairManagerInterface, Exchange public function __construct( protected StorageInterface $storage, + /** @var string[] */ protected array $currencyCodeList, protected string $referenceCurrencyCode, protected EventDispatcherInterface $dispatcher @@ -38,6 +39,10 @@ public function __construct( */ public function convert(Money $amount, string $currencyCode): Money { + if ('' === $currencyCode) { + throw new MoneyException('currency can not be an empty string'); + } + $converter = new Converter($this->currencies, $this); return $converter->convert($amount, new Currency($currencyCode)); @@ -58,6 +63,10 @@ public function quote(Currency $baseCurrency, Currency $counterCurrency): Curren */ public function saveRatio(string $currencyCode, float $ratio): void { + if ('' === $currencyCode) { + throw new MoneyException('currency can not be an empty string'); + } + $currency = new Currency($currencyCode); if ($ratio <= 0) { @@ -85,6 +94,14 @@ public function saveRatio(string $currencyCode, float $ratio): void */ public function getRelativeRatio(string $referenceCurrencyCode, string $currencyCode): float { + if ('' === $referenceCurrencyCode) { + throw new MoneyException('reference currency can not be an empty string'); + } + + if ('' === $currencyCode) { + throw new MoneyException('currency can not be an empty string'); + } + $currency = new Currency($currencyCode); $referenceCurrency = new Currency($referenceCurrencyCode); if ($currencyCode === $referenceCurrencyCode) { diff --git a/src/Pair/PairManagerInterface.php b/src/Pair/PairManagerInterface.php index f360f8b6..ee6fdd1e 100644 --- a/src/Pair/PairManagerInterface.php +++ b/src/Pair/PairManagerInterface.php @@ -49,7 +49,7 @@ public function getReferenceCurrencyCode(): string; * return ratio list for currencies in comparison to reference currency * array of type array("EUR" => 1, "USD" => 1.25);. * - * @return array + * @return array */ public function getRatioList(): array; diff --git a/src/Pair/RatioProvider/ECBRatioProvider.php b/src/Pair/RatioProvider/ECBRatioProvider.php index c901cba2..8338985b 100644 --- a/src/Pair/RatioProvider/ECBRatioProvider.php +++ b/src/Pair/RatioProvider/ECBRatioProvider.php @@ -51,7 +51,7 @@ public function fetchRatio(string $referenceCurrencyCode, string $currencyCode): } if ('' === $currencyCode) { - throw new MoneyException(sprintf('The currency code "%s" does not exist', $currencyCode)); + throw new MoneyException('The currency code is an empty string'); } try { @@ -60,7 +60,8 @@ public function fetchRatio(string $referenceCurrencyCode, string $currencyCode): throw new MoneyException(sprintf('The currency code "%s" does not exists', $currencyCode)); } - if (!$xml = $this->getXML()) { + $xml = $this->getXML(); + if (null === $xml || '' === $xml) { throw new MoneyException('Could not fetch XML from ECB'); } diff --git a/src/Pair/RatioProvider/ExchangerAdapterRatioProvider.php b/src/Pair/RatioProvider/ExchangerAdapterRatioProvider.php index 4260ed93..a7cf0710 100644 --- a/src/Pair/RatioProvider/ExchangerAdapterRatioProvider.php +++ b/src/Pair/RatioProvider/ExchangerAdapterRatioProvider.php @@ -52,6 +52,10 @@ private function getCurrencyPair(string $referenceCurrencyCode, string $currency private function ensureValidCurrency(string $currencyCode): void { + if ('' === $currencyCode) { + throw new MoneyException('The currency code is an empty string'); + } + try { new Currency($currencyCode); } catch (UnknownCurrencyException|InvalidArgumentException) { diff --git a/src/Pair/Storage/CsvStorage.php b/src/Pair/Storage/CsvStorage.php index 2e9f94a6..7aa3cca8 100644 --- a/src/Pair/Storage/CsvStorage.php +++ b/src/Pair/Storage/CsvStorage.php @@ -17,6 +17,7 @@ */ class CsvStorage implements StorageInterface { + /** @psalm-var array */ protected array $ratioList = []; public function __construct(protected string $ratioFileName, protected string $referenceCurrencyCode) @@ -52,6 +53,9 @@ public function loadRatioList(bool $force = false): array [$currencyCode, $ratio] = $data; // validate that currency exist in currency code list + if (null === $currencyCode || '' === $currencyCode) { + throw new MoneyException('error in ratioFileName '.$this->ratioFileName.' on line '.$row.', currency is an empty string or is null'); + } // @codeCoverageIgnoreStart try { // hack to throw an exception if currency doesn't exist diff --git a/src/Pair/Storage/DoctrineStorage.php b/src/Pair/Storage/DoctrineStorage.php index b046b44e..3b88cb88 100644 --- a/src/Pair/Storage/DoctrineStorage.php +++ b/src/Pair/Storage/DoctrineStorage.php @@ -15,12 +15,16 @@ */ class DoctrineStorage implements StorageInterface { + /** @psalm-var array */ protected array $ratioList = []; public function __construct(protected EntityManagerInterface $entityManager, protected string $referenceCurrencyCode) { } + /** + * {@inheritdoc} + */ public function loadRatioList(bool $force = false): array { if ((false === $force) && (count($this->ratioList) > 0)) { @@ -52,7 +56,7 @@ public function loadRatioList(bool $force = false): array } /** - * @psalm-param array $ratioList + * {@inheritdoc} */ public function saveRatioList(array $ratioList): void { @@ -62,14 +66,18 @@ public function saveRatioList(array $ratioList): void // index them in an associative array $existingStorageRatios = []; foreach ($doctrineStorageRatios as $doctrineStorageRatio) { - $existingStorageRatios[$doctrineStorageRatio->getCurrencyCode()] = $doctrineStorageRatio; + if (null !== ($code = $doctrineStorageRatio->getCurrencyCode())) { + $existingStorageRatios[$code] = $doctrineStorageRatio; + } } foreach ($ratioList as $currencyCode => $ratio) { // load from existing, or create a new $existingStorageRatio = $existingStorageRatios[$currencyCode] ?? new DoctrineStorageRatio($currencyCode, $ratio); - $existingStorageRatio->setRatio($ratio); - $this->entityManager->persist($existingStorageRatio); + if (null !== $ratio) { + $existingStorageRatio->setRatio($ratio); + $this->entityManager->persist($existingStorageRatio); + } // remove from the array, as we do not want to remove this one unset($existingStorageRatios[$currencyCode]); diff --git a/src/Pair/Storage/DocumentStorage.php b/src/Pair/Storage/DocumentStorage.php index 44c2aecc..b74077b5 100644 --- a/src/Pair/Storage/DocumentStorage.php +++ b/src/Pair/Storage/DocumentStorage.php @@ -15,12 +15,16 @@ */ class DocumentStorage implements StorageInterface { + /** @psalm-var array */ protected array $ratioList = []; public function __construct(protected DocumentManager $documentManager, protected string $referenceCurrencyCode) { } + /** + * {@inheritdoc} + */ public function loadRatioList(bool $force = false): array { if ((false === $force) && (count($this->ratioList) > 0)) { @@ -52,7 +56,7 @@ public function loadRatioList(bool $force = false): array } /** - * @psalm-param array $ratioList + * {@inheritdoc} */ public function saveRatioList(array $ratioList): void { @@ -61,14 +65,18 @@ public function saveRatioList(array $ratioList): void // index them in an associative array $existingStorageRatios = []; foreach ($documentStorageRatios as $documentStorageRatio) { - $existingStorageRatios[$documentStorageRatio->getCurrencyCode()] = $documentStorageRatio; + if (null !== ($code = $documentStorageRatio->getCurrencyCode())) { + $existingStorageRatios[$code] = $documentStorageRatio; + } } foreach ($ratioList as $currencyCode => $ratio) { // load from existing, or create a new $existingStorageRatio = $existingStorageRatios[$currencyCode] ?? new DocumentStorageRatio($currencyCode, $ratio); - $existingStorageRatio->setRatio($ratio); - $this->documentManager->persist($existingStorageRatio); + if (null !== $ratio) { + $existingStorageRatio->setRatio($ratio); + $this->documentManager->persist($existingStorageRatio); + } // remove from the array, as we do not want to remove this one unset($existingStorageRatios[$currencyCode]); diff --git a/src/TbbcMoneyBundle.php b/src/TbbcMoneyBundle.php index 65868e4f..a6e57ccb 100644 --- a/src/TbbcMoneyBundle.php +++ b/src/TbbcMoneyBundle.php @@ -10,6 +10,9 @@ use Tbbc\MoneyBundle\DependencyInjection\Compiler\RatioProviderCompilerPass; use Tbbc\MoneyBundle\DependencyInjection\Compiler\StorageCompilerPass; +/** + * @psalm-suppress MissingConstructor + */ class TbbcMoneyBundle extends Bundle { public function build(ContainerBuilder $container): void diff --git a/src/Type/MoneyType.php b/src/Type/MoneyType.php index 4448b4e4..273b477d 100644 --- a/src/Type/MoneyType.php +++ b/src/Type/MoneyType.php @@ -34,13 +34,19 @@ public function requiresSQLCommentHint(AbstractPlatform $platform): bool public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Money { - if (is_null($value)) { + if (null === $value) { return null; } - [$currency, $amount] = explode(' ', (string) $value, 2); + $money = explode(' ', (string) $value, 2); - return new Money($amount, new Currency($currency)); + if (count($money) !== 2 || '' === $money[0] || '' === $money[1]) { + return null; + } + + [$currency, $amount] = $money; + + return new Money((int) $amount, new Currency($currency)); } public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string