Merge pull request #35 from GoteoFoundation/feat/update-exchanges

[feat] Update exchanges
This commit is contained in:
2024-11-26 13:59:06 +01:00
committed by GitHub
4 changed files with 79 additions and 77 deletions
@@ -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;
}
}
@@ -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
@@ -7,7 +7,7 @@ use Brick\Money\Exception\CurrencyConversionException;
class ExchangeLocator
{
/**
* @var ExchangeInterface[]
* @var array<string, ExchangeInterface>
*/
private array $exchanges;
@@ -33,9 +33,9 @@ class ExchangeLocator
}
/**
* @return ExchangeInterface[]
* @return array<string, ExchangeInterface>
*/
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 {
+2 -2
View File
@@ -78,8 +78,8 @@ 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));
return self::toBrick($exchange->convert($money, $toCurrency));
}
}