-
-
Notifications
You must be signed in to change notification settings - Fork 824
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
dev/core#2638 Add Helper class for formatting
This brings back to life various formatting attempts such as #20296 but consolidates the 4 main types of formatting to one helper class"
- Loading branch information
1 parent
078cc1f
commit 2e3fcec
Showing
7 changed files
with
372 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
<?php | ||
|
||
namespace Civi\Core; | ||
|
||
use Brick\Money\Money; | ||
use Brick\Money\Context\CustomContext; | ||
use Brick\Math\RoundingMode; | ||
use Civi; | ||
use CRM_Core_Config; | ||
use CRM_Core_I18n; | ||
use CRM_Utils_Constant; | ||
use CRM_Utils_Date; | ||
use CRM_Utils_Money; | ||
use DateTime; | ||
use DateTimeZone; | ||
use NumberFormatter; | ||
|
||
/** | ||
* Class Paths | ||
* @package Civi\Core | ||
* | ||
* This class provides standardised formatting | ||
*/ | ||
class Format { | ||
|
||
/** | ||
* Get formatted money | ||
* | ||
* @param string $amount | ||
* @param string|null $currency | ||
* Currency, defaults to site currency if not provided. | ||
* @param string|null $locale | ||
* @param int|null $precision | ||
* | ||
* @return string | ||
* | ||
* @noinspection PhpDocMissingThrowsInspection | ||
* @noinspection PhpUnhandledExceptionInspection | ||
*/ | ||
public function money(string $amount, ?string $currency = NULL, ?string $locale = NULL, int $precision = NULL): string { | ||
if (!$currency) { | ||
$currency = Civi::settings()->get('defaultCurrency'); | ||
} | ||
if (!isset($locale) || $locale === CRM_Core_I18n::getLocale()) { | ||
// Legacy mode can't copy with locale or precision so we can only go 'the new way' | ||
// if the new params are passed in. | ||
if (!isset($precision) && $this->isUseSeparatorSettings()) { | ||
// @todo - this legacy method is losing it's charm! However, passing to it, for now, | ||
// means only the new functionality goes through the new, better but less tested, method. | ||
return CRM_Utils_Money::format($amount, $currency); | ||
} | ||
$locale = CRM_Core_I18n::getLocale(); | ||
} | ||
|
||
if ($precision === NULL) { | ||
$precision = CRM_Utils_Money::getCurrencyPrecision($currency); | ||
} | ||
$money = Money::of($amount, $currency, new CustomContext($precision), RoundingMode::HALF_UP); | ||
return $money->formatTo($locale); | ||
} | ||
|
||
/** | ||
* Get a formatted number. | ||
* | ||
* @param string|int|float|Money $amount | ||
* Amount in a machine money format. | ||
* @param string|null $locale | ||
* @param array $attributes | ||
* Additional values supported by NumberFormatter | ||
* https://www.php.net/manual/en/class.numberformatter.php | ||
* By default this will set it to round to 8 places and not | ||
* add any padding. | ||
* | ||
* @return string | ||
*/ | ||
public function number($amount, ?string $locale = NULL, array $attributes = [ | ||
NumberFormatter::MIN_FRACTION_DIGITS => 0, | ||
NumberFormatter::MAX_FRACTION_DIGITS => 8, | ||
]): string { | ||
if ($locale && $locale !== CRM_Core_I18n::getLocale()) { | ||
$formatter = new NumberFormatter($locale, NumberFormatter::DECIMAL); | ||
} | ||
else { | ||
$locale = CRM_Core_I18n::getLocale(); | ||
$formatter = new NumberFormatter($locale, NumberFormatter::DECIMAL); | ||
if ($this->isUseSeparatorSettings()) { | ||
$formatter->setAttribute('DECIMAL_SEPARATOR_SYMBOL', Civi::settings()->get('decimalSeparator')); | ||
$formatter->setAttribute('GROUPING_SEPARATOR_SYMBOL', Civi::settings()->get('thousandSeparator')); | ||
} | ||
} | ||
|
||
foreach ($attributes as $attribute => $value) { | ||
$formatter->setAttribute($attribute, $value); | ||
} | ||
return $formatter->format($amount); | ||
} | ||
|
||
public function moneyNumber($amount, $currency) { | ||
$formatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$formatter->setSymbol(\NumberFormatter::CURRENCY_SYMBOL, 'US$'); | ||
$formatter->setSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL, '·'); | ||
$formatter->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, 2); | ||
|
||
$money = Money::of($amount, $currency); | ||
echo $money->formatWith($formatter); // US$5·000.00 | ||
} | ||
|
||
/** | ||
* Should we use the configured thousand & decimal separators. | ||
* | ||
* The goal is to phase this into being FALSE - but for now | ||
* we are looking at how to manage an 'opt in' | ||
*/ | ||
protected function isUseSeparatorSettings(): bool { | ||
return !CRM_Utils_Constant::value('IGNORE_SEPARATOR_CONFIG'); | ||
} | ||
|
||
/** | ||
* Get a formatted date. | ||
* | ||
* @param ?string|\DateTime $date | ||
* @param string|null $dateFormat | ||
* @param string|null $timezone | ||
* | ||
* @return string | ||
* | ||
* @noinspection PhpDocMissingThrowsInspection | ||
* @noinspection PhpUnhandledExceptionInspection | ||
*/ | ||
public function date($date = 'now', ?string $dateFormat = NULL, ?string $timezone = NULL): string { | ||
if ($timezone && $timezone !== CRM_Core_Config::singleton()->userSystem->getTimeZoneString()) { | ||
if (!is_a($date, 'DateTime')) { | ||
$date = new DateTime($date); | ||
} | ||
$date->setTimezone(new DateTimeZone($timezone)); | ||
} | ||
if (is_a($date, 'DateTime')) { | ||
$date = $date->format('Y-m-d H:i:s'); | ||
} | ||
|
||
$configuredFormats = [ | ||
'Datetime', | ||
'Full', | ||
'Partial', | ||
'Time', | ||
'Year', | ||
'FinancialBatch', | ||
'shortdate', | ||
]; | ||
if (in_array($dateFormat, $configuredFormats, TRUE)) { | ||
$dateFormat = Civi::settings()->get('dateformat' . $dateFormat); | ||
} | ||
return CRM_Utils_Date::customFormat($date, $dateFormat); | ||
} | ||
|
||
/** | ||
* Get the date in a machine readable format. | ||
* | ||
* This will be 2012-08-09 13:56:23 | ||
* | ||
* @param string $date | ||
* | ||
* @return string | ||
*/ | ||
public function machineDate(string $date = 'now'): string { | ||
return date(strtotime($date), 'Y-m-d H:i:s'); | ||
} | ||
|
||
/** | ||
* Get Machine version of a number. | ||
* | ||
* This format is ready to use in code / the database. | ||
* | ||
* It looks like 12000.456 - note the lack of thousand separators | ||
* and the decimal point. | ||
* | ||
* The rounding defaults to 9 - like our database. | ||
* | ||
* | ||
* @param string $amount | ||
* @param int|null $precision | ||
* | ||
* @return string | ||
*/ | ||
public function machineNumber(string $amount, int $precision = 9): string { | ||
$formatter = new NumberFormatter('en_US', NumberFormatter::DECIMAL); | ||
$formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $precision); | ||
return $formatter->format($amount); | ||
} | ||
|
||
/** | ||
* Get Machine version of a number with rounding according to the currency. | ||
* | ||
* This format is ready to use in code / the database. | ||
* | ||
* It looks like 12000.45 - note the lack of thousand separators | ||
* and the decimal point and rounding to 2 decimal places per the currency. | ||
* | ||
* | ||
* @param string $amount | ||
* @param ?string $currency | ||
* | ||
* @return string | ||
*/ | ||
public function machineMoney(string $amount, ?string $currency = NULL): string { | ||
if (!$currency) { | ||
$currency = Civi::settings()->get('defaultCurrency'); | ||
} | ||
return $this->machineNumber($amount, CRM_Utils_Money::getCurrencyPrecision($currency)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.