From 5396752cebbe323df5a74c592cee76cd9f485a6f Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 26 Nov 2024 13:54:08 +0100 Subject: [PATCH 1/2] Update ExchangeLocator method names --- src/Library/Economy/Currency/ExchangeLocator.php | 12 ++++++------ src/Library/Economy/MoneyService.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Library/Economy/Currency/ExchangeLocator.php b/src/Library/Economy/Currency/ExchangeLocator.php index f125071..00a715f 100644 --- a/src/Library/Economy/Currency/ExchangeLocator.php +++ b/src/Library/Economy/Currency/ExchangeLocator.php @@ -7,7 +7,7 @@ use Brick\Money\Exception\CurrencyConversionException; class ExchangeLocator { /** - * @var ExchangeInterface[] + * @var array */ private array $exchanges; @@ -33,9 +33,9 @@ class ExchangeLocator } /** - * @return ExchangeInterface[] + * @return array */ - public function getExchanges(): array + public function getAll(): array { return $this->exchanges; } @@ -45,10 +45,10 @@ class ExchangeLocator * * @throws \Exception When the $name does not match to that of an implemented Exchange */ - public function getExchange(string $name): ExchangeInterface + public function getByName(string $name): ExchangeInterface { if (!\array_key_exists($name, $this->exchanges)) { - throw new \Exception("No such Exchange with the name $name"); + throw new \Exception("No such Exchange with the name '$name'"); } return $this->exchanges[$name]; @@ -60,7 +60,7 @@ class ExchangeLocator * * @throws CurrencyConversionException If the exchange rate is not available */ - public function getExchangeFor(string $source, string $target): ExchangeInterface + public function get(string $source, string $target): ExchangeInterface { foreach ($this->exchanges as $exchange) { try { diff --git a/src/Library/Economy/MoneyService.php b/src/Library/Economy/MoneyService.php index c6649fc..e7078f8 100644 --- a/src/Library/Economy/MoneyService.php +++ b/src/Library/Economy/MoneyService.php @@ -78,7 +78,7 @@ class MoneyService return self::toBrick($money); } - $exchange = $this->exchangeLocator->getExchangeFor($fromCurrency, $toCurrency); + $exchange = $this->exchangeLocator->get($fromCurrency, $toCurrency); return self::toBrick($exchange->convert(self::toBrick($money), $toCurrency)); } From e6be82a3efc448d2958223a69b539df6ed0b8e02 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 26 Nov 2024 13:56:50 +0100 Subject: [PATCH 2/2] Update ExchangeInterface --- .../Currency/EuropeanCentralBankExchange.php | 133 +++++++++--------- .../Economy/Currency/ExchangeInterface.php | 7 +- src/Library/Economy/MoneyService.php | 2 +- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/src/Library/Economy/Currency/EuropeanCentralBankExchange.php b/src/Library/Economy/Currency/EuropeanCentralBankExchange.php index c1e260b..7fc7508 100644 --- a/src/Library/Economy/Currency/EuropeanCentralBankExchange.php +++ b/src/Library/Economy/Currency/EuropeanCentralBankExchange.php @@ -2,13 +2,13 @@ namespace App\Library\Economy\Currency; -use App\Entity\Money as EntityMoney; +use App\Entity\Money; +use App\Library\Economy\MoneyService; use Brick\Math\RoundingMode; use Brick\Money\CurrencyConverter; use Brick\Money\ExchangeRateProvider; use Brick\Money\ExchangeRateProvider\BaseCurrencyProvider; use Brick\Money\ExchangeRateProvider\ConfigurableProvider; -use Brick\Money\MoneyContainer; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; @@ -20,6 +20,9 @@ use Symfony\Contracts\Cache\ItemInterface; */ class EuropeanCentralBankExchange implements ExchangeInterface { + public const NAME = 'european_central_bank'; + public const WEIGHT = 100; + public const ISO_4217 = 'EUR'; /** @@ -53,88 +56,31 @@ class EuropeanCentralBankExchange implements ExchangeInterface $provider->setExchangeRate(self::ISO_4217, $rate['currency'], $rate['rate']); } - $this->date = $this->getDataUpdatedDate($data['@attributes']['time']); + $this->date = $this->parseECBTime($data['@attributes']['time']); $this->provider = new BaseCurrencyProvider($provider, self::ISO_4217); $this->converter = new CurrencyConverter($this->provider); } - private function getDataLatest(): array - { - $data = \simplexml_load_file(self::ECB_DATA); - if (!$data) { - throw new \Exception('Could not retrieve XML data'); - } - - return \json_decode(\json_encode($data), true)['Cube']['Cube']; - } - - private function getDataCached(): array - { - $data = $this->cache->get($this->getName(), function (ItemInterface $item): array { - $item->expiresAfter(self::ECB_DATA_TTL); - - return $this->getDataLatest(); - }); - - if (!$data) { - throw new \Exception('Could not retrieve cached data'); - } - - return $data; - } - - private function getDataUpdatedDate(string $time): \DateTimeInterface - { - return \DateTime::createFromFormat( - \DateTimeInterface::RFC3339, - sprintf('%sT16:00:00+01:00', $time), - new \DateTimeZone(self::ECB_TIMEZONE) - ); - } - - public function getData(): array - { - try { - $cachedData = $this->getDataCached(); - - $currentDate = new \DateTime('now', new \DateTimeZone(self::ECB_TIMEZONE)); - $currentDayAt16 = (new \DateTime('now', new \DateTimeZone(self::ECB_TIMEZONE)))->setTime(16, 0); - $cachedDate = $this->getDataUpdatedDate($cachedData['@attributes']['time']); - - if ( - $currentDate > $currentDayAt16 - && $cachedDate < $currentDayAt16 - ) { - $this->cache->delete($this->getName()); - $cachedData = $this->getDataCached(); - } - - return $cachedData; - } catch (\Exception $e) { - return $this->getDataLatest(); - } - } - public function getName(): string { - return 'european_central_bank'; + return self::NAME; } public function getWeight(): int { - return 100; + return self::WEIGHT; } - public function convert(MoneyContainer $money, string $toCurrency): EntityMoney + public function convert(Money $money, string $toCurrency): Money { $converted = $this->converter->convert( - $money, + MoneyService::toBrick($money), $toCurrency, null, RoundingMode::HALF_EVEN ); - return new EntityMoney( + return new Money( $converted->getMinorAmount()->toInt(), $converted->getCurrency()->getCurrencyCode() ); @@ -151,4 +97,61 @@ class EuropeanCentralBankExchange implements ExchangeInterface return $this->date; } + + public function getData(): array + { + try { + $cachedData = $this->getDataCached(); + $cachedDate = $this->parseECBTime($cachedData['@attributes']['time']); + + $currentDate = new \DateTime('now', new \DateTimeZone(self::ECB_TIMEZONE)); + $currentDayAt16 = (new \DateTime('now', new \DateTimeZone(self::ECB_TIMEZONE)))->setTime(16, 0); + + if ( + $currentDate > $currentDayAt16 + && $cachedDate < $currentDayAt16 + ) { + $this->cache->delete(self::NAME); + $cachedData = $this->getDataCached(); + } + + return $cachedData; + } catch (\Exception $e) { + return $this->getDataLatest(); + } + } + + private function parseECBTime(string $time): \DateTimeInterface + { + return \DateTime::createFromFormat( + \DateTimeInterface::RFC3339, + \sprintf('%sT16:00:00+01:00', $time), + new \DateTimeZone(self::ECB_TIMEZONE) + ); + } + + private function getDataLatest(): array + { + $data = \simplexml_load_file(self::ECB_DATA); + if (!$data) { + throw new \Exception('Could not retrieve XML data'); + } + + return \json_decode(\json_encode($data), true)['Cube']['Cube']; + } + + private function getDataCached(): array + { + $data = $this->cache->get(self::NAME, function (ItemInterface $item): array { + $item->expiresAfter(self::ECB_DATA_TTL); + + return $this->getDataLatest(); + }); + + if (!$data) { + throw new \Exception('Could not retrieve cached data'); + } + + return $data; + } } diff --git a/src/Library/Economy/Currency/ExchangeInterface.php b/src/Library/Economy/Currency/ExchangeInterface.php index d2e2f17..a4c2aee 100644 --- a/src/Library/Economy/Currency/ExchangeInterface.php +++ b/src/Library/Economy/Currency/ExchangeInterface.php @@ -4,7 +4,6 @@ namespace App\Library\Economy\Currency; use App\Entity\Money; use Brick\Money\Exception\CurrencyConversionException; -use Brick\Money\MoneyContainer; interface ExchangeInterface { @@ -19,14 +18,14 @@ interface ExchangeInterface public function getWeight(): int; /** - * @param MoneyContainer $money The money to be converted - * @param string $toCurrency The currency to convert to + * @param Money $money The money to be converted + * @param string $toCurrency The currency to convert to * * @return Money The converted Money * * @throws CurrencyConversionException If the exchange rate is not available */ - public function convert(MoneyContainer $money, string $toCurrency): Money; + public function convert(Money $money, string $toCurrency): Money; /** * @param string $fromCurrency The currency to convert from diff --git a/src/Library/Economy/MoneyService.php b/src/Library/Economy/MoneyService.php index e7078f8..3b0a17f 100644 --- a/src/Library/Economy/MoneyService.php +++ b/src/Library/Economy/MoneyService.php @@ -80,6 +80,6 @@ class MoneyService $exchange = $this->exchangeLocator->get($fromCurrency, $toCurrency); - return self::toBrick($exchange->convert(self::toBrick($money), $toCurrency)); + return self::toBrick($exchange->convert($money, $toCurrency)); } }