<?php
namespace App\Service;
use App\Entity\model\DayPrice;
use App\Entity\Price;
use Swap\Swap;
class CurrencyService {
private Swap $swap;
public function __construct(Swap $swap) {
$this->swap = $swap;
}
/**
* @param Price|DayPrice $p
* @param string $toCurrency
*/
public function updateCurrency($p, string $toCurrency) {
if($p->getCurrency() === $toCurrency) return;
$rate = $this->getRate($p->getCurrency(), $toCurrency);
$p->setCurrency($toCurrency);
$p->setCents(intval($rate * $p->getCents()));
}
public function updateCurrencyInfo($cents, string $fromCurrency, string $toCurrency) {
$rate = $this->getRate($fromCurrency, $toCurrency);
return intval($rate * $cents);
}
/**
* Because of the APIs used, we must use the EUR or USD as a base for conversions
* TODO must be improved (for free usage) as it fetches a list of pair currencies but cache only one (the one asked)
*/
public function getRate(string $from, string $to): float {
$rate = 1;
if($from === $to) {
$rate = 1;
} else if ($from === 'EUR' || $from === 'USD') {
$rate = $this->swap->latest("$from/$to")->getValue();
} else if ($to === 'EUR' || $to === 'USD') {
$rate = 1 / $this->swap->latest("$to/$from")->getValue();
} else { //FROM -> EUR -> TO
$rateToEur = 1 / $this->swap->latest("EUR/$from")->getValue();
$rateFromEur = $this->swap->latest("EUR/$to")->getValue();
$rate = $rateFromEur * $rateToEur;
}
return $rate;
}
/**
* Returns the price to display
* TODO handle before/after ( $pad = $fmt->getAttribute(\NumberFormatter::PAD_AFTER_PREFIX);)
* in Google flight if currency of country use symbol, otherwise if has same symbol that other (eg "$") use currency iso code
*/
public static function nicePrice(int $cents, string $currency, ?string $locale = null): string {
if($cents > 2000) // if higher than 20, remove cents
$cents = ceil($cents/100)*100;
$amount = self::niceCents($cents); //1050 => "10.50" / 1000 => "10"
switch ($currency) {
case 'GBP' : return '£'.$amount;
case 'EUR' : return $amount.'€';
case 'MAD' : return $amount.' dh';
case 'CZK' : return $amount.' Kč';
case 'PLN' : return $amount.' zł';
case 'RUB' : return $amount.' ₽';
case 'UAH' : return $amount.' ₴';
case 'INR' : return '₹'.$amount;
case 'TRY' : return $amount.'₺';
case 'USD' : return '$'.$amount;
case 'BGN' : return 'Лв'.$amount;
case 'VND' : return $amount.'₫';
case 'THB' : return '฿'.$amount;
case 'HUF' : return $amount.'Ft';
default: return $locale ? self::nicePriceExt($cents, $currency, $locale) : $currency.' '.$amount;
}
}
/**
* Generates the amount part
* 550 => 5.50
* 500 => 5
*/
public static function niceCents(int $cents): string {
if($cents % 100 == 0)
return $cents/100;
else
return number_format($cents/100, 2);
}
/**
* Generates the price to display using the ext-intl
* //Intl::getCurrencyBundle()->getCurrencySymbol('INR');
*/
public static function nicePriceExt(int $cents, string $currency, ?string $locale): string {
$amount = $cents/100;
$fmt = new \NumberFormatter( $locale, \NumberFormatter::CURRENCY );
$fmt->setTextAttribute(\NumberFormatter::CURRENCY_CODE, $currency);
if($cents % 100 == 0)
$fmt->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, 0); //do not display cents if ".00"
return $fmt->format($amount);
}
public static function countryCurrency(string $countryCode) : string {
// use swich case as number formatter method could be slow
switch ($countryCode) {
case 'GB': return 'GBP';
case 'US': return 'USD';
case 'FR': return 'EUR';
case 'ES': return 'EUR';
case 'IT': return 'EUR';
}
$fmt = new \NumberFormatter( '_'.$countryCode, \NumberFormatter::CURRENCY );
return $fmt->getTextAttribute(\NumberFormatter::CURRENCY_CODE);
}
public static function countryLang(string $countryCode): string {
return "";
}
}