NumberHelper.php 8.0 KB

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