1. sfNumberFormatInfo.class.php
  2. /** * sfNumberFormatInfo class * * Defines how numeric values are formatted and displayed, * depending on the culture. Numeric values are formatted using * standard or custom patterns stored in the properties of a * sfNumberFormatInfo. * * This class contains information, such as currency, decimal * separators, and other numeric symbols. * * To create a sfNumberFormatInfo for a specific culture, * create a sfCultureInfo for that culture and retrieve the * sfCultureInfo->NumberFormat property. Or use * sfNumberFormatInfo::getInstance($culture). * To create a sfNumberFormatInfo for the invariant culture, use the * InvariantInfo::getInvariantInfo(). * * * @author Xiang Wei Zhuo * @version v1.0, last update on Sun Dec 05 14:48:26 EST 2004 * @package symfony * @subpackage i18n */
  3. class sfNumberFormatInfo
  4. {
  5. /**
  6. * ICU number formatting data.
  7. * @var array
  8. */
  9. protected $data = array();
  10. /**
  11. * A list of properties that are accessable/writable.
  12. * @var array
  13. */
  14. protected $properties = array();
  15. /**
  16. * The number pattern.
  17. * @var array
  18. */
  19. protected $pattern = array();
  20. const DECIMAL = 0;
  21. const CURRENCY = 1;
  22. const PERCENTAGE = 2;
  23. const SCIENTIFIC = 3;
  24. /**
  25. * Allows functions that begins with 'set' to be called directly
  26. * as an attribute/property to retrieve the value.
  27. *
  28. * @return mixed
  29. */
  30. function __get($name)
  31. {
  32. $getProperty = 'get'.$name;
  33. if (in_array($getProperty, $this->properties))
  34. {
  35. return $this->$getProperty();
  36. }
  37. else
  38. {
  39. throw new sfException(sprintf('Property %s does not exists.', $name));
  40. }
  41. }
  42. /**
  43. * Allows functions that begins with 'set' to be called directly
  44. * as an attribute/property to set the value.
  45. */
  46. function __set($name, $value)
  47. {
  48. $setProperty = 'set'.$name;
  49. if (in_array($setProperty, $this->properties))
  50. {
  51. $this->$setProperty($value);
  52. }
  53. else
  54. {
  55. throw new sfException(sprintf('Property %s can not be set.', $name));
  56. }
  57. }
  58. /**
  59. * Initializes a new writable instance of the sfNumberFormatInfo class
  60. * that is dependent on the ICU data for number, decimal, and currency
  61. * formatting information. <b>N.B.</b>You should not initialize this
  62. * class directly unless you know what you are doing. Please use use
  63. * sfNumberFormatInfo::getInstance() to create an instance.
  64. *
  65. * @param array $data ICU data for date time formatting.
  66. * @param int $type The sfNumberFormatInfo type
  67. * @see getInstance()
  68. */
  69. function __construct($data = array(), $type = sfNumberFormatInfo::DECIMAL)
  70. {
  71. $this->properties = get_class_methods($this);
  72. if (empty($data))
  73. {
  74. throw new sfException('Please provide the ICU data to initialize.');
  75. }
  76. $this->data = $data;
  77. $this->setPattern($type);
  78. }
  79. /**
  80. * Sets the pattern for a specific number pattern. The validate patterns
  81. * sfNumberFormatInfo::DECIMAL, sfNumberFormatInfo::CURRENCY,
  82. * sfNumberFormatInfo::PERCENTAGE, or sfNumberFormatInfo::SCIENTIFIC
  83. *
  84. * @param int $type pattern type.
  85. */
  86. function setPattern($type = sfNumberFormatInfo::DECIMAL)
  87. {
  88. if (is_int($type))
  89. {
  90. $this->pattern = $this->parsePattern($this->data['NumberPatterns'][$type]);
  91. }
  92. else
  93. {
  94. $this->pattern = $this->parsePattern($type);
  95. }
  96. $this->pattern['negInfty'] = $this->data['NumberElements'][6].$this->data['NumberElements'][9];
  97. $this->pattern['posInfty'] = $this->data['NumberElements'][11].$this->data['NumberElements'][9];
  98. }
  99. function getPattern()
  100. {
  101. return $this->pattern;
  102. }
  103. /**
  104. * Gets the default sfNumberFormatInfo that is culture-independent (invariant).
  105. *
  106. * @return sfNumberFormatInfo default sfNumberFormatInfo.
  107. */
  108. static public function getInvariantInfo($type = sfNumberFormatInfo::DECIMAL)
  109. {
  110. static $invariant;
  111. if (null === $invariant)
  112. {
  113. $culture = sfCultureInfo::getInvariantCulture();
  114. $invariant = $culture->NumberFormat;
  115. $invariant->setPattern($type);
  116. }
  117. return $invariant;
  118. }
  119. /**
  120. * Returns the sfNumberFormatInfo associated with the specified culture.
  121. *
  122. * @param sfCultureInfo $culture the culture that gets the sfNumberFormat property.
  123. * @param int $type the number formatting type, it should be
  124. * sfNumberFormatInfo::DECIMAL, sfNumberFormatInfo::CURRENCY,
  125. * sfNumberFormatInfo::PERCENTAGE, or sfNumberFormatInfo::SCIENTIFIC
  126. * @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
  127. * @see getCurrencyInstance();
  128. * @see getPercentageInstance();
  129. * @see getScientificInstance();
  130. */
  131. public static function getInstance($culture = null, $type = sfNumberFormatInfo::DECIMAL)
  132. {
  133. if ($culture instanceof sfCultureInfo)
  134. {
  135. $formatInfo = $culture->getNumberFormat();
  136. $formatInfo->setPattern($type);
  137. return $formatInfo;
  138. }
  139. else if (is_string($culture))
  140. {
  141. $sfCultureInfo = sfCultureInfo::getInstance($culture);
  142. $formatInfo = $sfCultureInfo->getNumberFormat();
  143. $formatInfo->setPattern($type);
  144. return $formatInfo;
  145. }
  146. else
  147. {
  148. $sfCultureInfo = sfCultureInfo::getInstance();
  149. $formatInfo = $sfCultureInfo->getNumberFormat();
  150. $formatInfo->setPattern($type);
  151. return $formatInfo;
  152. }
  153. }
  154. /**
  155. * Returns the currency format info associated with the specified culture.
  156. *
  157. * @param sfCultureInfo $culture the culture that gets the NumberFormat property.
  158. * @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
  159. */
  160. public static function getCurrencyInstance($culture = null)
  161. {
  162. return self::getInstance($culture, self::CURRENCY);
  163. }
  164. /**
  165. * Returns the percentage format info associated with the specified culture.
  166. *
  167. * @param sfCultureInfo $culture the culture that gets the NumberFormat property.
  168. * @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
  169. */
  170. public static function getPercentageInstance($culture = null)
  171. {
  172. return self::getInstance($culture, self::PERCENTAGE);
  173. }
  174. /**
  175. * Returns the scientific format info associated with the specified culture.
  176. *
  177. * @param sfCultureInfo $culture the culture that gets the NumberFormat property.
  178. * @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
  179. */
  180. public static function getScientificInstance($culture = null)
  181. {
  182. return self::getInstance($culture, self::SCIENTIFIC);
  183. }
  184. /**
  185. * Parses the given pattern and return a list of known properties.
  186. *
  187. * @param string $pattern a number pattern.
  188. * @return array list of pattern properties.
  189. */
  190. protected function parsePattern($pattern)
  191. {
  192. $pattern = explode(';', $pattern);
  193. $negative = null;
  194. if (count($pattern) > 1)
  195. {
  196. $negative = $pattern[1];
  197. }
  198. $pattern = $pattern[0];
  199. $comma = ',';
  200. $dot = '.';
  201. $digit = '0';
  202. $hash = '#';
  203. // find the first group point, and decimal point
  204. $groupPos1 = strrpos($pattern, $comma);
  205. $decimalPos = strrpos($pattern, $dot);
  206. $groupPos2 = false;
  207. $groupSize1 = false;
  208. $groupSize2 = false;
  209. $decimalPoints = is_int($decimalPos) ? -1 : false;
  210. $info['negPref'] = $this->data['NumberElements'][6];
  211. $info['negPost'] = '';
  212. $info['negative'] = $negative;
  213. $info['positive'] = $pattern;
  214. // find the negative prefix and postfix
  215. if ($negative)
  216. {
  217. $prefixPostfix = $this->getPrePostfix($negative);
  218. $info['negPref'] = $prefixPostfix[0];
  219. $info['negPost'] = $prefixPostfix[1];
  220. }
  221. $posfix = $this->getPrePostfix($pattern);
  222. $info['posPref'] = $posfix[0];
  223. $info['posPost'] = $posfix[1];
  224. if (is_int($groupPos1))
  225. {
  226. // get the second group
  227. $groupPos2 = strrpos(substr($pattern, 0, $groupPos1), $comma);
  228. // get the number of decimal digits
  229. if (is_int($decimalPos))
  230. {
  231. $groupSize1 = $decimalPos - $groupPos1 - 1;
  232. }
  233. else
  234. {
  235. // no decimal point, so traverse from the back
  236. // to find the groupsize 1.
  237. for ($i = strlen($pattern) - 1; $i >= 0; $i--)
  238. {
  239. if ($pattern{$i} == $digit || $pattern{$i} == $hash)
  240. {
  241. $groupSize1 = $i - $groupPos1;
  242. break;
  243. }
  244. }
  245. }
  246. // get the second group size
  247. if (is_int($groupPos2))
  248. {
  249. $groupSize2 = $groupPos1 - $groupPos2 - 1;
  250. }
  251. }
  252. if (is_int($decimalPos))
  253. {
  254. for ($i = strlen($pattern) - 1; $i >= 0; $i--)
  255. {
  256. if ($pattern{$i} == $dot)
  257. {
  258. break;
  259. }
  260. if ($pattern{$i} == $digit)
  261. {
  262. $decimalPoints = $i - $decimalPos;
  263. break;
  264. }
  265. }
  266. }
  267. $digitPattern = is_int($decimalPos) ? substr($pattern, 0, $decimalPos) : $pattern;
  268. $digitPattern = preg_replace('/[^0]/', '', $digitPattern);
  269. $info['groupPos1'] = $groupPos1;
  270. $info['groupSize1'] = $groupSize1;
  271. $info['groupPos2'] = $groupPos2;
  272. $info['groupSize2'] = $groupSize2;
  273. $info['decimalPos'] = $decimalPos;
  274. $info['decimalPoints'] = $decimalPoints;
  275. $info['digitSize'] = strlen($digitPattern);
  276. return $info;
  277. }
  278. /**
  279. * Gets the prefix and postfix of a pattern.
  280. *
  281. * @param string $pattern pattern
  282. * @return array of prefix and postfix, array(prefix,postfix).
  283. */
  284. protected function getPrePostfix($pattern)
  285. {
  286. $regexp = '/[#,\.0]+/';
  287. $result = preg_split($regexp, $pattern);
  288. return array($result[0], $result[1]);
  289. }
  290. /**
  291. * Indicates the number of decimal places.
  292. *
  293. * @return int number of decimal places.
  294. */
  295. function getDecimalDigits()
  296. {
  297. return $this->pattern['decimalPoints'];
  298. }
  299. /**
  300. * Sets the number of decimal places.
  301. *
  302. * @param int $value number of decimal places.
  303. */
  304. function setDecimalDigits($value)
  305. {
  306. return $this->pattern['decimalPoints'] = $value;
  307. }
  308. /**
  309. * Indicates the digit size.
  310. *
  311. * @return int digit size.
  312. */
  313. function getDigitSize()
  314. {
  315. return $this->pattern['digitSize'];
  316. }
  317. /**
  318. * Sets the digit size.
  319. *
  320. * @param int $value digit size.
  321. */
  322. function setDigitSize($value)
  323. {
  324. $this->pattern['digitSize'] = $value;
  325. }
  326. /**
  327. * Gets the string to use as the decimal separator.
  328. *
  329. * @return string decimal separator.
  330. */
  331. function getDecimalSeparator()
  332. {
  333. return $this->data['NumberElements'][0];
  334. }
  335. /**
  336. * Sets the string to use as the decimal separator.
  337. *
  338. * @param string $value the decimal point
  339. */
  340. function setDecimalSeparator($value)
  341. {
  342. return $this->data['NumberElements'][0] = $value;
  343. }
  344. /**
  345. * Gets the string that separates groups of digits to the left
  346. * of the decimal in currency values.
  347. *
  348. * @return string currency group separator.
  349. */
  350. function getGroupSeparator()
  351. {
  352. return $this->data['NumberElements'][1];
  353. }
  354. /**
  355. * Sets the string to use as the group separator.
  356. *
  357. * @param string $value the group separator.
  358. */
  359. function setGroupSeparator($value)
  360. {
  361. return $this->data['NumberElements'][1] = $value;
  362. }
  363. /**
  364. * Gets the number of digits in each group to the left of the decimal
  365. * There can be two grouping sizes, this fucntion
  366. * returns <b>array(group1, group2)</b>, if there is only 1 grouping size,
  367. * group2 will be false.
  368. *
  369. * @return array grouping size(s).
  370. */
  371. function getGroupSizes()
  372. {
  373. $group1 = $this->pattern['groupSize1'];
  374. $group2 = $this->pattern['groupSize2'];
  375. return array($group1, $group2);
  376. }
  377. /**
  378. * Sets the number of digits in each group to the left of the decimal.
  379. * There can be two grouping sizes, the value should
  380. * be an <b>array(group1, group2)</b>, if there is only 1 grouping size,
  381. * group2 should be false.
  382. *
  383. * @param array $groupSize grouping size(s).
  384. */
  385. function setGroupSizes($groupSize)
  386. {
  387. $this->pattern['groupSize1'] = $groupSize[0];
  388. $this->pattern['groupSize2'] = $groupSize[1];
  389. }
  390. /**
  391. * Gets the format pattern for negative values.
  392. * The negative pattern is composed of a prefix, and postfix.
  393. * This function returns <b>array(prefix, postfix)</b>.
  394. *
  395. * @return arary negative pattern.
  396. */
  397. function getNegativePattern()
  398. {
  399. $prefix = $this->pattern['negPref'];
  400. $postfix = $this->pattern['negPost'];
  401. return array($prefix, $postfix);
  402. }
  403. /**
  404. * Sets the format pattern for negative values.
  405. * The negative pattern is composed of a prefix, and postfix in the form
  406. * <b>array(prefix, postfix)</b>.
  407. *
  408. * @param arary $pattern negative pattern.
  409. */
  410. function setNegativePattern($pattern)
  411. {
  412. $this->pattern['negPref'] = $pattern[0];
  413. $this->pattern['negPost'] = $pattern[1];
  414. }
  415. /**
  416. * Gets the format pattern for positive values.
  417. * The positive pattern is composed of a prefix, and postfix.
  418. * This function returns <b>array(prefix, postfix)</b>.
  419. *
  420. * @return arary positive pattern.
  421. */
  422. function getPositivePattern()
  423. {
  424. $prefix = $this->pattern['posPref'];
  425. $postfix = $this->pattern['posPost'];
  426. return array($prefix, $postfix);
  427. }
  428. /**
  429. * Sets the format pattern for positive values.
  430. * The positive pattern is composed of a prefix, and postfix in the form
  431. * <b>array(prefix, postfix)</b>.
  432. *
  433. * @param arary $pattern positive pattern.
  434. */
  435. function setPositivePattern($pattern)
  436. {
  437. $this->pattern['posPref'] = $pattern[0];
  438. $this->pattern['posPost'] = $pattern[1];
  439. }
  440. /**
  441. * Gets the string to use as the currency symbol.
  442. *
  443. * @return string $currency currency symbol.
  444. */
  445. function getCurrencySymbol($currency = 'USD')
  446. {
  447. if (isset($this->pattern['symbol']))
  448. {
  449. return $this->pattern['symbol'];
  450. }
  451. else
  452. {
  453. return $this->data['Currencies'][$currency][0];
  454. }
  455. }
  456. /**
  457. * Sets the string to use as the currency symbol.
  458. *
  459. * @param string $symbol currency symbol.
  460. */
  461. function setCurrencySymbol($symbol)
  462. {
  463. $this->pattern['symbol'] = $symbol;
  464. }
  465. /**
  466. * Gets the string that represents negative infinity.
  467. *
  468. * @return string negative infinity.
  469. */
  470. function getNegativeInfinitySymbol()
  471. {
  472. return $this->pattern['negInfty'];
  473. }
  474. /**
  475. * Sets the string that represents negative infinity.
  476. *
  477. * @param string $value negative infinity.
  478. */
  479. function setNegativeInfinitySymbol($value)
  480. {
  481. $this->pattern['negInfty'] = $value;
  482. }
  483. /**
  484. * Gets the string that represents positive infinity.
  485. *
  486. * @return string positive infinity.
  487. */
  488. function getPositiveInfinitySymbol()
  489. {
  490. return $this->pattern['posInfty'];
  491. }
  492. /**
  493. * Sets the string that represents positive infinity.
  494. *
  495. * @param string $value positive infinity.
  496. */
  497. function setPositiveInfinitySymbol($value)
  498. {
  499. $this->pattern['posInfty'] = $value;
  500. }
  501. /**
  502. * Gets the string that denotes that the associated number is negative.
  503. *
  504. * @return string negative sign.
  505. */
  506. function getNegativeSign()
  507. {
  508. return $this->data['NumberElements'][6];
  509. }
  510. /**
  511. * Sets the string that denotes that the associated number is negative.
  512. *
  513. * @param string $value negative sign.
  514. */
  515. function setNegativeSign($value)
  516. {
  517. $this->data['NumberElements'][6] = $value;
  518. }
  519. /**
  520. * Gets the string that denotes that the associated number is positive.
  521. *
  522. * @return string positive sign.
  523. */
  524. function getPositiveSign()
  525. {
  526. return $this->data['NumberElements'][11];
  527. }
  528. /**
  529. * Sets the string that denotes that the associated number is positive.
  530. *
  531. * @param string $value positive sign.
  532. */
  533. function setPositiveSign($value)
  534. {
  535. $this->data['NumberElements'][11] = $value;
  536. }
  537. /**
  538. * Gets the string that represents the IEEE NaN (not a number) value.
  539. *
  540. * @return string NaN symbol.
  541. */
  542. function getNaNSymbol()
  543. {
  544. return $this->data['NumberElements'][10];
  545. }
  546. /**
  547. * Sets the string that represents the IEEE NaN (not a number) value.
  548. *
  549. * @param string $value NaN symbol.
  550. */
  551. function setNaNSymbol($value)
  552. {
  553. $this->data['NumberElements'][10] = $value;
  554. }
  555. /**
  556. * Gets the string to use as the percent symbol.
  557. *
  558. * @return string percent symbol.
  559. */
  560. function getPercentSymbol()
  561. {
  562. return $this->data['NumberElements'][3];
  563. }
  564. /**
  565. * Sets the string to use as the percent symbol.
  566. *
  567. * @param string $value percent symbol.
  568. */
  569. function setPercentSymbol($value)
  570. {
  571. $this->data['NumberElements'][3] = $value;
  572. }
  573. /**
  574. * Gets the string to use as the per mille symbol.
  575. *
  576. * @return string percent symbol.
  577. */
  578. function getPerMilleSymbol()
  579. {
  580. return $this->data['NumberElements'][8];
  581. }
  582. /**
  583. * Sets the string to use as the per mille symbol.
  584. *
  585. * @param string $value percent symbol.
  586. */
  587. function setPerMilleSymbol($value)
  588. {
  589. $this->data['NumberElements'][8] = $value;
  590. }
  591. }

Debug toolbar