From 98c117f8710beca4003e5a1ba2ea6d8b926cb034 Mon Sep 17 00:00:00 2001 From: Deeka Wong Date: Sun, 19 Nov 2023 20:41:46 +0800 Subject: [PATCH] Adds Number utility class (#440) Co-authored-by: Deeka Wong <8337659+huangdijia@users.noreply.github.com> --- src/Number.php | 197 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 src/Number.php diff --git a/src/Number.php b/src/Number.php new file mode 100644 index 0000000..ecbb187 --- /dev/null +++ b/src/Number.php @@ -0,0 +1,197 @@ +setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); + } elseif (! is_null($precision)) { + $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); + } + + return $formatter->format($number); + } + + /** + * Spell out the given number in the given locale. + * + * @param ?string $locale + * @return string + */ + public static function spell(int|float $number, ?string $locale = null) + { + static::ensureIntlExtensionIsInstalled(); + + $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::SPELLOUT); + + return $formatter->format($number); + } + + /** + * Convert the given number to ordinal form. + * + * @param ?string $locale + * @return string + */ + public static function ordinal(int|float $number, ?string $locale = null) + { + static::ensureIntlExtensionIsInstalled(); + + $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::ORDINAL); + + return $formatter->format($number); + } + + /** + * Convert the given number to its percentage equivalent. + * + * @param ?string $locale + * @return string|false + */ + public static function percentage(int|float $number, int $precision = 0, ?int $maxPrecision = null, ?string $locale = null) + { + static::ensureIntlExtensionIsInstalled(); + + $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::PERCENT); + + if (! is_null($maxPrecision)) { + $formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); + } else { + $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); + } + + return $formatter->format($number / 100); + } + + /** + * Convert the given number to its currency equivalent. + * + * @param ?string $locale + * @return string|false + */ + public static function currency(int|float $number, string $in = 'USD', ?string $locale = null) + { + static::ensureIntlExtensionIsInstalled(); + + $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::CURRENCY); + + return $formatter->formatCurrency($number, $in); + } + + /** + * Convert the given number to its file size equivalent. + * + * @return string + */ + public static function fileSize(int|float $bytes, int $precision = 0, ?int $maxPrecision = null) + { + $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + + for ($i = 0; ($bytes / 1024) > 0.9 && ($i < count($units) - 1); ++$i) { + $bytes /= 1024; + } + + return sprintf('%s %s', static::format($bytes, $precision, $maxPrecision), $units[$i]); + } + + /** + * Convert the number to its human readable equivalent. + * + * @param int $number + * @return string + */ + public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null) + { + $units = [ + 3 => 'thousand', + 6 => 'million', + 9 => 'billion', + 12 => 'trillion', + 15 => 'quadrillion', + ]; + + switch (true) { + case $number === 0: + return '0'; + case $number < 0: + return sprintf('-%s', static::forHumans(abs($number), $precision, $maxPrecision)); + case $number >= 1e15: + return sprintf('%s quadrillion', static::forHumans($number / 1e15, $precision, $maxPrecision)); + } + + $numberExponent = floor(log10($number)); + $displayExponent = $numberExponent - ($numberExponent % 3); + $number /= pow(10, $displayExponent); + + return trim(sprintf('%s %s', static::format($number, $precision, $maxPrecision), $units[$displayExponent] ?? '')); + } + + /** + * Execute the given callback using the given locale. + * + * @return mixed + */ + public static function withLocale(string $locale, callable $callback) + { + $previousLocale = static::$locale; + + static::useLocale($locale); + + return tap($callback(), fn () => static::useLocale($previousLocale)); + } + + /** + * Set the default locale. + */ + public static function useLocale(string $locale) + { + static::$locale = $locale; + } + + /** + * Ensure the "intl" PHP extension is installed. + */ + protected static function ensureIntlExtensionIsInstalled() + { + if (! extension_loaded('intl')) { + throw new RuntimeException('The "intl" PHP extension is required to use this method.'); + } + } +}