PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/core/src/lmbObject.class.php

https://github.com/idler/limb
PHP | 408 lines | 224 code | 50 blank | 134 comment | 27 complexity | dcd1d5611b7e22b9e5f2d9758437db1d MD5 | raw file
  1. <?php
  2. /*
  3. * Limb PHP Framework
  4. *
  5. * @link http://limb-project.com
  6. * @copyright Copyright &copy; 2004-2009 BIT(http://bit-creative.com)
  7. * @license LGPL http://www.gnu.org/copyleft/lesser.html
  8. */
  9. lmb_require('limb/core/src/lmbSetInterface.interface.php');
  10. lmb_require('limb/core/src/exception/lmbNoSuchMethodException.class.php');
  11. lmb_require('limb/core/src/exception/lmbNoSuchPropertyException.class.php');
  12. /**
  13. * Generic container for data with magic accessors.
  14. *
  15. * NOTE: All properties are stored as attributes of an object. If you need to
  16. * make certain properties 'guarded', you should prefix these properties
  17. * with "_" symbol.
  18. *
  19. * <b>Basic usage</b>
  20. * <code>
  21. * //filling object
  22. * $obj = new lmbObject(array('foo' => 'bar'));
  23. * //the getter calls below are equal
  24. * $obj->get('foo');
  25. * $obj->getFoo();
  26. * $obj['foo'];
  27. * $obj->foo;
  28. * //the setter calls below are equal
  29. * $obj->set('foo', 'hey');
  30. * $obj->setFoo('hey');
  31. * $obj['foo'] = 'hey';
  32. * $obj->foo = 'hey';
  33. * </code>
  34. *
  35. * <b>Mapping generic getters to fine-grained methods</b>
  36. * <code>
  37. * class Foo extends lmbObject
  38. * {
  39. * function getBar()
  40. * {
  41. * return 'bar';
  42. * }
  43. * }
  44. * $foo = new Foo();
  45. * //the call below will be magically mapped to getBar() method
  46. * //this can be very useful for templates, e.g. {$bar} in
  47. * //template will trigger the same method getBar() as well
  48. * $foo->get('bar');
  49. * </code>
  50. *
  51. * <b>Mapping generic setters to fine-grained methods</b>
  52. * <code>
  53. * class Foo extends lmbObject
  54. * {
  55. * function setBar($value)
  56. * {
  57. * $this->_setRaw('bar', (int)$value);
  58. * }
  59. * }
  60. * $foo = new Foo();
  61. * //the call below will be magically mapped to setBar($value) method
  62. * //this can be useful if some property processing is required
  63. * $foo->set('bar', '10.0');
  64. * </code>
  65. *
  66. * @version $Id: lmbObject.class.php 5567 2007-04-06 14:37:24Z serega $
  67. * @package core
  68. */
  69. class lmbObject implements lmbSetInterface
  70. {
  71. private $_map = array(
  72. 'public' => array(),
  73. 'dynamic' => array(),
  74. 'initialized' => false,
  75. );
  76. /**
  77. * Constructor.
  78. * Fills internals properties if any
  79. * @param array properties array
  80. */
  81. function __construct($properties = array())
  82. {
  83. $this->_registerPredefinedVariables();
  84. if($properties)
  85. $this->import($properties);
  86. }
  87. protected function _registerPredefinedVariables()
  88. {
  89. if($this->_map['initialized'])
  90. return;
  91. $var_names = get_object_vars($this);
  92. foreach($var_names as $key => $item)
  93. {
  94. if(!$this->_isGuarded($key))
  95. $this->_map['public'][$key] = $key;
  96. }
  97. $this->_map['initialized'] = true;
  98. }
  99. /**
  100. * Returns class name using PHP built in get_class
  101. * @see get_class
  102. * @return string
  103. */
  104. final function getClass()
  105. {
  106. return get_class($this);
  107. }
  108. /**
  109. * Merges existing properties with new ones
  110. * @param array
  111. */
  112. function import($values, $raw = false)
  113. {
  114. if(!is_array($values))
  115. return $this;
  116. foreach($values as $property => $value)
  117. if($raw)
  118. $this->_setRaw($property, $value);
  119. else
  120. $this->set($property, $value);
  121. return $this;
  122. }
  123. /**
  124. * Exports all object properties as an array
  125. * @return array
  126. */
  127. function export()
  128. {
  129. $exported = array();
  130. foreach($this->getPropertiesNames() as $name)
  131. $exported[$name] = $this->$name;
  132. return $exported;
  133. }
  134. /**
  135. * Checks if such property exists
  136. * Can be overridden in child classes like lmbActiveRecord
  137. * @return bool returns true even if attribute is null
  138. */
  139. function has($name)
  140. {
  141. return $this->_hasProperty($name) || $this->_mapPropertyToMethod($name);
  142. }
  143. protected function _hasProperty($name)
  144. {
  145. $this->_registerPredefinedVariables();
  146. return isset($this->_map['public'][$name]);
  147. }
  148. function getPropertiesNames()
  149. {
  150. $this->_registerPredefinedVariables();
  151. return array_keys($this->_map['public']);
  152. }
  153. /**
  154. * Alias for getPropertiesNames
  155. *
  156. * @deprecated
  157. */
  158. function getAttributesNames()
  159. {
  160. return $this->getPropertiesNames();
  161. }
  162. /**
  163. * Removes specified property
  164. * @param string
  165. */
  166. function remove($name)
  167. {
  168. if($this->_isGuarded($name))
  169. return;
  170. unset($this->_map['public'][$name]);
  171. unset($this->_map['dynamic'][$name]);
  172. unset($this->$name);
  173. }
  174. /**
  175. * Removes all object properties
  176. */
  177. function reset()
  178. {
  179. $this->_map['public'] = array();
  180. $this->_map['dynamic'] = array();
  181. foreach($this->getPropertiesNames() as $name)
  182. unset($this->$name);
  183. }
  184. /**
  185. * Returns property value if it exists and not guarded.
  186. * Magically maps getter to fine-grained method if it exists, e.g. get('foo') => getFoo()
  187. * @param string property name
  188. * @return mixed|null
  189. */
  190. function get($name, $default = LIMB_UNDEFINED)
  191. {
  192. if($method = $this->_mapPropertyToMethod($name))
  193. return $this->$method();
  194. if($this->_hasProperty($name))
  195. return $this->_getRaw($name);
  196. if(LIMB_UNDEFINED !== $default)
  197. return $default;
  198. throw new lmbNoSuchPropertyException("No such property '$name' in " . get_class($this));
  199. }
  200. /**
  201. * Sets property value
  202. * Magically maps setter to fine-grained method if it exists, e.g. set('foo', $value) => setFoo($value)
  203. * @param string property name
  204. * @param mixed value
  205. */
  206. function set($property, $value)
  207. {
  208. if(!$property)
  209. return;
  210. if($method = $this->_mapPropertyToSetMethod($property))
  211. return $this->$method($value);
  212. $this->_setRaw($property, $value);
  213. }
  214. protected function _getRaw($name)
  215. {
  216. if($this->_hasProperty($name))
  217. return $this->$name;
  218. }
  219. protected function _setRaw($name, $value)
  220. {
  221. if($this->_isGuarded($name))
  222. return;
  223. $this->_map['public'][$name] = $name;
  224. $this->_map['dynamic'][$name] = $name;
  225. $this->$name = $value;
  226. }
  227. protected function _isGuarded($property)
  228. {
  229. return isset($property{0}) ? $property{0} == '_' : false;
  230. }
  231. /**#@+
  232. * Implements ArrayAccess interface
  233. * @see ArrayAccess
  234. */
  235. function offsetExists($offset)
  236. {
  237. return $this->has($offset);
  238. }
  239. function offsetGet($offset)
  240. {
  241. return $this->get($offset);
  242. }
  243. function offsetSet($offset, $value)
  244. {
  245. $this->set($offset, $value);
  246. }
  247. function offsetUnset($offset)
  248. {
  249. $this->remove($offset);
  250. }
  251. /**#@-*/
  252. function __call($method, $args = array())
  253. {
  254. if($property = $this->_mapGetToProperty($method))
  255. {
  256. if($this->has($property))
  257. return $this->get($property);
  258. }
  259. elseif($property = $this->_mapSetToProperty($method))
  260. {
  261. $this->set($property, $args[0]);
  262. return;
  263. }
  264. throw new lmbNoSuchMethodException("No such method '$method' in " . get_class($this));
  265. }
  266. protected function _mapGetToProperty($method)
  267. {
  268. if(0 === strpos($method, 'get'))
  269. return lmb_under_scores(substr($method, 3));
  270. }
  271. protected function _mapSetToProperty($method)
  272. {
  273. if(0 === strpos($method, 'set'))
  274. return lmb_under_scores(substr($method, 3));
  275. }
  276. protected function _mapPropertyToMethod($property)
  277. {
  278. static $map = array();
  279. if(isset($map[$property]))
  280. return $map[$property];
  281. $capsed = lmb_camel_case($property);
  282. $method = 'get' . $capsed;
  283. if($method !== 'get' && method_exists($this, $method))
  284. {
  285. $map[$property] = $method;
  286. return $method;
  287. }
  288. //'is_foo' property is mapped to 'isFoo' method if it exists
  289. if(strpos($property, 'is_') === 0 && method_exists($this, $capsed))
  290. {
  291. $map[$property] = $capsed;
  292. return $capsed;
  293. }
  294. $map[$property] = false;
  295. }
  296. protected function _mapPropertyToSetMethod($property)
  297. {
  298. $method = 'set' . lmb_camel_case($property);
  299. if($method !== 'set' && method_exists($this, $method))
  300. return $method;
  301. }
  302. /**
  303. * __set an alias of set()
  304. * @see set, offsetSet
  305. */
  306. function __set($property, $value)
  307. {
  308. if(isset($this->_map['dynamic'][$property]))
  309. $this->$property = $value;
  310. else
  311. $this->set($property, $value);
  312. }
  313. /**
  314. * __get -- an alias of get()
  315. * @see get, offsetGet
  316. * @return mixed
  317. */
  318. function __get($property)
  319. {
  320. return $this->get($property);
  321. }
  322. /**
  323. * __isset an alias of has()
  324. * @return boolean whether or not this object contains $name
  325. */
  326. function __isset($name)
  327. {
  328. return $this->has($name);
  329. }
  330. /**
  331. * __unser an alias of remove()
  332. * @param string $name
  333. */
  334. function __unset($name)
  335. {
  336. return $this->remove($name);
  337. }
  338. function current()
  339. {
  340. return $this->_getRaw($this->key());
  341. }
  342. function next()
  343. {
  344. return $this->_getRaw(next($this->_map['public']));
  345. }
  346. function key()
  347. {
  348. return current($this->_map['public']);
  349. }
  350. function valid()
  351. {
  352. return (bool) $this->key();
  353. }
  354. function rewind()
  355. {
  356. reset($this->_map['public']);
  357. }
  358. }