diff --git a/lib/Cake/Test/Case/Utility/CakeNumberTest.php b/lib/Cake/Test/Case/Utility/CakeNumberTest.php index dc80e66da..1d0acdcf3 100644 --- a/lib/Cake/Test/Case/Utility/CakeNumberTest.php +++ b/lib/Cake/Test/Case/Utility/CakeNumberTest.php @@ -72,6 +72,54 @@ class CakeNumberTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * testMultibyteFormat + * + * @return void + */ + public function testMultibyteFormat() { + $value = '5199100.0006'; + $result = $this->Number->format($value, array( + 'thousands' => ' ', + 'decimals' => '&', + 'places' => 3, + 'escape' => false, + 'before' => '', + )); + $expected = '5 199 100&001'; + $this->assertEqual($expected, $result); + + $value = 1000.45; + $result = $this->Number->format($value, array( + 'thousands' => ',,', + 'decimals' => '.a', + 'escape' => false, + )); + $expected = '$1,,000.a45'; + $this->assertEqual($expected, $result); + + $value = 519919827593784.00; + $this->Number->addFormat('RUR', array( + 'thousands' => 'ø€ƒ‡™', + 'decimals' => '(§.§)', + 'escape' => false, + 'wholeSymbol' => '€', + 'wholePosition' => 'after', + )); + $result = $this->Number->currency($value, 'RUR'); + $expected = '519ø€ƒ‡™919ø€ƒ‡™827ø€ƒ‡™593ø€ƒ‡™784(§.§)00€'; + $this->assertEquals($expected, $result); + + $value = '13371337.1337'; + $result = CakeNumber::format($value, array( + 'thousands' => '- |-| /-\ >< () |2 -', + 'decimals' => '- £€€† -', + 'before' => '' + )); + $expected = '13- |-| /-\ >< () |2 -371- |-| /-\ >< () |2 -337- £€€† -13'; + $this->assertEquals($expected, $result); + } + /** * Test currency method. * diff --git a/lib/Cake/Utility/CakeNumber.php b/lib/Cake/Utility/CakeNumber.php index 46415c946..2829016be 100644 --- a/lib/Cake/Utility/CakeNumber.php +++ b/lib/Cake/Utility/CakeNumber.php @@ -60,6 +60,13 @@ class CakeNumber { 'zero' => '0', 'places' => 2, 'thousands' => ',', 'decimals' => '.','negative' => '()', 'escape' => true, ); +/** + * If native number_format() should be used. If >= PHP5.4 + * + * @var boolean + */ + protected static $_numberFormatSupport = null; + /** * Formats a number with a level of precision. * @@ -142,7 +149,7 @@ class CakeNumber { extract($options); } - $out = $before . number_format($number, $places, $decimals, $thousands) . $after; + $out = $before . self::_number_format($number, $places, $decimals, $thousands) . $after; if ($escape) { return h($out); @@ -150,6 +157,36 @@ class CakeNumber { return $out; } +/** + * Alternative number_format() to accommodate multibyte decimals and thousands < PHP 5.4 + * + * @param float $number + * @param integer $places + * @param string $decimals + * @param string $thousands + * @return string + */ + protected static function _number_format($number, $places = 0, $decimals = '.', $thousands = ',') { + if (!isset(self::$_numberFormatSupport)) { + self::$_numberFormatSupport = version_compare(PHP_VERSION, '5.4.0', '>='); + } + if (self::$_numberFormatSupport) { + return number_format($number, $places, $decimals, $thousands); + } + $number = number_format($number, $places, '.', ''); + $after = ''; + $foundDecimal = strpos($number, '.'); + if ($foundDecimal !== false) { + $after = substr($number, $foundDecimal); + $number = substr($number, 0, $foundDecimal); + } + while (($foundThousand = preg_replace('/(\d+)(\d\d\d)/', '\1 \2', $number)) != $number) { + $number = $foundThousand; + } + $number .= $after; + return strtr($number, array(' ' => $thousands, '.' => $decimals)); + } + /** * Formats a number into a currency format. *