You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

327 lines
6.5 KiB

  1. <?php
  2. /**
  3. * Object in Mongo
  4. *
  5. *
  6. */
  7. class RObject extends RModel implements ArrayAccess {
  8. /**
  9. * Enter description here...
  10. *
  11. * @var MongoCollection
  12. */
  13. private $_collection;
  14. private $_operations = array();
  15. private $_attrs = array();
  16. private $_id;
  17. /**
  18. * Construct object
  19. *
  20. * @param array $attrs fields
  21. */
  22. function __construct(array $attrs = array()) {
  23. $this->setAttrs($attrs);
  24. }
  25. /**
  26. * Set field value
  27. *
  28. * @param string $name field name
  29. * @param mixed $value field value
  30. */
  31. function setAttr($name, $value) {
  32. if ($name == "_id") {
  33. $this->setId($value);
  34. return;
  35. }
  36. $this->_attrs = rock_array_set($this->_attrs, $name, $value);
  37. $this->_execOperator('$set', $name, $value);
  38. }
  39. /**
  40. * Set fields values
  41. *
  42. * @param array $attrs fields values
  43. */
  44. function setAttrs(array $attrs) {
  45. foreach ($attrs as $field => $value) {
  46. $this->setAttr($field, $value);
  47. }
  48. }
  49. /**
  50. * Set original fields values
  51. *
  52. * @param array $attrs fields
  53. */
  54. function setSource(array $attrs) {
  55. if (isset($attrs["_id"])) {
  56. $this->setId($attrs["_id"]);
  57. }
  58. $this->_attrs = array_merge($this->_attrs, $attrs);
  59. }
  60. private function _execOperator($operator, $attr, $newValue) {
  61. if (!isset($this->_operations[$operator])) {
  62. $this->_operations[$operator] = array();
  63. }
  64. $this->_operations[$operator][$attr] = $newValue;
  65. }
  66. /**
  67. * Return current object ID, can determine if the object is saved
  68. *
  69. * @return MongoId
  70. */
  71. function id() {
  72. return $this->_id;
  73. }
  74. /**
  75. * Return current object ID string value
  76. *
  77. * @return string
  78. */
  79. function idValue() {
  80. return $this->_id ? $this->_id->__toString() : null;
  81. }
  82. /**
  83. * Set current object id
  84. *
  85. * @param string|MongoId $id New id, must contains 24 chars
  86. */
  87. function setId($id) {
  88. $this->_id = ($id);
  89. }
  90. /**
  91. * Increase numeric field value
  92. *
  93. * @param string $attr Field
  94. * @param integer $count The count to increase
  95. */
  96. function increase($attr, $count = 1) {
  97. $this->_execOperator('$inc', $attr, $count);
  98. }
  99. /**
  100. * Remove field
  101. *
  102. * Later, you need to $obj->pull($attrParent, null) to remove NULL field
  103. *
  104. * @param string $attr Field
  105. * @param boolean $pullNull Should remove NULL field automatically?
  106. */
  107. function remove($attr, $pullNull = true) {
  108. if ($pullNull) {
  109. $this->_execOperator('$unset', $attr, 1);
  110. $this->save();
  111. if (strstr($attr, ".")) {
  112. $parent = substr($attr, 0, strrpos($attr, "."));
  113. $this->pull($parent, null);
  114. }
  115. }
  116. else {
  117. $this->_execOperator('$unset', $attr, 1);
  118. }
  119. }
  120. /**
  121. * Push value to collection
  122. *
  123. * @param string $attr Field
  124. * @param mixed $value Value
  125. * @param boolean|string|integer $genId Should generate ID?
  126. */
  127. function push($attr, $value, $genId = false) {
  128. if (is_bool($genId) && $genId) {
  129. $attr .= "." . strtoupper(uniqid("ID_"));
  130. $this->setAttr($attr, $value);
  131. }
  132. elseif (is_string($genId) || is_integer($genId)) {
  133. $attr .= "." . $genId;
  134. $this->setAttr($attr, $value);
  135. }
  136. else {
  137. $this->_execOperator('$push', $attr, $value);
  138. }
  139. }
  140. /**
  141. * Add values to collection
  142. *
  143. * @param string $attr Field
  144. * @param array $values Values
  145. */
  146. function pushAll($attr, array $values) {
  147. $this->_execOperator('$pushAll', $attr, $values);
  148. }
  149. function addToSet($attr, $value) {
  150. $this->_execOperator('$addToSet', $attr, $value);
  151. }
  152. function addAllToSet($attr, array $values) {
  153. $this->_execOperator('$addToSet', $attr, array( '$each' => $values ));
  154. }
  155. function pop($attr) {
  156. $this->_execOperator('$pop', $attr, 1);
  157. }
  158. function shift($attr) {
  159. $this->_execOperator('$pop', $attr, -1);
  160. }
  161. /**
  162. * Pull specified value in field
  163. *
  164. * @param string $attr Field
  165. * @param mixed $value Value
  166. */
  167. function pull($attr, $value) {
  168. $this->_execOperator('$pull', $attr, $value);
  169. }
  170. function pullAll($attr, array $values) {
  171. $this->_execOperator('$pullAll', $attr, $values);
  172. }
  173. /**
  174. * Save current object to MongoDB
  175. *
  176. * @param boolean $refresh Should refresh the object fields values?
  177. * @return boolean
  178. */
  179. function save($refresh = false) {
  180. if (!$this->_collection) {
  181. import("@.RMongoException");
  182. throw new RMongoException("Object is not in any collection, please use setCollection() to method to set a collection.");
  183. }
  184. $bool = true;
  185. if ($this->_id) {//if exists
  186. if (!empty($this->_operations)) {
  187. $bool = $this->_collection->update(array( "_id" => $this->_id ), $this->_operations, array(
  188. "upsert" => false,
  189. "multiple" => false
  190. ));
  191. if ($refresh) {
  192. $bool = $this->refresh();
  193. }
  194. }
  195. }
  196. else {
  197. $bool = $this->_collection->insert($this->_attrs, true);
  198. if ($bool) {
  199. $this->_id = $this->_attrs["_id"];
  200. import("@.RMongo");
  201. RMongo::setLastInsertId($this->_id->__toString());
  202. }
  203. }
  204. $this->_operations = array();
  205. return $bool;
  206. }
  207. /**
  208. * Refresh the current object
  209. *
  210. * @return boolean
  211. */
  212. function refresh() {
  213. if (!$this->_collection) {
  214. import("@.RMongoException");
  215. throw new RMongoException("Object is not in any collection, please use setCollection() to method to set a collection.");
  216. }
  217. if (!$this->_id) {
  218. return true;
  219. }
  220. $this->setSource($this->_collection->findOne( array( "_id" => $this->_id ) ));
  221. return true;
  222. }
  223. function setCollection(MongoCollection $collection) {
  224. $this->_collection = $collection;
  225. }
  226. function attr($name) {
  227. return rock_array_get($this->_attrs, $name);
  228. }
  229. /**
  230. * Get all fields values
  231. *
  232. * @return array
  233. */
  234. function attrs() {
  235. return $this->_attrs;
  236. }
  237. /**
  238. * Delete the object
  239. *
  240. */
  241. function delete() {
  242. if ($this->_collection && $this->_id) {
  243. $this->_collection->remove(array( "_id" => $this->_id ));
  244. }
  245. $this->_id = null;
  246. $this->_attrs = array();
  247. }
  248. function __get($name) {
  249. return $this->attr($name);
  250. }
  251. /**
  252. * Determine offset exists
  253. *
  254. * For ArrayAccess implementation
  255. *
  256. * @param integer $index
  257. * @return boolean
  258. * @since 1.0
  259. */
  260. function offsetExists($index) {
  261. return !is_null($this->attr($index));
  262. }
  263. /**
  264. * Get value at specified offset
  265. *
  266. * For ArrayAccess implementation
  267. *
  268. * @param integer $index Offset
  269. * @return mixed
  270. */
  271. function offsetGet($index) {
  272. return $this->attr($index);
  273. }
  274. /**
  275. * Set value at specified offset
  276. *
  277. * For ArrayAccess implementation
  278. *
  279. * @param integer $index 偏移量
  280. * @param mixed $item 值
  281. */
  282. function offsetSet($index, $item) {
  283. $this->setAttr($index, $item);
  284. }
  285. /**
  286. * Unset value at specified offset
  287. *
  288. * For ArrayAccess implementation
  289. *
  290. * @param integer $index Offset
  291. */
  292. function offsetUnset($index) {
  293. $this->setAttr($index, null);
  294. }
  295. }
  296. ?>