PageRenderTime 32ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/couchDocument.php

https://github.com/voitto/structal.todos
PHP | 396 lines | 256 code | 17 blank | 123 comment | 9 complexity | 24535d70a14a37f759fbeab3e66400e1 MD5 | raw file
  1. <?PHP
  2. /*
  3. Copyright (C) 2009 Mickael Bailly
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. */
  16. class couchDocument {
  17. /**
  18. * @var stdClass object internal data
  19. */
  20. protected $__couch_data = NULL;
  21. /**
  22. *class constructor
  23. *
  24. * @param couchClient $client couchClient connection object
  25. *
  26. */
  27. function __construct(couchClient $client) {
  28. $this->__couch_data = new stdClass();
  29. $this->__couch_data->client = $client;
  30. $this->__couch_data->fields = new stdClass();
  31. $this->__couch_data->autocommit = true;
  32. }
  33. /**
  34. * load a CouchDB document from the CouchDB server
  35. *
  36. * @param string $id CouchDB document ID
  37. * @return couchDocument $this
  38. */
  39. public function load ( $id ) {
  40. if ( !strlen($id) ) throw new InvalidArgumentException("No id given");
  41. $this->__couch_data->fields = $this->__couch_data->client->getDoc($id);
  42. return $this;
  43. }
  44. /**
  45. * Set the auto-commit mode (default true)
  46. *
  47. * If set to false, you should explicitely call the record() method :
  48. * <code>
  49. * $couchdoc->setAutocommit(false);
  50. * $couchdoc->somefield = "foo";
  51. * $couchdoc->someotherfield = "bar";
  52. * $couchdoc->record();
  53. * </code>
  54. *
  55. * @param boolean $commit turn on or off the autocommit feature
  56. * @return couchDocument $this
  57. */
  58. public function setAutocommit($commit) {
  59. $this->__couch_data->autocommit = (boolean)true;
  60. return $this;
  61. }
  62. /**
  63. * get current auto-commit state (on or off)
  64. *
  65. * @return boolean true if auto-commit is enabled
  66. */
  67. public function getAutocommit() {
  68. return $this->__couch_data->autocommit;
  69. }
  70. /**
  71. * load a CouchDB document from a PHP object
  72. *
  73. * note that this method clones the object given in argument
  74. *
  75. * @param object $doc CouchDB document (should have $doc->_id , $doc->_rev, ...)
  76. * @return couchDocument $this
  77. */
  78. public function loadFromObject($doc) {
  79. $this->__couch_data->fields = clone $doc;
  80. return $this;
  81. }
  82. /**
  83. * load a document in a couchDocument object and return it
  84. *
  85. * @static
  86. * @param couchClient $client couchClient instance
  87. * @param string $id id of the document to load
  88. * @return couchDocument couch document loaded with data of document $id
  89. */
  90. public static function getInstance(couchClient $client,$id) {
  91. $back = new couchDocument($client);
  92. return $back->load($id);
  93. }
  94. /**
  95. * returns all defined keys in this document
  96. *
  97. * @return array list of keys available in this document
  98. */
  99. public function getKeys ( ) {
  100. return array_keys(get_object_vars($this->__couch_data->fields));
  101. }
  102. /**
  103. * returns all fields (key => values) of this document
  104. *
  105. * @return object all fields of the document
  106. */
  107. public function getFields () {
  108. return clone $this->__couch_data->fields;
  109. }
  110. /**
  111. * returns document URI
  112. *
  113. * example : couch.server.com:5984/mydb/thisdoc
  114. *
  115. * @return string document URI
  116. */
  117. public function getUri() {
  118. return $this->__couch_data->client->getDatabaseUri().'/'.$this->id();
  119. }
  120. /**
  121. * returns document id (or null)
  122. *
  123. * @return string document id
  124. */
  125. public function id() {
  126. return $this->get('_id');
  127. }
  128. /**
  129. * returns value of field $key
  130. *
  131. * @param string $key field name
  132. * @return mixed field value (or null)
  133. */
  134. public function get ( $key ) {
  135. //echo "get for $key\n";
  136. $key = (string)$key;
  137. if (!strlen($key) ) throw new InvalidArgumentException("No key given");
  138. return property_exists( $this->__couch_data->fields,$key ) ? $this->__couch_data->fields->$key : NULL;
  139. }
  140. /**
  141. * PHP magic method : getter
  142. *
  143. * @see get()
  144. */
  145. public function __get ( $key ) {
  146. return $this->get($key);
  147. }
  148. /**
  149. * set one field to a value
  150. *
  151. * does not update the database
  152. *
  153. * @param string $key field name
  154. * @param mixed $value field value
  155. * @return boolean TRUE
  156. */
  157. protected function setOne ($key, $value ) {
  158. $key = (string)$key;
  159. if ( !strlen($key) ) throw new InvalidArgumentException("property name can't be empty");
  160. if ( $key == '_rev' ) throw new InvalidArgumentException("Can't set _rev field");
  161. if ( $key == '_id' AND $this->get('_id') ) throw new InvalidArgumentException("Can't set _id field because it's already set");
  162. if ( substr($key,0,1) == '_' AND !in_array($key,couchClient::$allowed_underscored_properties) )
  163. throw new InvalidArgumentException("Property $key can't begin with an underscore");
  164. //echo "setting $key to ".print_r($value,TRUE)."<BR>\n";
  165. $this->__couch_data->fields->$key = $value;
  166. return TRUE;
  167. }
  168. /**
  169. * record the object to the database
  170. *
  171. *
  172. */
  173. public function record() {
  174. foreach ( couchClient::$underscored_properties_to_remove_on_storage as $key ) {
  175. if ( property_exists($this->__couch_data->fields,$key) ) {
  176. unset( $this->__couch_data->fields->$key );
  177. }
  178. }
  179. $response = $this->__couch_data->client->storeDoc($this->__couch_data->fields);
  180. $this->__couch_data->fields->_id = $response->id;
  181. $this->__couch_data->fields->_rev = $response->rev;
  182. }
  183. /**
  184. * set document fields
  185. *
  186. * this method store the object in the database !
  187. *
  188. * there is 2 ways to use it. Set one field :
  189. * <code>
  190. * $this->set('some_field','some value');
  191. * </code>
  192. *
  193. * or set multiple fields in one go :
  194. * <code>
  195. * $this->set( array('some_field'=>'some value','some_other_field'=>'another value') );
  196. * </code>
  197. *
  198. * @param string|array $key
  199. * @param mixed $value
  200. *
  201. */
  202. public function set ( $key , $value = NULL ) {
  203. if ( func_num_args() == 1 ) {
  204. if ( !is_array($key) AND !is_object($key) ) throw new InvalidArgumentException("When second argument is null, first argument should ba an array or an object");
  205. foreach ( $key as $one_key => $one_value ) {
  206. $this->setOne($one_key,$one_value);
  207. }
  208. } else {
  209. $this->setOne($key,$value);
  210. }
  211. if ( $this->__couch_data->autocommit ) {
  212. $this->record();
  213. }
  214. return TRUE;
  215. }
  216. /**
  217. * PHP automagic setter
  218. *
  219. * modify a document property and store to the Server
  220. *
  221. * @link http://php.net/__set
  222. *
  223. * @param string $key name of the property to set
  224. * @param mixed $value property value
  225. */
  226. public function __set( $key , $value ) {
  227. return $this->set($key,$value);
  228. }
  229. /**
  230. * PHP automagic isset'er
  231. *
  232. *
  233. * @link http://php.net/__isset
  234. *
  235. * @param string $key name of the property to test
  236. */
  237. public function __isset($key) {
  238. return property_exists($this->__couch_data->fields,$key);
  239. }
  240. /**
  241. * deletes a document property
  242. *
  243. * @param string $key the key to remove
  244. * @return boolean whether the removal process ran successfully
  245. */
  246. public function remove($key) {
  247. $key = (string)$key;
  248. if ( !strlen($key) ) throw new InvalidArgumentException("Can't remove a key without name");
  249. if ( $key == '_id' OR $key == '_rev' ) return FALSE;
  250. if ( isset($this->$key) ) {
  251. unset($this->__couch_data->fields->$key);
  252. $this->record();
  253. }
  254. return TRUE;
  255. }
  256. /**
  257. * PHP automagic unset'er
  258. *
  259. * @see remove()
  260. * @param string $key the property to delete
  261. * @return boolean whether the removal process ran successfully
  262. */
  263. public function __unset($key) {
  264. return $this->remove($key);
  265. }
  266. /**
  267. * Replicates document on another couchDB database
  268. *
  269. * @param string $url the database to replicate to ( eg. "http://localhost:5984/foo" or "foo" )
  270. * @param boolean $create_target if set to true, target database will be created if needed
  271. * @return boolean tell if document replication succeded
  272. */
  273. public function replicateTo($url, $create_target = false) {
  274. echo "replicateTo : ".$this->_id.", $url\n";
  275. if ( !isset($this->_id) ) {
  276. throw new InvalidArgumentException("Can't replicate a document without id");
  277. }
  278. if ( !class_exists("couchReplicator") ) {
  279. return false;
  280. }
  281. $r = new couchReplicator($this->__couch_data->client);
  282. if ( $create_target ) {
  283. $r->create_target();
  284. }
  285. try {
  286. $res = $r ->doc_ids( array( $this->_id ) )
  287. ->to($url);
  288. } catch ( Exception $e ) {
  289. return false;
  290. }
  291. print_r($res);
  292. return true;
  293. }
  294. /**
  295. * Replicates document on another couchDB database
  296. *
  297. * @param string $id id of the document to replicate
  298. * @param string $url the database to replicate from ( eg. "http://localhost:5984/foo" or "foo" )
  299. * @param boolean $create_target if set to true, target database will be created if needed
  300. * @return boolean tell if document replication succeded
  301. */
  302. public function replicateFrom($id, $url, $create_target = false) {
  303. echo "replicateFrom : $id, $url\n";
  304. if ( !class_exists("couchReplicator") ) {
  305. return false;
  306. }
  307. $r = new couchReplicator($this->__couch_data->client);
  308. if ( $create_target ) {
  309. $r->create_target();
  310. }
  311. $r->doc_ids( array( $id ) )->from($url);
  312. $this->load($id);
  313. return true;
  314. }
  315. /**
  316. * Attach a file to a document
  317. *
  318. *
  319. * @param string $file the attachment file (local storage)
  320. * @param string $content_type the attachment content-type (defaults to 'application/octet-stream')
  321. * @param string $filename the attachment filename. If not specified, the basename of "$file" will be used
  322. * @return object CouchDB attachment storage response
  323. */
  324. public function storeAttachment($file, $content_type = 'application/octet-stream',$filename = null) {
  325. $back = $this->__couch_data->client->storeAttachment($this,$file,$content_type,$filename);
  326. $this->load($this->_id);
  327. return $back;
  328. }
  329. /**
  330. * Attach data as a document attachment
  331. *
  332. *
  333. * @param string $data the attachment contents
  334. * @param string $filename the attachment filename.
  335. * @param string $content_type the attachment content-type (defaults to 'application/octet-stream')
  336. * @return object CouchDB attachment storage response
  337. */
  338. public function storeAsAttachment ($data,$filename,$content_type = 'application/octet-stream') {
  339. $back = $this->__couch_data->client->storeAsAttachment($this,$data,$filename,$content_type);
  340. $this->load($this->_id);
  341. return $back;
  342. }
  343. /**
  344. * Deletes an attachment
  345. *
  346. * @param string $attachment_name name of the document attachment
  347. * @return object CouchDB attachment removal response
  348. */
  349. public function deleteAttachment ($attachment_name) {
  350. $back = $this->__couch_data->client->deleteAttachment( $this , $attachment_name );
  351. $this->load($this->_id);
  352. return $back;
  353. }
  354. /**
  355. * returns the URI of a document attachment
  356. *
  357. * @param string $attachment_name the name of the attachment (relative to the document)
  358. * @return string the attachment URI
  359. */
  360. public function getAttachmentUri ($attachment_name ) {
  361. return $this->getUri().'/'.$attachment_name;
  362. }
  363. }