PageRenderTime 26ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/RedBean/OODBBean.php

https://github.com/pietercolpaert/redbean
PHP | 449 lines | 157 code | 57 blank | 235 comment | 32 complexity | 100d29042d7e9412e648bcbd0b59e750 MD5 | raw file
  1. <?php
  2. /**
  3. * RedBean_OODBBean (Object Oriented DataBase Bean)
  4. * @file RedBean/RedBean_OODBBean.php
  5. * @description The Bean class used for passing information
  6. * @author Gabor de Mooij
  7. * @license BSD
  8. *
  9. *
  10. * (c) G.J.G.T. (Gabor) de Mooij
  11. * This source file is subject to the BSD/GPLv2 License that is bundled
  12. * with this source code in the file license.txt.
  13. */
  14. class RedBean_OODBBean implements IteratorAggregate, ArrayAccess {
  15. /**
  16. * Reference to NULL property for magic getter.
  17. *
  18. * @var Null $null
  19. */
  20. private $null = null;
  21. /**
  22. * Properties of the bean. These are kept in a private
  23. * array called properties and exposed through the array interface.
  24. *
  25. * @var array $properties
  26. */
  27. private $properties = array();
  28. /**
  29. * Meta Data storage. This is the internal property where all
  30. * Meta information gets stored.
  31. *
  32. * @var array
  33. */
  34. private $__info = NULL;
  35. /**
  36. * Contains a BeanHelper to access service objects like
  37. * te association manager and OODB.
  38. *
  39. * @var RedBean_BeanHelper
  40. */
  41. private $beanHelper = NULL;
  42. /**
  43. * Contains the latest Fetch Type.
  44. * A Fetch Type is a preferred type for the next nested bean.
  45. *
  46. * @var null
  47. */
  48. public static $fetchType = NULL;
  49. /**
  50. * Sets the Bean Helper. Normally the Bean Helper is set by OODB.
  51. * Here you can change the Bean Helper. The Bean Helper is an object
  52. * providing access to a toolbox for the bean necessary to retrieve
  53. * nested beans (bean lists: ownBean,sharedBean) without the need to
  54. * rely on static calls to the facade (or make this class dep. on OODB).
  55. *
  56. * @param RedBean_IBeanHelper $helper
  57. * @return void
  58. */
  59. public function setBeanHelper(RedBean_IBeanHelper $helper) {
  60. $this->beanHelper = $helper;
  61. }
  62. /**
  63. * Returns an ArrayIterator so you can treat the bean like
  64. * an array with the properties container as its contents.
  65. *
  66. * @return ArrayIterator $arrayIt an array iterator instance with $properties
  67. */
  68. public function getIterator() {
  69. return new ArrayIterator($this->properties);
  70. }
  71. /**
  72. * Imports all values in associative array $array. Every key is used
  73. * for a property and every value will be assigned to the property
  74. * identified by the key. So basically this method converts the
  75. * associative array to a bean by loading the array. You can filter
  76. * the values using the $selection parameter. If $selection is boolean
  77. * false, no filtering will be applied. If $selection is an array
  78. * only the properties specified (as values) in the $selection
  79. * array will be taken into account. To skip a property, omit it from
  80. * the $selection array. Also, instead of providing an array you may
  81. * pass a comma separated list of property names. This method is
  82. * chainable because it returns its own object.
  83. * Imports data into bean
  84. *
  85. * @param array $array what you want to import
  86. * @param string|array $selection selection of values
  87. * @param boolean $notrim if TRUE values will not be trimmed
  88. *
  89. * @return RedBean_OODBBean $this
  90. */
  91. public function import( $arr, $selection=false, $notrim=false ) {
  92. if (is_string($selection)) $selection = explode(",",$selection);
  93. //trim whitespaces
  94. if (!$notrim && is_array($selection)) foreach($selection as $k=>$s){ $selection[$k]=trim($s); }
  95. foreach($arr as $k=>$v) {
  96. if ($k != "__info") {
  97. if (!$selection || ($selection && in_array($k,$selection))) {
  98. $this->$k = $v;
  99. }
  100. }
  101. }
  102. return $this;
  103. }
  104. /**
  105. * Exports the bean as an array.
  106. * This function exports the contents of a bean to an array and returns
  107. * the resulting array. If $meta eq uals boolean TRUE, then the array will
  108. * also contain the __info section containing the meta data inside the
  109. * RedBean_OODBBean Bean object.
  110. * @param boolean $meta
  111. * @return array $arr
  112. */
  113. public function export($meta = false) {
  114. $arr = $this->properties;
  115. foreach($arr as $k=>$v) {
  116. if (is_array($v) || is_object($v)) unset($arr[$k]);
  117. }
  118. if ($meta) $arr["__info"] = $this->__info;
  119. return $arr;
  120. }
  121. /**
  122. * Implements isset() function for use as an array.
  123. * Returns whether bean has an element with key
  124. * named $property. Returns TRUE if such an element exists
  125. * and FALSE otherwise.
  126. * @param string $property
  127. * @return boolean $hasProperty
  128. */
  129. public function __isset( $property ) {
  130. return (isset($this->properties[$property]));
  131. }
  132. /**
  133. * Returns the ID of the bean no matter what the ID field is.
  134. *
  135. * @return string $id record Identifier for bean
  136. */
  137. public function getID() {
  138. $idfield = $this->getMeta("sys.idfield");
  139. return (string) $this->$idfield;
  140. }
  141. /**
  142. * Unsets a property. This method will load the property first using
  143. * __get.
  144. *
  145. * @param string $property property
  146. *
  147. * @return void
  148. */
  149. public function __unset($property) {
  150. $this->__get($property);
  151. $fieldLink = $property."_id";
  152. if (isset($this->$fieldLink)) {
  153. //wanna unset a bean reference?
  154. $this->$fieldLink = null;
  155. return;
  156. }
  157. if ((isset($this->properties[$property]))) {
  158. unset($this->properties[$property]);
  159. }
  160. }
  161. /**
  162. * Removes a property from the properties list without invoking
  163. * an __unset on the bean.
  164. *
  165. * @param string $property property that needs to be unset
  166. *
  167. * @return void
  168. */
  169. public function removeProperty( $property ) {
  170. unset($this->properties[$property]);
  171. }
  172. /**
  173. * Magic Getter. Gets the value for a specific property in the bean.
  174. * If the property does not exist this getter will make sure no error
  175. * occurs. This is because RedBean allows you to query (probe) for
  176. * properties. If the property can not be found this method will
  177. * return NULL instead.
  178. * @param string $property
  179. * @return mixed $value
  180. */
  181. public function &__get( $property ) {
  182. if ($this->beanHelper)
  183. $toolbox = $this->beanHelper->getToolbox();
  184. if (!isset($this->properties[$property])) {
  185. $fieldLink = $property."_id";
  186. /**
  187. * All this magic can be become very complex quicly. For instance,
  188. * my PHP CLI produced a segfault while testing this code. Turns out that
  189. * if fieldlink equals idfield, scripts tend to recusrively load beans and
  190. * instead of giving a clue they simply crash and burn isnt that nice?
  191. */
  192. if (isset($this->$fieldLink) && $fieldLink != $this->getMeta('sys.idfield')) {
  193. $this->setMeta("tainted",true);
  194. $type = $toolbox->getWriter()->getAlias($property);
  195. $targetType = $this->properties[$fieldLink];
  196. $bean = $toolbox->getRedBean()->load($type,$targetType);
  197. return $bean;
  198. }
  199. if (strpos($property,'own')===0) {
  200. $firstCharCode = ord(substr($property,3,1));
  201. if ($firstCharCode>=65 && $firstCharCode<=90) {
  202. $type = (strtolower(str_replace('own','',$property)));
  203. $myFieldLink = $this->getMeta('type')."_id";
  204. $beans = $toolbox->getRedBean()->find($type,array(),array(" $myFieldLink = ? ",array($this->getID())));
  205. $this->properties[$property] = $beans;
  206. $this->setMeta("sys.shadow.".$property,$beans);
  207. $this->setMeta("tainted",true);
  208. return $this->properties[$property];
  209. }
  210. }
  211. if (strpos($property,'shared')===0) {
  212. $firstCharCode = ord(substr($property,6,1));
  213. if ($firstCharCode>=65 && $firstCharCode<=90) {
  214. $type = (strtolower(str_replace('shared','',$property)));
  215. $keys = $toolbox->getRedBean()->getAssociationManager()->related($this,$type);
  216. if (!count($keys)) $beans = array(); else
  217. $beans = $toolbox->getRedBean()->batch($type,$keys);
  218. $this->properties[$property] = $beans;
  219. $this->setMeta("sys.shadow.".$property,$beans);
  220. $this->setMeta("tainted",true);
  221. return $this->properties[$property];
  222. }
  223. }
  224. return $this->null;
  225. }
  226. return $this->properties[$property];
  227. }
  228. /**
  229. * Magic Setter. Sets the value for a specific property.
  230. * This setter acts as a hook for OODB to mark beans as tainted.
  231. * The tainted meta property can be retrieved using getMeta("tainted").
  232. * The tainted meta property indicates whether a bean has been modified and
  233. * can be used in various caching mechanisms.
  234. * @param string $property
  235. * @param mixed $value
  236. */
  237. public function __set( $property, $value ) {
  238. $this->__get($property);
  239. $this->setMeta("tainted",true);
  240. if ($value===false) {
  241. $value = "0";
  242. }
  243. if ($value===true) {
  244. $value = "1";
  245. }
  246. $this->properties[$property] = $value;
  247. }
  248. /**
  249. * Returns the value of a meta property. A meta property
  250. * contains extra information about the bean object that will not
  251. * get stored in the database. Meta information is used to instruct
  252. * RedBean as well as other systems how to deal with the bean.
  253. * For instance: $bean->setMeta("buildcommand.unique.0", array(
  254. * "column1", "column2", "column3") );
  255. * Will add a UNIQUE constaint for the bean on columns: column1, column2 and
  256. * column 3.
  257. * To access a Meta property we use a dot separated notation.
  258. * If the property cannot be found this getter will return NULL instead.
  259. * @param string $path
  260. * @param mixed $default
  261. * @return mixed $value
  262. */
  263. public function getMeta( $path, $default = NULL) {
  264. return (isset($this->__info[$path])) ? $this->__info[$path] : $default;
  265. }
  266. /**
  267. * Stores a value in the specified Meta information property. $value contains
  268. * the value you want to store in the Meta section of the bean and $path
  269. * specifies the dot separated path to the property. For instance "my.meta.property".
  270. * If "my" and "meta" do not exist they will be created automatically.
  271. * @param string $path
  272. * @param mixed $value
  273. */
  274. public function setMeta( $path, $value ) {
  275. $this->__info[$path] = $value;
  276. }
  277. /**
  278. * Copies the meta information of the specified bean
  279. * This is a convenience method to enable you to
  280. * exchange meta information easily.
  281. * @param RedBean_OODBBean $bean
  282. * @return RedBean_OODBBean
  283. */
  284. public function copyMetaFrom( RedBean_OODBBean $bean ) {
  285. $this->__info = $bean->__info;
  286. return $this;
  287. }
  288. /**
  289. * Sleep function fore serialize() call. This will be invoked if you
  290. * perform a serialize() operation.
  291. *
  292. * @return mixed $array
  293. */
  294. public function __sleep() {
  295. //return the public stuff
  296. $this->setMeta("sys.oodb",null);
  297. return array('properties','__info');
  298. }
  299. /**
  300. * Reroutes a call to Model if exists. (new fuse)
  301. * @param string $method
  302. * @param array $args
  303. * @return mixed $mixed
  304. */
  305. public function __call($method, $args) {
  306. if (!isset($this->__info["model"])) {
  307. //@todo eliminate this dependency!
  308. $modelName = RedBean_ModelHelper::getModelName( $this->getMeta("type") );
  309. if (!class_exists($modelName)) return null;
  310. $obj = new $modelName();
  311. $obj->loadBean($this);
  312. $this->__info["model"] = $obj;
  313. }
  314. if (!method_exists($this->__info["model"],$method)) return null;
  315. return call_user_func_array(array($this->__info["model"],$method), $args);
  316. }
  317. /**
  318. * Implementation of __toString Method
  319. * Routes call to Model.
  320. * @return string $string
  321. */
  322. public function __toString() {
  323. $string = $this->__call('__toString',array());
  324. if ($string === null) {
  325. return json_encode($this->properties);
  326. }
  327. else {
  328. return $string;
  329. }
  330. }
  331. /**
  332. * Implementation of Array Access Interface, you can access bean objects
  333. * like an array.
  334. * Call gets routed to __set.
  335. *
  336. * @param mixed $offset offset string
  337. * @param mixed $value value
  338. *
  339. * @return void
  340. */
  341. public function offsetSet($offset, $value) {
  342. $this->__set($offset, $value);
  343. }
  344. /**
  345. * Implementation of Array Access Interface, you can access bean objects
  346. * like an array.
  347. *
  348. * @param mixed $offset property
  349. *
  350. * @return
  351. */
  352. public function offsetExists($offset) {
  353. return isset($this->properties[$offset]);
  354. }
  355. /**
  356. * Implementation of Array Access Interface, you can access bean objects
  357. * like an array.
  358. * Unsets a value from the array/bean.
  359. *
  360. * @param mixed $offset property
  361. *
  362. * @return
  363. */
  364. public function offsetUnset($offset) {
  365. unset($this->properties[$offset]);
  366. }
  367. /**
  368. * Implementation of Array Access Interface, you can access bean objects
  369. * like an array.
  370. * Returns value of a property.
  371. *
  372. * @param mixed $offset property
  373. *
  374. * @return
  375. */
  376. public function offsetGet($offset) {
  377. return $this->__get($offset);
  378. }
  379. /**
  380. * Chainable method to cast a certain ID to a bean; for instance:
  381. * $person = $club->fetchAs('person')->member;
  382. * This will load a bean of type person using member_id as ID.
  383. *
  384. * @param string $type preferred fetch type
  385. *
  386. * @return RedBean_OODBBean
  387. */
  388. public function fetchAs($type) {
  389. self::$fetchType = $type;
  390. return $this;
  391. }
  392. }