NumberHelper.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. /**
  3. * Number Helper.
  4. *
  5. * Methods to make numbers more readable.
  6. *
  7. * PHP 5
  8. *
  9. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  10. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. *
  12. * Licensed under The MIT License
  13. * Redistributions of files must retain the above copyright notice.
  14. *
  15. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  16. * @link http://cakephp.org CakePHP(tm) Project
  17. * @package Cake.View.Helper
  18. * @since CakePHP(tm) v 0.10.0.1076
  19. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  20. */
  21. App::uses('AppHelper', 'View/Helper');
  22. /**
  23. * Number helper library.
  24. *
  25. * Methods to make numbers more readable.
  26. *
  27. * @package Cake.View.Helper
  28. * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html
  29. */
  30. class NumberHelper extends AppHelper {
  31. /**
  32. * Currencies supported by the helper. You can add additional currency formats
  33. * with NumberHelper::addFormat
  34. *
  35. * @var array
  36. */
  37. protected $_currencies = array(
  38. 'USD' => array(
  39. 'wholeSymbol' => '$', 'wholePosition' => 'before', 'fractionSymbol' => 'c', 'fractionPosition' => 'after',
  40. 'zero' => 0, 'places' => 2, 'thousands' => ',', 'decimals' => '.', 'negative' => '()', 'escape' => true
  41. ),
  42. 'GBP' => array(
  43. 'wholeSymbol'=>'&#163;', 'wholePosition' => 'before', 'fractionSymbol' => 'p', 'fractionPosition' => 'after',
  44. 'zero' => 0, 'places' => 2, 'thousands' => ',', 'decimals' => '.', 'negative' => '()','escape' => false
  45. ),
  46. 'EUR' => array(
  47. 'wholeSymbol'=>'&#8364;', 'wholePosition' => 'before', 'fractionSymbol' => false, 'fractionPosition' => 'after',
  48. 'zero' => 0, 'places' => 2, 'thousands' => '.', 'decimals' => ',', 'negative' => '()', 'escape' => false
  49. )
  50. );
  51. /**
  52. * Default options for currency formats
  53. *
  54. * @var array
  55. */
  56. protected $_currencyDefaults = array(
  57. 'wholeSymbol'=>'', 'wholePosition' => 'before', 'fractionSymbol' => '', 'fractionPosition' => 'after',
  58. 'zero' => '0', 'places' => 2, 'thousands' => ',', 'decimals' => '.','negative' => '()', 'escape' => true
  59. );
  60. /**
  61. * Formats a number with a level of precision.
  62. *
  63. * @param float $number A floating point number.
  64. * @param integer $precision The precision of the returned number.
  65. * @return float Formatted float.
  66. * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::precision
  67. */
  68. public function precision($number, $precision = 3) {
  69. return sprintf("%01.{$precision}f", $number);
  70. }
  71. /**
  72. * Returns a formatted-for-humans file size.
  73. *
  74. * @param integer $size Size in bytes
  75. * @return string Human readable size
  76. * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::toReadableSize
  77. */
  78. public function toReadableSize($size) {
  79. switch (true) {
  80. case $size < 1024:
  81. return __dn('cake', '%d Byte', '%d Bytes', $size, $size);
  82. case round($size / 1024) < 1024:
  83. return __('%d KB', $this->precision($size / 1024, 0));
  84. case round($size / 1024 / 1024, 2) < 1024:
  85. return __('%.2f MB', $this->precision($size / 1024 / 1024, 2));
  86. case round($size / 1024 / 1024 / 1024, 2) < 1024:
  87. return __('%.2f GB', $this->precision($size / 1024 / 1024 / 1024, 2));
  88. default:
  89. return __('%.2f TB', $this->precision($size / 1024 / 1024 / 1024 / 1024, 2));
  90. }
  91. }
  92. /**
  93. * Formats a number into a percentage string.
  94. *
  95. * @param float $number A floating point number
  96. * @param integer $precision The precision of the returned number
  97. * @return string Percentage string
  98. * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::toPercentage
  99. */
  100. public function toPercentage($number, $precision = 2) {
  101. return $this->precision($number, $precision) . '%';
  102. }
  103. /**
  104. * Formats a number into a currency format.
  105. *
  106. * @param float $number A floating point number
  107. * @param integer $options if int then places, if string then before, if (,.-) then use it
  108. * or array with places and before keys
  109. * @return string formatted number
  110. * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::format
  111. */
  112. public function format($number, $options = false) {
  113. $places = 0;
  114. if (is_int($options)) {
  115. $places = $options;
  116. }
  117. $separators = array(',', '.', '-', ':');
  118. $before = $after = null;
  119. if (is_string($options) && !in_array($options, $separators)) {
  120. $before = $options;
  121. }
  122. $thousands = ',';
  123. if (!is_array($options) && in_array($options, $separators)) {
  124. $thousands = $options;
  125. }
  126. $decimals = '.';
  127. if (!is_array($options) && in_array($options, $separators)) {
  128. $decimals = $options;
  129. }
  130. $escape = true;
  131. if (is_array($options)) {
  132. $options = array_merge(array('before'=>'$', 'places' => 2, 'thousands' => ',', 'decimals' => '.'), $options);
  133. extract($options);
  134. }
  135. $out = $before . number_format($number, $places, $decimals, $thousands) . $after;
  136. if ($escape) {
  137. return h($out);
  138. }
  139. return $out;
  140. }
  141. /**
  142. * Formats a number into a currency format.
  143. *
  144. * ### Options
  145. *
  146. * - `before` - The currency symbol to place before whole numbers ie. '$'
  147. * - `after` - The currency symbol to place after decimal numbers ie. 'c'. Set to boolean false to
  148. * use no decimal symbol. eg. 0.35 => $0.35.
  149. * - `zero` - The text to use for zero values, can be a string or a number. ie. 0, 'Free!'
  150. * - `places` - Number of decimal places to use. ie. 2
  151. * - `thousands` - Thousands separator ie. ','
  152. * - `decimals` - Decimal separator symbol ie. '.'
  153. * - `negative` - Symbol for negative numbers. If equal to '()', the number will be wrapped with ( and )
  154. * - `escape` - Should the output be htmlentity escaped? Defaults to true
  155. *
  156. * @param float $number
  157. * @param string $currency Shortcut to default options. Valid values are 'USD', 'EUR', 'GBP', otherwise
  158. * set at least 'before' and 'after' options.
  159. * @param array $options
  160. * @return string Number formatted as a currency.
  161. * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::currency
  162. */
  163. public function currency($number, $currency = 'USD', $options = array()) {
  164. $default = $this->_currencyDefaults;
  165. if (isset($this->_currencies[$currency])) {
  166. $default = $this->_currencies[$currency];
  167. } elseif (is_string($currency)) {
  168. $options['before'] = $currency;
  169. }
  170. $options = array_merge($default, $options);
  171. if (isset($options['before']) && $options['before'] !== '') {
  172. $options['wholeSymbol'] = $options['before'];
  173. }
  174. if (isset($options['after']) && !$options['after'] !== '') {
  175. $options['fractionSymbol'] = $options['after'];
  176. }
  177. $result = $options['before'] = $options['after'] = null;
  178. $symbolKey = 'whole';
  179. if ($number == 0 ) {
  180. if ($options['zero'] !== 0 ) {
  181. return $options['zero'];
  182. }
  183. } elseif ($number < 1 && $number > -1 ) {
  184. if ($options['fractionSymbol'] !== false) {
  185. $multiply = intval('1' . str_pad('', $options['places'], '0'));
  186. $number = $number * $multiply;
  187. $options['places'] = null;
  188. $symbolKey = 'fraction';
  189. }
  190. }
  191. $position = $options[$symbolKey.'Position'] != 'after' ? 'before' : 'after';
  192. $options[$position] = $options[$symbolKey.'Symbol'];
  193. $abs = abs($number);
  194. $result = $this->format($abs, $options);
  195. if ($number < 0 ) {
  196. if ($options['negative'] == '()') {
  197. $result = '(' . $result .')';
  198. } else {
  199. $result = $options['negative'] . $result;
  200. }
  201. }
  202. return $result;
  203. }
  204. /**
  205. * Add a currency format to the Number helper. Makes reusing
  206. * currency formats easier.
  207. *
  208. * {{{ $number->addFormat('NOK', array('before' => 'Kr. ')); }}}
  209. *
  210. * You can now use `NOK` as a shortform when formatting currency amounts.
  211. *
  212. * {{{ $number->currency($value, 'NOK'); }}}
  213. *
  214. * Added formats are merged with the following defaults.
  215. *
  216. * {{{
  217. * array(
  218. * 'before' => '$', 'after' => 'c', 'zero' => 0, 'places' => 2, 'thousands' => ',',
  219. * 'decimals' => '.', 'negative' => '()', 'escape' => true
  220. * )
  221. * }}}
  222. *
  223. * @param string $formatName The format name to be used in the future.
  224. * @param array $options The array of options for this format.
  225. * @return void
  226. * @see NumberHelper::currency()
  227. */
  228. public function addFormat($formatName, $options) {
  229. $this->_currencies[$formatName] = $options + $this->_currencyDefaults;
  230. }
  231. }