[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhortuneCurrency extends Phobject { 4 5 private $value; 6 private $currency; 7 8 private function __construct() { 9 // Intentionally private. 10 } 11 12 public static function getDefaultCurrency() { 13 return 'USD'; 14 } 15 16 public static function newEmptyCurrency() { 17 return self::newFromString('0.00 USD'); 18 } 19 20 public static function newFromUserInput(PhabricatorUser $user, $string) { 21 // Eventually, this might select a default currency based on user settings. 22 return self::newFromString($string, self::getDefaultCurrency()); 23 } 24 25 public static function newFromString($string, $default = null) { 26 $matches = null; 27 $ok = preg_match( 28 '/^([-$]*(?:\d+)?(?:[.]\d{0,2})?)(?:\s+([A-Z]+))?$/', 29 trim($string), 30 $matches); 31 32 if (!$ok) { 33 self::throwFormatException($string); 34 } 35 36 $value = $matches[1]; 37 38 if (substr_count($value, '-') > 1) { 39 self::throwFormatException($string); 40 } 41 42 if (substr_count($value, '$') > 1) { 43 self::throwFormatException($string); 44 } 45 46 $value = str_replace('$', '', $value); 47 $value = (float)$value; 48 $value = (int)round(100 * $value); 49 50 $currency = idx($matches, 2, $default); 51 switch ($currency) { 52 case 'USD': 53 break; 54 default: 55 throw new Exception("Unsupported currency '{$currency}'!"); 56 } 57 58 return self::newFromValueAndCurrency($value, $currency); 59 } 60 61 public static function newFromValueAndCurrency($value, $currency) { 62 $obj = new PhortuneCurrency(); 63 64 $obj->value = $value; 65 $obj->currency = $currency; 66 67 return $obj; 68 } 69 70 public static function newFromList(array $list) { 71 assert_instances_of($list, 'PhortuneCurrency'); 72 73 if (!$list) { 74 return PhortuneCurrency::newEmptyCurrency(); 75 } 76 77 $total = null; 78 foreach ($list as $item) { 79 if ($total === null) { 80 $total = $item; 81 } else { 82 $total = $total->add($item); 83 } 84 } 85 86 return $total; 87 } 88 89 public function formatForDisplay() { 90 $bare = $this->formatBareValue(); 91 return '$'.$bare.' '.$this->currency; 92 } 93 94 public function serializeForStorage() { 95 return $this->formatBareValue().' '.$this->currency; 96 } 97 98 public function formatBareValue() { 99 switch ($this->currency) { 100 case 'USD': 101 return sprintf('%.02f', $this->value / 100); 102 default: 103 throw new Exception( 104 pht('Unsupported currency ("%s")!', $this->currency)); 105 } 106 } 107 108 public function getValue() { 109 return $this->value; 110 } 111 112 public function getCurrency() { 113 return $this->currency; 114 } 115 116 public function getValueInUSDCents() { 117 if ($this->currency !== 'USD') { 118 throw new Exception(pht('Unexpected currency!')); 119 } 120 return $this->value; 121 } 122 123 private static function throwFormatException($string) { 124 throw new Exception("Invalid currency format ('{$string}')."); 125 } 126 127 private function throwUnlikeCurrenciesException(PhortuneCurrency $other) { 128 throw new Exception( 129 pht( 130 'Trying to operate on unlike currencies ("%s" and "%s")!', 131 $this->currency, 132 $other->currency)); 133 } 134 135 public function add(PhortuneCurrency $other) { 136 if ($this->currency !== $other->currency) { 137 $this->throwUnlikeCurrenciesException($other); 138 } 139 140 $currency = new PhortuneCurrency(); 141 142 // TODO: This should check for integer overflows, etc. 143 $currency->value = $this->value + $other->value; 144 $currency->currency = $this->currency; 145 146 return $currency; 147 } 148 149 public function subtract(PhortuneCurrency $other) { 150 if ($this->currency !== $other->currency) { 151 $this->throwUnlikeCurrenciesException($other); 152 } 153 154 $currency = new PhortuneCurrency(); 155 156 // TODO: This should check for integer overflows, etc. 157 $currency->value = $this->value - $other->value; 158 $currency->currency = $this->currency; 159 160 return $currency; 161 } 162 163 public function isEqualTo(PhortuneCurrency $other) { 164 if ($this->currency !== $other->currency) { 165 $this->throwUnlikeCurrenciesException($other); 166 } 167 168 return ($this->value === $other->value); 169 } 170 171 public function negate() { 172 $currency = new PhortuneCurrency(); 173 $currency->value = -$this->value; 174 $currency->currency = $this->currency; 175 return $currency; 176 } 177 178 public function isPositive() { 179 return ($this->value > 0); 180 } 181 182 public function isGreaterThan(PhortuneCurrency $other) { 183 if ($this->currency !== $other->currency) { 184 $this->throwUnlikeCurrenciesException($other); 185 } 186 return $this->value > $other->value; 187 } 188 189 /** 190 * Assert that a currency value lies within a range. 191 * 192 * Throws if the value is not between the minimum and maximum, inclusive. 193 * 194 * In particular, currency values can be negative (to represent a debt or 195 * credit), so checking against zero may be useful to make sure a value 196 * has the expected sign. 197 * 198 * @param string|null Currency string, or null to skip check. 199 * @param string|null Currency string, or null to skip check. 200 * @return this 201 */ 202 public function assertInRange($minimum, $maximum) { 203 if ($minimum !== null && $maximum !== null) { 204 $min = PhortuneCurrency::newFromString($minimum); 205 $max = PhortuneCurrency::newFromString($maximum); 206 if ($min->value > $max->value) { 207 throw new Exception( 208 pht( 209 'Range (%s - %s) is not valid!', 210 $min->formatForDisplay(), 211 $max->formatForDisplay())); 212 } 213 } 214 215 if ($minimum !== null) { 216 $min = PhortuneCurrency::newFromString($minimum); 217 if ($min->value > $this->value) { 218 throw new Exception( 219 pht( 220 'Minimum allowed amount is %s.', 221 $min->formatForDisplay())); 222 } 223 } 224 225 if ($maximum !== null) { 226 $max = PhortuneCurrency::newFromString($maximum); 227 if ($max->value < $this->value) { 228 throw new Exception( 229 pht( 230 'Maximum allowed amount is %s.', 231 $max->formatForDisplay())); 232 } 233 } 234 235 return $this; 236 } 237 238 239 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |