Skip to content

Commit

Permalink
Add money format functions
Browse files Browse the repository at this point in the history
Civi::format()->money();
Civi::format()->number();
Civi::format()->moneyNumber();
Civi::format()->moneyLong();
  • Loading branch information
eileenmcnaughton committed Oct 4, 2021
1 parent 34258da commit b2445a0
Show file tree
Hide file tree
Showing 4 changed files with 408 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Civi.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use Civi\Core\Format;

/**
* Class Civi
*
Expand Down Expand Up @@ -103,6 +105,15 @@ public static function paths() {
return \Civi\Core\Container::getBootService('paths');
}

/**
* Obtain the formatting object.
*
* @return \Civi\Core\Format
*/
public static function format(): Format {
return new Civi\Core\Format();
}

/**
* Fetch a service from the container.
*
Expand Down
5 changes: 5 additions & 0 deletions Civi/Core/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ public function createContainer() {
[]
))->setPublic(TRUE);

$container->setDefinition('format', new Definition(
'\Civi\Core\Format',
[]
))->setPublic(TRUE);

$container->setDefinition('bundle.bootstrap3', new Definition('CRM_Core_Resources_Bundle', ['bootstrap3']))
->setFactory('CRM_Core_Resources_Common::createBootstrap3Bundle')->setPublic(TRUE);

Expand Down
161 changes: 161 additions & 0 deletions Civi/Core/Format.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?php

namespace Civi\Core;

use Brick\Money\Currency;
use Brick\Money\Money;
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_Rule;
use DateTime;
use DateTimeZone;
use NumberFormatter;
use Brick\Money\Context\AutoContext;

/**
* 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
*
* @return string
*
* @noinspection PhpDocMissingThrowsInspection
* @noinspection PhpUnhandledExceptionInspection
*/
public function money(string $amount, ?string $currency = NULL, ?string $locale = NULL): string {
if (!$currency) {
$currency = Civi::settings()->get('defaultCurrency');
}
if (!isset($locale)) {
$locale = CRM_Core_I18n::getLocale();
}
$money = Money::of($amount, $currency, NULL, RoundingMode::HALF_UP);
$formatter = $this->getMoneyFormatter($currency, $locale);
return $money->formatWith($formatter);
}

/**
* 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 {
$formatter = $this->getMoneyFormatter(NULL, $locale, NumberFormatter::DECIMAL, $attributes);
return $formatter->format($amount);
}

/**
* Get a number formatted with rounding expectations derived from the currency.
*
* @param string|float|int $amount
* @param string $currency
* @param $locale
*
* @return string
*
* @noinspection PhpDocMissingThrowsInspection
* @noinspection PhpUnhandledExceptionInspection
*/
public function moneyNumber($amount, string $currency, $locale): string {
$formatter = $this->getMoneyFormatter($currency, $locale, NumberFormatter::DECIMAL);
$money = Money::of($amount, $currency, NULL, RoundingMode::HALF_UP);
return $money->formatWith($formatter);
}


/**
* Get a money value with formatting but not rounding.
*
* @param string|float|int $amount
* @param string|null $currency
* @param string|null $locale
*
* @return string
*
* @noinspection PhpDocMissingThrowsInspection
* @noinspection PhpUnhandledExceptionInspection
*/
public function moneyLong($amount, ?string $currency, ?string $locale): string {
$formatter = $this->getMoneyFormatter($currency, $locale, NumberFormatter::CURRENCY, [
NumberFormatter::MAX_FRACTION_DIGITS => 9,
]);
$money = Money::of($amount, $currency, new AutoContext());
return $money->formatWith($formatter);
}

/**
* 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 the money formatter for when we are using configured thousand separators.
*
* Our intent is to phase out these settings in favour of deriving them from the locale.
*
* @param string|null $currency
* @param string|null $locale
* @param int $style
* @param array $attributes
*
* @return \NumberFormatter
*
* @noinspection PhpDocMissingThrowsInspection
* @noinspection PhpUnhandledExceptionInspection
*/
public function getMoneyFormatter(?string $currency = NULL, ?string $locale = NULL, int $style = NumberFormatter::CURRENCY, array $attributes = []): NumberFormatter {
if (!$currency) {
$currency = Civi::settings()->get('defaultCurrency');
}
$formatter = new NumberFormatter($locale, $style);

if (!isset($attributes[NumberFormatter::MIN_FRACTION_DIGITS])) {
$attributes[NumberFormatter::MIN_FRACTION_DIGITS] = Currency::of($currency)->getDefaultFractionDigits();
}
if (!isset($attributes[NumberFormatter::MAX_FRACTION_DIGITS])) {
$attributes[NumberFormatter::MAX_FRACTION_DIGITS] = Currency::of($currency)->getDefaultFractionDigits();
}

foreach ($attributes as $attribute => $value) {
$formatter->setAttribute($attribute, $value);
}
if ($locale === CRM_Core_I18n::getLocale() && $this->isUseSeparatorSettings()) {
$formatter->setSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL, CRM_Core_Config::singleton()->monetaryThousandSeparator);
$formatter->setSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL, CRM_Core_Config::singleton()->monetaryDecimalPoint);
}
return $formatter;
}

}
Loading

0 comments on commit b2445a0

Please sign in to comment.