Просмотр файла news/libraries/db/mongo/mapper.php

Размер файла: 7.69Kb
  1. <?php
  2.  
  3. /*
  4. Copyright (c) 2009-2014 F3::Factory/Bong Cosca, All rights reserved.
  5.  
  6. This file is part of the Fat-Free Framework (http://fatfree.sf.net).
  7.  
  8. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
  9. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  10. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  11. PURPOSE.
  12.  
  13. Please see the license.txt file for more information.
  14. */
  15.  
  16. namespace DB\Mongo;
  17.  
  18. //! MongoDB mapper
  19. class Mapper extends \DB\Cursor {
  20.  
  21. protected
  22. //! MongoDB wrapper
  23. $db,
  24. //! Mongo collection
  25. $collection,
  26. //! Mongo document
  27. $document=array(),
  28. //! Mongo cursor
  29. $cursor;
  30.  
  31. /**
  32. * Return database type
  33. * @return string
  34. **/
  35. function dbtype() {
  36. return 'Mongo';
  37. }
  38.  
  39. /**
  40. * Return TRUE if field is defined
  41. * @return bool
  42. * @param $key string
  43. **/
  44. function exists($key) {
  45. return array_key_exists($key,$this->document);
  46. }
  47.  
  48. /**
  49. * Assign value to field
  50. * @return scalar|FALSE
  51. * @param $key string
  52. * @param $val scalar
  53. **/
  54. function set($key,$val) {
  55. return $this->document[$key]=$val;
  56. }
  57.  
  58. /**
  59. * Retrieve value of field
  60. * @return scalar|FALSE
  61. * @param $key string
  62. **/
  63. function get($key) {
  64. if ($this->exists($key))
  65. return $this->document[$key];
  66. user_error(sprintf(self::E_Field,$key));
  67. return FALSE;
  68. }
  69.  
  70. /**
  71. * Delete field
  72. * @return NULL
  73. * @param $key string
  74. **/
  75. function clear($key) {
  76. unset($this->document[$key]);
  77. }
  78.  
  79. /**
  80. * Convert array to mapper object
  81. * @return object
  82. * @param $row array
  83. **/
  84. protected function factory($row) {
  85. $mapper=clone($this);
  86. $mapper->reset();
  87. foreach ($row as $key=>$val)
  88. $mapper->document[$key]=$val;
  89. $mapper->query=array(clone($mapper));
  90. if (isset($mapper->trigger['load']))
  91. \Base::instance()->call($mapper->trigger['load'],$mapper);
  92. return $mapper;
  93. }
  94.  
  95. /**
  96. * Return fields of mapper object as an associative array
  97. * @return array
  98. * @param $obj object
  99. **/
  100. function cast($obj=NULL) {
  101. if (!$obj)
  102. $obj=$this;
  103. return $obj->document;
  104. }
  105.  
  106. /**
  107. * Build query and execute
  108. * @return array
  109. * @param $fields string
  110. * @param $filter array
  111. * @param $options array
  112. * @param $ttl int
  113. **/
  114. function select($fields=NULL,$filter=NULL,array $options=NULL,$ttl=0) {
  115. if (!$options)
  116. $options=array();
  117. $options+=array(
  118. 'group'=>NULL,
  119. 'order'=>NULL,
  120. 'limit'=>0,
  121. 'offset'=>0
  122. );
  123. $fw=\Base::instance();
  124. $cache=\Cache::instance();
  125. if (!($cached=$cache->exists($hash=$fw->hash($this->db->dsn().
  126. $fw->stringify(array($fields,$filter,$options))).'.mongo',
  127. $result)) || !$ttl || $cached[0]+$ttl<microtime(TRUE)) {
  128. if ($options['group']) {
  129. $grp=$this->collection->group(
  130. $options['group']['keys'],
  131. $options['group']['initial'],
  132. $options['group']['reduce'],
  133. array(
  134. 'condition'=>$filter,
  135. 'finalize'=>$options['group']['finalize']
  136. )
  137. );
  138. $tmp=$this->db->selectcollection(
  139. $fw->get('HOST').'.'.$fw->get('BASE').'.'.
  140. uniqid(NULL,TRUE).'.tmp'
  141. );
  142. $tmp->batchinsert($grp['retval'],array('safe'=>TRUE));
  143. $filter=array();
  144. $collection=$tmp;
  145. }
  146. else {
  147. $filter=$filter?:array();
  148. $collection=$this->collection;
  149. }
  150. $this->cursor=$collection->find($filter,$fields?:array());
  151. if ($options['order'])
  152. $this->cursor=$this->cursor->sort($options['order']);
  153. if ($options['limit'])
  154. $this->cursor=$this->cursor->limit($options['limit']);
  155. if ($options['offset'])
  156. $this->cursor=$this->cursor->skip($options['offset']);
  157. $result=array();
  158. while ($this->cursor->hasnext())
  159. $result[]=$this->cursor->getnext();
  160. if ($options['group'])
  161. $tmp->drop();
  162. if ($fw->get('CACHE') && $ttl)
  163. // Save to cache backend
  164. $cache->set($hash,$result,$ttl);
  165. }
  166. $out=array();
  167. foreach ($result as $doc)
  168. $out[]=$this->factory($doc);
  169. return $out;
  170. }
  171.  
  172. /**
  173. * Return records that match criteria
  174. * @return array
  175. * @param $filter array
  176. * @param $options array
  177. * @param $ttl int
  178. **/
  179. function find($filter=NULL,array $options=NULL,$ttl=0) {
  180. if (!$options)
  181. $options=array();
  182. $options+=array(
  183. 'group'=>NULL,
  184. 'order'=>NULL,
  185. 'limit'=>0,
  186. 'offset'=>0
  187. );
  188. return $this->select(NULL,$filter,$options,$ttl);
  189. }
  190.  
  191. /**
  192. * Count records that match criteria
  193. * @return int
  194. * @param $filter array
  195. * @param $ttl int
  196. **/
  197. function count($filter=NULL,$ttl=0) {
  198. $fw=\Base::instance();
  199. $cache=\Cache::instance();
  200. if (!($cached=$cache->exists($hash=$fw->hash($fw->stringify(
  201. array($filter))).'.mongo',$result)) || !$ttl ||
  202. $cached[0]+$ttl<microtime(TRUE)) {
  203. $result=$this->collection->count($filter);
  204. if ($fw->get('CACHE') && $ttl)
  205. // Save to cache backend
  206. $cache->set($hash,$result,$ttl);
  207. }
  208. return $result;
  209. }
  210.  
  211. /**
  212. * Return record at specified offset using criteria of previous
  213. * load() call and make it active
  214. * @return array
  215. * @param $ofs int
  216. **/
  217. function skip($ofs=1) {
  218. $this->document=($out=parent::skip($ofs))?$out->document:array();
  219. if ($this->document && isset($this->trigger['load']))
  220. \Base::instance()->call($this->trigger['load'],$this);
  221. return $out;
  222. }
  223.  
  224. /**
  225. * Insert new record
  226. * @return array
  227. **/
  228. function insert() {
  229. if (isset($this->document['_id']))
  230. return $this->update();
  231. if (isset($this->trigger['beforeinsert']))
  232. \Base::instance()->call($this->trigger['beforeinsert'],
  233. array($this,$pkey));
  234. $this->collection->insert($this->document);
  235. $pkey=array('_id'=>$this->document['_id']);
  236. if (isset($this->trigger['afterinsert']))
  237. \Base::instance()->call($this->trigger['afterinsert'],
  238. array($this,$pkey));
  239. $this->load(array('_id'=>$this->document['_id']));
  240. return $this->document;
  241. }
  242.  
  243. /**
  244. * Update current record
  245. * @return array
  246. **/
  247. function update() {
  248. if (isset($this->trigger['beforeupdate']))
  249. \Base::instance()->call($this->trigger['beforeupdate'],
  250. array($this,$pkey));
  251. $this->collection->update(
  252. $pkey=array('_id'=>$this->document['_id']),
  253. $this->document,
  254. array('upsert'=>TRUE)
  255. );
  256. if (isset($this->trigger['afterupdate']))
  257. \Base::instance()->call($this->trigger['afterupdate'],
  258. array($this,$pkey));
  259. return $this->document;
  260. }
  261.  
  262. /**
  263. * Delete current record
  264. * @return bool
  265. * @param $filter array
  266. **/
  267. function erase($filter=NULL) {
  268. if ($filter)
  269. return $this->collection->remove($filter);
  270. $pkey=array('_id'=>$this->document['_id']);
  271. if (isset($this->trigger['beforeerase']))
  272. \Base::instance()->call($this->trigger['beforeerase'],
  273. array($this,$pkey));
  274. $result=$this->collection->
  275. remove(array('_id'=>$this->document['_id']));
  276. parent::erase();
  277. $this->skip(0);
  278. if (isset($this->trigger['aftererase']))
  279. \Base::instance()->call($this->trigger['aftererase'],
  280. array($this,$pkey));
  281. return $result;
  282. }
  283.  
  284. /**
  285. * Reset cursor
  286. * @return NULL
  287. **/
  288. function reset() {
  289. $this->document=array();
  290. parent::reset();
  291. }
  292.  
  293. /**
  294. * Hydrate mapper object using hive array variable
  295. * @return NULL
  296. * @param $key string
  297. * @param $func callback
  298. **/
  299. function copyfrom($key,$func=NULL) {
  300. $var=\Base::instance()->get($key);
  301. if ($func)
  302. $var=$func($var);
  303. foreach ($var as $key=>$val)
  304. $this->document[$key]=$val;
  305. }
  306.  
  307. /**
  308. * Populate hive array variable with mapper fields
  309. * @return NULL
  310. * @param $key string
  311. **/
  312. function copyto($key) {
  313. $var=&\Base::instance()->ref($key);
  314. foreach ($this->document as $key=>$field)
  315. $var[$key]=$field;
  316. }
  317.  
  318. /**
  319. * Return field names
  320. * @return array
  321. **/
  322. function fields() {
  323. return array_keys($this->document);
  324. }
  325.  
  326. /**
  327. * Return the cursor from last query
  328. * @return object|NULL
  329. **/
  330. function cursor() {
  331. return $this->cursor;
  332. }
  333.  
  334. /**
  335. * Instantiate class
  336. * @return void
  337. * @param $db object
  338. * @param $collection string
  339. **/
  340. function __construct(\DB\Mongo $db,$collection) {
  341. $this->db=$db;
  342. $this->collection=$db->{$collection};
  343. $this->reset();
  344. }
  345.  
  346. }