/library/Zend/Measure/AbstractMeasure.php

https://github.com/jtai/zf2 · PHP · 417 lines · 216 code · 45 blank · 156 comment · 38 complexity · 177f0c5c49bca1839b85f87b602d6db5 MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Measure
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /**
  21. * @namespace
  22. */
  23. namespace Zend\Measure;
  24. use Zend\Registry;
  25. use Zend\Locale;
  26. use Zend\Locale\Math;
  27. /**
  28. * Abstract class for all measurements
  29. *
  30. * @uses Zend\Locale\Locale
  31. * @uses Zend\Locale\Locale\Math
  32. * @uses Zend\Registry
  33. * @category Zend
  34. * @package Zend_Measure
  35. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  36. * @license http://framework.zend.com/license/new-bsd New BSD License
  37. */
  38. abstract class AbstractMeasure
  39. {
  40. /**
  41. * Plain value in standard unit
  42. *
  43. * @var string $_value
  44. */
  45. protected $_value;
  46. /**
  47. * Original type for this unit
  48. *
  49. * @var string $_type
  50. */
  51. protected $_type;
  52. /**
  53. * Locale identifier
  54. *
  55. * @var string $_locale
  56. */
  57. protected $_locale = null;
  58. /**
  59. * Unit types for this measurement
  60. */
  61. protected $_units = array();
  62. /**
  63. * Zend\Measure\MeasureAbstract is an abstract class for the different measurement types
  64. *
  65. * @param mixed $value Value as string, integer, real or float
  66. * @param string $type OPTIONAL a measure type f.e. Zend\Measure\Length::METER
  67. * @param Zend_Locale $locale OPTIONAL a Zend\Zend\Locale Type
  68. * @throws Zend\Measure\Exception
  69. */
  70. public function __construct($value, $type = null, $locale = null)
  71. {
  72. if (($type !== null) and (Locale\Locale::isLocale($type))) {
  73. $locale = $type;
  74. $type = null;
  75. }
  76. $this->setLocale($locale);
  77. if ($type === null) {
  78. $type = $this->_units['STANDARD'];
  79. }
  80. if (isset($this->_units[$type]) === false) {
  81. throw new Exception("Type ($type) is unknown");
  82. }
  83. $this->setValue($value, $type, $this->_locale);
  84. }
  85. /**
  86. * Returns the actual set locale
  87. *
  88. * @return string
  89. */
  90. public function getLocale()
  91. {
  92. return $this->_locale;
  93. }
  94. /**
  95. * Sets a new locale for the value representation
  96. *
  97. * @param string|Zend\Locale\Locale $locale (Optional) New locale to set
  98. * @param boolean $check False, check but don't set; True, set the new locale
  99. * @return Zend\Measure\AbstractMeasure
  100. */
  101. public function setLocale($locale = null, $check = false)
  102. {
  103. if (empty($locale)) {
  104. if (Registry::isRegistered('Zend_Locale') === true) {
  105. $locale = Registry::get('Zend_Locale');
  106. }
  107. }
  108. if ($locale === null) {
  109. $locale = new Locale\Locale();
  110. }
  111. if (!Locale\Locale::isLocale($locale, true)) {
  112. if (!Locale\Locale::isLocale($locale, false)) {
  113. throw new Exception("Language (" . (string) $locale . ") is unknown");
  114. }
  115. $locale = new Locale\Locale($locale);
  116. }
  117. if (!$check) {
  118. $this->_locale = (string) $locale;
  119. }
  120. return $this;
  121. }
  122. /**
  123. * Returns the internal value
  124. *
  125. * @param integer $round (Optional) Rounds the value to an given precision,
  126. * Default is -1 which returns without rounding
  127. * @param string|Zend\Locale\Locale $locale (Optional) Locale for number representation
  128. * @return integer|string
  129. */
  130. public function getValue($round = -1, $locale = null)
  131. {
  132. if ($round < 0) {
  133. $return = $this->_value;
  134. } else {
  135. $return = Math::round($this->_value, $round);
  136. }
  137. if ($locale !== null) {
  138. $this->setLocale($locale, true);
  139. return Locale\Format::toNumber($return, array('locale' => $locale));
  140. }
  141. return $return;
  142. }
  143. /**
  144. * Set a new value
  145. *
  146. * @param integer|string $value Value as string, integer, real or float
  147. * @param string $type OPTIONAL A measure type f.e. Zend_Measure_Length::METER
  148. * @param string|Zend\Locale\Locale $locale OPTIONAL Locale for parsing numbers
  149. * @throws Zend\Measure\Exception
  150. * @return Zend\Measure\AbstractMeasure
  151. */
  152. public function setValue($value, $type = null, $locale = null)
  153. {
  154. if (($type !== null) and (Locale\Locale::isLocale($type))) {
  155. $locale = $type;
  156. $type = null;
  157. }
  158. if ($locale === null) {
  159. $locale = $this->_locale;
  160. }
  161. $this->setLocale($locale, true);
  162. if ($type === null) {
  163. $type = $this->_units['STANDARD'];
  164. }
  165. if (empty($this->_units[$type])) {
  166. throw new Exception("Type ($type) is unknown");
  167. }
  168. try {
  169. $value = Locale\Format::getNumber($value, array('locale' => $locale));
  170. } catch(\Exception $e) {
  171. throw new Exception($e->getMessage(), $e->getCode(), $e);
  172. }
  173. $this->_value = $value;
  174. $this->setType($type);
  175. return $this;
  176. }
  177. /**
  178. * Returns the original type
  179. *
  180. * @return type
  181. */
  182. public function getType()
  183. {
  184. return $this->_type;
  185. }
  186. /**
  187. * Set a new type, and convert the value
  188. *
  189. * @param string $type New type to set
  190. * @throws Zend\Measure\Exception
  191. * @return Zend\Measure\AbstractMeasure
  192. */
  193. public function setType($type)
  194. {
  195. if (empty($this->_units[$type])) {
  196. throw new Exception("Type ($type) is unknown");
  197. }
  198. if (empty($this->_type)) {
  199. $this->_type = $type;
  200. } else {
  201. // Convert to standard value
  202. $value = $this->_value;
  203. if (is_array($this->_units[$this->getType()][0])) {
  204. foreach ($this->_units[$this->getType()][0] as $key => $found) {
  205. switch ($key) {
  206. case "/":
  207. if ($found != 0) {
  208. $value = call_user_func(Math::$div, $value, $found, 25);
  209. }
  210. break;
  211. case "+":
  212. $value = call_user_func(Math::$add, $value, $found, 25);
  213. break;
  214. case "-":
  215. $value = call_user_func(Math::$sub, $value, $found, 25);
  216. break;
  217. default:
  218. $value = call_user_func(Math::$mul, $value, $found, 25);
  219. break;
  220. }
  221. }
  222. } else {
  223. $value = call_user_func(Math::$mul, $value, $this->_units[$this->getType()][0], 25);
  224. }
  225. // Convert to expected value
  226. if (is_array($this->_units[$type][0])) {
  227. foreach (array_reverse($this->_units[$type][0]) as $key => $found) {
  228. switch ($key) {
  229. case "/":
  230. $value = call_user_func(Math::$mul, $value, $found, 25);
  231. break;
  232. case "+":
  233. $value = call_user_func(Math::$sub, $value, $found, 25);
  234. break;
  235. case "-":
  236. $value = call_user_func(Math::$add, $value, $found, 25);
  237. break;
  238. default:
  239. if ($found != 0) {
  240. $value = call_user_func(Math::$div, $value, $found, 25);
  241. }
  242. break;
  243. }
  244. }
  245. } else {
  246. $value = call_user_func(Math::$div, $value, $this->_units[$type][0], 25);
  247. }
  248. $this->_value = $this->roundToPrecision($value);
  249. $this->_type = $type;
  250. }
  251. return $this;
  252. }
  253. /**
  254. * Compare if the value and type is equal
  255. *
  256. * @param Zend\Measure\AbstractMeasure $object object to compare
  257. * @return boolean
  258. */
  259. public function equals($object)
  260. {
  261. if ((string) $object == $this->toString()) {
  262. return true;
  263. }
  264. return false;
  265. }
  266. /**
  267. * Returns a string representation
  268. *
  269. * @param integer $round (Optional) Runds the value to an given exception
  270. * @param string|Zend\Locale\Locale $locale (Optional) Locale to set for the number
  271. * @return string
  272. */
  273. public function toString($round = -1, $locale = null)
  274. {
  275. if ($locale === null) {
  276. $locale = $this->_locale;
  277. }
  278. return $this->getValue($round, $locale) . ' ' . $this->_units[$this->getType()][1];
  279. }
  280. /**
  281. * Returns a string representation
  282. *
  283. * @return string
  284. */
  285. public function __toString()
  286. {
  287. return $this->toString();
  288. }
  289. /**
  290. * Returns the conversion list
  291. *
  292. * @return array
  293. */
  294. public function getConversionList()
  295. {
  296. return $this->_units;
  297. }
  298. /**
  299. * Alias function for setType returning the converted unit
  300. *
  301. * @param string $type Constant Type
  302. * @param integer $round (Optional) Rounds the value to a given precision
  303. * @param string|Zend\Locale\Locale $locale (Optional) Locale to set for the number
  304. * @return string
  305. */
  306. public function convertTo($type, $round = 2, $locale = null)
  307. {
  308. $this->setType($type);
  309. return $this->toString($round, $locale);
  310. }
  311. /**
  312. * Adds an unit to another one
  313. *
  314. * @param Zend\Measure\AbstractMeasure $object object of same unit type
  315. * @return Zend\Measure\AbstractMeasure
  316. */
  317. public function add($object)
  318. {
  319. $object->setType($this->getType());
  320. $value = call_user_func(Math::$add, $this->getValue(-1), $object->getValue(-1), 25);
  321. $this->_value = $this->roundToPrecision($value);
  322. return $this;
  323. }
  324. /**
  325. * Substracts an unit from another one
  326. *
  327. * @param Zend\Measure\AbstractMeasure $object object of same unit type
  328. * @return Zend\Measure\AbstractMeasure
  329. */
  330. public function sub($object)
  331. {
  332. $object->setType($this->getType());
  333. $value = call_user_func(Math::$sub, $this->getValue(-1), $object->getValue(-1), 25);
  334. $this->_value = $this->roundToPrecision($value);
  335. return $this;
  336. }
  337. /**
  338. * Compares two units
  339. *
  340. * @param Zend\Measure\AbstractMeasure $object object of same unit type
  341. * @return boolean
  342. */
  343. public function compare($object)
  344. {
  345. $object->setType($this->getType());
  346. $value = $this->getValue(-1) - $object->getValue(-1);
  347. if ($value < 0) {
  348. return -1;
  349. } else if ($value > 0) {
  350. return 1;
  351. }
  352. return 0;
  353. }
  354. /**
  355. * Rounds a number to its last significant figure
  356. *
  357. * @param integer|float|string $value the number to round
  358. * @return float the rounded number
  359. */
  360. protected function roundToPrecision($value)
  361. {
  362. $slength = strlen($value);
  363. $length = 0;
  364. for($i = 1; $i <= $slength; ++$i) {
  365. if ($value[$slength - $i] != '0') {
  366. $length = 26 - $i;
  367. break;
  368. }
  369. }
  370. return Math::round($value, $length);
  371. }
  372. }