NumberHelper.php 8.1 KB

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