Skip to content

Commit

Permalink
phpstan and float formatting in utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
Zrnik committed Mar 12, 2021
1 parent aa91846 commit 3b60f80
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 57 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,8 @@ jobs:
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest

- name: Run PHPStan
run: composer run-script phpstan

- name: Run PHPUnit
run: composer run-script phpunit
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
"moneyphp/money": "^v3.3"
},
"require-dev": {
"phpunit/phpunit": "^9.4"
"phpunit/phpunit": "^9.4",
"phpstan/phpstan": "^0.12"
},
"scripts": {
"phpunit": "phpunit"
"phpunit": "phpunit",
"phpstan": "phpstan analyse --memory-limit 1G"
}
}
5 changes: 5 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
parameters:
level: max
paths:
- src
- tests
34 changes: 23 additions & 11 deletions src/CnbExchange.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ public static function currencyRatioBetween(int $When, Currency $baseCurrency, C

//Do our currencies exist in CNB results?
if(!isset($exchangeRates[$baseCurrency->getCode()]))
if (!isset($exchangeRates[$baseCurrency->getCode()]))
throw new UnresolvableCurrencyPairException(
"Currency '".$baseCurrency->getCode()."' is not defined in CNB exchange rates file!"
"Currency '" . $baseCurrency->getCode() . "' is not defined in CNB exchange rates file!"
);

if(!isset($exchangeRates[$counterCurrency->getCode()]))
if (!isset($exchangeRates[$counterCurrency->getCode()]))
throw new UnresolvableCurrencyPairException(
"Currency '".$counterCurrency->getCode()."' is not defined in CNB exchange rates file!"
"Currency '" . $counterCurrency->getCode() . "' is not defined in CNB exchange rates file!"
);

// I'm afraid we need to use...MATH
Expand All @@ -97,9 +97,9 @@ public static function currencyRatioBetween(int $When, Currency $baseCurrency, C

/**
* @param int $When
* @return false|string
* @return string
*/
private static function getCnbDateKey(int $When)
private static function getCnbDateKey(int $When): string
{
// CNB exchange rates are released every working day after 14:30
// (GMT +2)
Expand All @@ -114,11 +114,14 @@ private static function getCnbDateKey(int $When)

}

/**
* @var array<string,array<string, array<int,float>>>
*/
private static array $ratiosMemoryCache = [];

/**
* @param int $When
* @return array
* @return array<string, array<int,float>>
* @throws Exception
*/
private static function getExchangeRates(int $When): array
Expand All @@ -137,14 +140,22 @@ private static function getExchangeRates(int $When): array

// $fileCacheDirectory ends with slash already.
// "spa" => serialized php array :)
$keyFile = $fileCacheDirectory . $cnbDateKey.".spa";
$keyFile = $fileCacheDirectory . $cnbDateKey . ".spa";

if (file_exists($keyFile)) {
// Oh hey! We have them in the FileCache.
// Once set, the ratios are not changing, so
// we don't need any invalidation mechanism!

$decoded = unserialize(file_get_contents($keyFile));
$content = @file_get_contents($keyFile);

if ($content === false)
throw new Exception("Unable to read cache file!");

$decoded = @unserialize($content);

if ($decoded === false)
throw new Exception("Corrupted cache file!");

// Save it to memory, so we dont need to
// reach for file again for this case
Expand Down Expand Up @@ -174,7 +185,7 @@ private static function getExchangeRates(int $When): array

/**
* @param string $key
* @return array
* @return array<string, array<int,float>>
* @throws Exception
*/
static function loadAndParse(string $key): array
Expand All @@ -194,7 +205,7 @@ static function loadAndParse(string $key): array
curl_setopt($curlHandler, CURLOPT_URL, $url);
$CnbResult = curl_exec($curlHandler);

if ($CnbResult === false)
if (is_bool($CnbResult))
throw new Exception("'Curl' failed with error #" . curl_errno($curlHandler) . " '" . curl_error($curlHandler) . "'");

curl_close($curlHandler);
Expand Down Expand Up @@ -222,6 +233,7 @@ static function loadAndParse(string $key): array
$Price = round(floatval(str_replace(",", ".", $Parts[4])), 4);
$Ratios[$Short] = [$Amount, $Price];
}

return $Ratios;
}
}
130 changes: 90 additions & 40 deletions src/Utilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,65 +12,114 @@

class Utilities
{

const SupportedCurrencies = [
"CZK" => "cs_CZ",
"AUD" => "en_AU",
"BRL" => "pt_BR",
"BGN" => "bg_BG",
"CNY" => "bo_CN",
"DKK" => "da_DK",
"EUR" => "de_DE",
"PHP" => "en_PH",
"HKD" => "en_HK",
"HRK" => "hr_HR",
"INR" => "ar_IN",
"IDR" => "id_ID",
"ISK" => "is_IS",
"ILS" => "en_IL",
"JPY" => "ja_JP",
"ZAR" => "af_ZA",
"CAD" => "en_CA",
"KRW" => "ko_KR",
"HUF" => "hu_HU",
"MYR" => "ms_MY",
"MXN" => "es_MX",
"NOK" => "nb_NO",
"NZD" => "en_NZ",
"PLN" => "pl_PL",
"RON" => "ro_RO",
"RUB" => "ru_RU",
"SGD" => "zh_SG",
"SEK" => "sv_SE",
"CHF" => "fr_CH",
"THB" => "th_TH",
"TRY" => "tr_TR",
"USD" => "en_US",
"GBP" => "en_GB",
];


/**
* @param Money $money
* @return string
*/
public static function format(Money $money)
{
$Formats = [
"CZK" => "cs_CZ",
"AUD" => "en_AU",
"BRL" => "pt_BR",
"BGN" => "bg_BG",
"CNY" => "bo_CN",
"DKK" => "da_DK",
"EUR" => "de_DE",
"PHP" => "en_PH",
"HKD" => "en_HK",
"HRK" => "hr_HR",
"INR" => "ar_IN",
"IDR" => "id_ID",
"ISK" => "is_IS",
"ILS" => "en_IL",
"JPY" => "ja_JP",
"ZAR" => "af_ZA",
"CAD" => "en_CA",
"KRW" => "ko_KR",
"HUF" => "hu_HU",
"MYR" => "ms_MY",
"MXN" => "es_MX",
"NOK" => "nb_NO",
"NZD" => "en_NZ",
"PLN" => "pl_PL",
"RON" => "ro_RO",
"RUB" => "ru_RU",
"SGD" => "zh_SG",
"SEK" => "sv_SE",
"CHF" => "fr_CH",
"THB" => "th_TH",
"TRY" => "tr_TR",
"USD" => "en_US",
"GBP" => "en_GB",
];

$currencies = new ISOCurrencies();

if (!$currencies->contains($money->getCurrency()))
throw new LogicException(
"Currency '" . $money->getCurrency()->getCode() . "' is invalid!"
);

if (!isset($Formats[$money->getCurrency()->getCode()]))
if (!isset(self::SupportedCurrencies[$money->getCurrency()->getCode()]))
throw new LogicException(
"Currency '" . $money->getCurrency()->getCode() . "' not supported!"
);

$numberFormatter = new NumberFormatter($Formats[$money->getCurrency()->getCode()], NumberFormatter::CURRENCY);
$numberFormatter = new NumberFormatter(self::SupportedCurrencies[$money->getCurrency()->getCode()], NumberFormatter::CURRENCY);
$moneyFormatter = new IntlMoneyFormatter($numberFormatter, $currencies);
return $moneyFormatter->format($money);
}

public static function formatFloat(
float $floatAmount, Currency $currency
): string
{
// This will give us: 1.222,30 or 1,222.30 or 1 222.30 or 1 222,30 or whatever :D
$correctFormat = self::format(new Money(122230, $currency));

[$firstPart, $secondPart] = explode("222", $correctFormat);

[$trash, $thousandsSeparator] = explode("1", $firstPart);
unset($trash);

[$decimalSeparator, $trash] = explode("30", $secondPart);
unset($trash);

$integerPart = floor($floatAmount);
$decimalPart = $floatAmount - $integerPart;

$decimalLength = strlen(strval($decimalPart)) - 2; // -2 = "0." in double representation

$formattedExample = number_format(
1222.3, 2, $decimalSeparator, $thousandsSeparator
);
$formattedNumber = number_format(
$floatAmount, $decimalLength, $decimalSeparator, $thousandsSeparator
);


$result = str_replace($formattedExample, $formattedNumber, $correctFormat);

/*
var_dump([
"original" => $floatAmount,
"integer_part" => $integerPart,
"decimal_part" => $decimalPart,
"decimal_len" => $decimalLength,
"formatted_example" => $formattedExample,
"formatted" => $formattedNumber,
"result" => $result,
"thousands_separator" => $thousandsSeparator,
"decimal_separator" => $decimalSeparator
]);
*/

return $result;
}

/**
* @param Money $money
* @param Currency $counterCurrency
Expand All @@ -83,7 +132,7 @@ public static function convert(
?int $When = null
): Money
{
if($When === null)
if ($When === null)
$When = time();

$converter = static::createConverter($When);
Expand All @@ -97,10 +146,11 @@ public static function convert(
*/
public static function createConverter(?int $When = null): Converter
{
if($When === null)
if ($When === null)
$When = time();

return new Converter(new ISOCurrencies(), new CnbExchange($When));
}


}
33 changes: 29 additions & 4 deletions tests/CnbExchangeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
use Money\Currency;
use Money\Money;
use PHPUnit\Framework\TestCase;
use Zrnik\Exchange\CnbExchange;
use Zrnik\Exchange\Utilities;

class CnbExchangeTest extends TestCase
{
public function testExchange()
public function testExchange(): void
{
$When = mktime(
12, 0, 0,
8, 22, 2016
$When = intval(
mktime(
12, 0, 0,
8, 22, 2016
)
);

$USD_345 = new Money(34500, new Currency("USD"));
Expand All @@ -25,4 +28,26 @@ public function testExchange()
$GBP_263_13->getAmount()
);
}

/**
* @throws Exception
*/
public function testPreciseExchangeRatio(): void
{
$ratio = CnbExchange::currencyRatioBetween(
intval(
mktime(
12,0,0,
1,1,2010
)
),
new Currency("EUR"),
new Currency("CZK"),
);

$this->assertSame(
$ratio, 26.465
);

}
}

0 comments on commit 3b60f80

Please sign in to comment.