diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index 356d1989a6..2d04172600 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -49,20 +49,21 @@ if ( ! function_exists('number_to_size')) */ function number_to_size($num, int $precision = 1, string $locale = null) { - // Strip any formatting - $num = 0 + str_replace(',', '', $num); - - // Can't work with non-numbers... - if ( ! is_numeric($num)) + // Strip any formatting & ensure numeric input + try + { + $num = 0 + str_replace(',', '', $num); + } + catch (\ErrorException $ee) { return false; } // ignore sub part $genralLocale = $locale; - if( ! empty($locale) && ( $underscorePos = strpos( $locale, '_' ))) + if ( ! empty($locale) && ( $underscorePos = strpos($locale, '_'))) { - $genralLocale = substr( $locale, 0, $underscorePos ); + $genralLocale = substr($locale, 0, $underscorePos); } if ($num >= 1000000000000) @@ -119,22 +120,24 @@ if ( ! function_exists('number_to_amount')) */ function number_to_amount($num, int $precision = 0, string $locale = null) { - // Strip any formatting - $num = 0 + str_replace(',', '', $num); - - // Can't work with non-numbers... - if ( ! is_numeric($num)) + // Strip any formatting & ensure numeric input + try + { + $num = 0 + str_replace(',', '', $num); + } + catch (\ErrorException $ee) { return false; } + $suffix = ''; // ignore sub part $genralLocale = $locale; - if( ! empty($locale) && ( $underscorePos = strpos( $locale, '_' ))) + if ( ! empty($locale) && ( $underscorePos = strpos($locale, '_'))) { - $genralLocale = substr( $locale, 0, $underscorePos ); + $genralLocale = substr($locale, 0, $underscorePos); } if ($num > 1000000000000000) @@ -172,6 +175,7 @@ if ( ! function_exists('number_to_amount')) if ( ! function_exists('number_to_currency')) { + /** * @param float $num * @param string $currency @@ -182,8 +186,8 @@ if ( ! function_exists('number_to_currency')) function number_to_currency($num, string $currency, string $locale = null) { return format_number($num, 1, $locale, [ - 'type' => NumberFormatter::CURRENCY, - 'currency' => $currency + 'type' => NumberFormatter::CURRENCY, + 'currency' => $currency ]); } @@ -258,49 +262,48 @@ if ( ! function_exists('format_number')) if ( ! function_exists('number_to_roman')) { + /** - * Convert a number to a roman numeral. - * - * @param int $num it will convert to int - * - * @return string - */ + * Convert a number to a roman numeral. + * + * @param int $num it will convert to int + * + * @return string + */ function number_to_roman($num) { $num = (int) $num; if ($num < 1 || $num > 3999) { - return; + return; } $_number_to_roman = function($num, $th) use ( &$_number_to_roman ) { $return = ''; $key1 = NULL; $key2 = NULL; - switch ($th) - { + switch ($th) { case 1: - $key1 = 'I'; - $key2 = 'V'; + $key1 = 'I'; + $key2 = 'V'; $key_f = 'X'; break; case 2: - $key1 = 'X'; - $key2 = 'L'; + $key1 = 'X'; + $key2 = 'L'; $key_f = 'C'; break; case 3: - $key1 = 'C'; - $key2 = 'D'; + $key1 = 'C'; + $key2 = 'D'; $key_f = 'M'; break; case 4: - $key1 = 'M'; + $key1 = 'M'; break; } $n = $num % 10; - switch ($n) - { + switch ($n) { case 1: case 2: case 3: @@ -321,8 +324,7 @@ if ( ! function_exists('number_to_roman')) $return = $key1 . $key_f; break; } - switch ($num) - { + switch ($num) { case 10: $return = $key_f; break; @@ -335,4 +337,5 @@ if ( ! function_exists('number_to_roman')) }; return $_number_to_roman($num, 1); } + } diff --git a/tests/system/Helpers/NumberHelperTest.php b/tests/system/Helpers/NumberHelperTest.php index 36a4b9da20..4c5b437a4d 100755 --- a/tests/system/Helpers/NumberHelperTest.php +++ b/tests/system/Helpers/NumberHelperTest.php @@ -2,98 +2,123 @@ class numberHelperTest extends \CIUnitTestCase { + public function setUp() { parent::setUp(); helper('number'); - } + } - public function test_roman_number() - { - $this->assertEquals('XCVI', number_to_roman(96)); - $this->assertEquals('MMDCCCXCV', number_to_roman(2895)); - $this->assertEquals('CCCXXIX', number_to_roman(329)); - } + public function test_roman_number() + { + $this->assertEquals('XCVI', number_to_roman(96)); + $this->assertEquals('MMDCCCXCV', number_to_roman(2895)); + $this->assertEquals('CCCXXIX', number_to_roman(329)); + $this->assertEquals('IV', number_to_roman(4)); + $this->assertEquals('X', number_to_roman(10)); + } - public function test_format_number() - { - $this->assertEquals('123,456', format_number(123456, 0, 'en_US')); - } + public function testRomanNumberRange() + { + $this->assertEquals(null, number_to_roman(-1)); + $this->assertEquals(null, number_to_roman(0)); + $this->assertEquals(null, number_to_roman(4000)); + } - public function test_format_number_with_precision() - { - $this->assertEquals('123,456.8', format_number(123456.789, 1, 'en_US')); - $this->assertEquals('123,456.79', format_number(123456.789, 2, 'en_US')); - } + public function test_format_number() + { + $this->assertEquals('123,456', format_number(123456, 0, 'en_US')); + } - public function test_number_to_size() - { - $this->assertEquals('456 Bytes', number_to_size(456, 1, 'en_US')); - } + public function test_format_number_with_precision() + { + $this->assertEquals('123,456.8', format_number(123456.789, 1, 'en_US')); + $this->assertEquals('123,456.79', format_number(123456.789, 2, 'en_US')); + } - public function test_kb_format() - { - $this->assertEquals('4.5 KB', number_to_size(4567, 1, 'en_US')); - } + public function testFormattingOptions() + { + $options = [ + 'before' => '<<', + 'after' => '>>', + ]; + $this->assertEquals('<<123,456.79>>', format_number(123456.789, 2, 'en_US', $options)); + } - public function test_kb_format_medium() - { - $this->assertEquals('44.6 KB', number_to_size(45678, 1, 'en_US')); - } + public function test_number_to_size() + { + $this->assertEquals('456 Bytes', number_to_size(456, 1, 'en_US')); + } - public function test_kb_format_large() - { - $this->assertEquals('446.1 KB', number_to_size(456789, 1, 'en_US')); - } + public function test_kb_format() + { + $this->assertEquals('4.5 KB', number_to_size(4567, 1, 'en_US')); + } - public function test_mb_format() - { - $this->assertEquals('3.3 MB', number_to_size(3456789, 1, 'en_US')); - } + public function test_kb_format_medium() + { + $this->assertEquals('44.6 KB', number_to_size(45678, 1, 'en_US')); + } - public function test_gb_format() - { - $this->assertEquals('1.8 GB', number_to_size(1932735283.2, 1, 'en_US')); - } + public function test_kb_format_large() + { + $this->assertEquals('446.1 KB', number_to_size(456789, 1, 'en_US')); + } - public function test_tb_format() - { - $this->assertEquals('112,283.3 TB', number_to_size(123456789123456789, 1, 'en_US')); - } + public function test_mb_format() + { + $this->assertEquals('3.3 MB', number_to_size(3456789, 1, 'en_US')); + } - public function test_thousands() - { - $this->assertEquals('123 thousand', number_to_amount('123,000', 0, 'en_US')); - } + public function test_gb_format() + { + $this->assertEquals('1.8 GB', number_to_size(1932735283.2, 1, 'en_US')); + } - public function test_millions() - { - $this->assertEquals('123.4 million', number_to_amount('123,400,000', 1, 'en_US')); - } + public function test_tb_format() + { + $this->assertEquals('112,283.3 TB', number_to_size(123456789123456789, 1, 'en_US')); + } - public function test_billions() - { - $this->assertEquals('123.46 billion', number_to_amount('123,456,000,000', 2, 'en_US')); - } + public function test_thousands() + { + $this->assertEquals('123 thousand', number_to_amount('123,000', 0, 'en_US')); + } - public function test_trillions() - { - $this->assertEquals('123.457 trillion', number_to_amount('123,456,700,000,000', 3, 'en_US')); - } + public function test_millions() + { + $this->assertEquals('123.4 million', number_to_amount('123,400,000', 1, 'en_US')); + } - public function test_quadrillions() - { - $this->assertEquals('123.5 quadrillion', number_to_amount('123,456,700,000,000,000', 1, 'en_US')); - } + public function test_billions() + { + $this->assertEquals('123.46 billion', number_to_amount('123,456,000,000', 2, 'en_US')); + } - /** - * @group single - */ - public function test_currency_current_locale() - { - $this->assertEquals('$1,234.56', number_to_currency(1234.56, 'USD', 'en_US')); - $this->assertEquals('£1,234.56', number_to_currency(1234.56, 'GBP', 'en_GB')); - } + public function test_trillions() + { + $this->assertEquals('123.457 trillion', number_to_amount('123,456,700,000,000', 3, 'en_US')); + } + + public function test_quadrillions() + { + $this->assertEquals('123.5 quadrillion', number_to_amount('123,456,700,000,000,000', 1, 'en_US')); + } + + /** + * @group single + */ + public function test_currency_current_locale() + { + $this->assertEquals('$1,234.56', number_to_currency(1234.56, 'USD', 'en_US')); + $this->assertEquals('£1,234.56', number_to_currency(1234.56, 'GBP', 'en_GB')); + } + + public function testNumbersThatArent() + { + $this->assertFalse(number_to_size('1232x')); + $this->assertFalse(number_to_amount('1232x')); + } } diff --git a/user_guide_src/source/helpers/number_helper.rst b/user_guide_src/source/helpers/number_helper.rst index 58ab341b39..77842e525e 100644 --- a/user_guide_src/source/helpers/number_helper.rst +++ b/user_guide_src/source/helpers/number_helper.rst @@ -19,6 +19,13 @@ This helper is loaded using the following code:: helper('number'); +When Things Go Wrong +==================== + +If PHP's internationalization and localization logic cannot handle +a value provided, for the given locale and options, then a +``BadFunctionCallException()`` will be thrown. + Available Functions =================== @@ -28,7 +35,7 @@ The following functions are available: :param mixed $num: Number of bytes :param int $precision: Floating point precision - :returns: Formatted data size string + :returns: Formatted data size string, or false if the provided value is not numeric :rtype: string Formats numbers as bytes, based on size, and adds the appropriate @@ -64,7 +71,7 @@ The following functions are available: :param mixed $num: Number to format :param int $precision: Floating point precision :param string $locale: The locale to use for formatting - :returns: A human-readable version of the string + :returns: A human-readable version of the string, or false if the provided value is not numeric :rtype: string Converts a number into a human-readable version, like **123.4 trillion** @@ -109,3 +116,6 @@ The following functions are available: echo number_to_roman(23); // Returns XXIII echo number_to_roman(324); // Returns CCCXXIV echo number_to_roman(2534); // Returns MMDXXXIV + + This function only handles numbers in the range 1 through 3999. + It will return null for any value outside that range . \ No newline at end of file diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index cef75d658a..f681801a2c 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -12,7 +12,9 @@ and :doc:`images `. Getting a File instance ======================= -You create a new File instance by passing in the path to the file in the constructor. By default the file does not need to exist. However, you can pass an additional argument of "true" to check that the file exist and throw ``FileNotFoundException()`` when it does not. +You create a new File instance by passing in the path to the file in the constructor. +By default the file does not need to exist. However, you can pass an additional argument of "true" +to check that the file exist and throw ``FileNotFoundException()`` if it does not. ::