├── README.md ├── config └── cimongo.php ├── libraries ├── MY_Form_validation.php ├── MY_Session.php └── cimongo │ ├── Cimongo.php │ ├── Cimongo_base.php │ ├── Cimongo_cursor.php │ └── Cimongo_extras.php └── spark.info /README.md: -------------------------------------------------------------------------------- 1 | # PLEASE NOTE, THIS PROJECT IS NO LONGER BEING MAINTAINED 2 | 3 | ### A CodeIgniter library for interact with MongoDb. 4 | --------------------------------------------------- 5 | VERSION 1.3.0 STABLE 6 | 7 | Inspired by https://github.com/alexbilbie/codeigniter-mongodb-library 8 | 9 | A bit more explained documentation will be soon available. 10 | 11 | Install like every other CI library 12 | 13 | --Under development--- 14 | 15 | Available Functions 16 | ------------------- 17 | 18 | ### Selecting Data 19 | 20 | get 21 | get_where 22 | 23 | select 24 | 25 | where -> take a look at the comment in the code for usage details 26 | or_where 27 | where_in 28 | or_where_in 29 | 30 | like 31 | or_like 32 | not_like 33 | or_not_like 34 | 35 | limit 36 | 37 | order_by 38 | 39 | count_all_results 40 | count_all 41 | 42 | ### Query Results 43 | 44 | result 45 | result_array 46 | result_object 47 | 48 | row 49 | row_array 50 | 51 | insert_id 52 | 53 | 54 | ### Result Helper 55 | 56 | num_rows 57 | has_error 58 | 59 | ### Modifying Data 60 | 61 | set 62 | insert 63 | insert_batch 64 | update 65 | update_batch 66 | delete 67 | delete_batch 68 | 69 | ### Extra methods 70 | command 71 | ensure_index 72 | remove_index 73 | remove_all_indexes 74 | list_indexes 75 | get_dbref 76 | create_dbref 77 | where_gt 78 | where_gte 79 | where_lt 80 | where_lte 81 | where_between 82 | where_between_ne 83 | where_ne 84 | where_near 85 | inc 86 | dec 87 | unset_field 88 | add_to_set 89 | push 90 | push_all 91 | pull 92 | pull_all 93 | pop 94 | rename_field 95 | 96 | Author 97 | ------------------- 98 | 99 | ####Alessandro Arnodo 100 | 101 | + [@vesparny](https://twitter.com/vesparny) 102 | 103 | + [http://alessandro.arnodo.net](http://alessandro.arnodo.net) 104 | 105 | + 106 | 107 | -------------------------------------------------------------------------------- /config/cimongo.php: -------------------------------------------------------------------------------- 1 | CI =& get_instance(); 29 | $this->CI->load->library("cimongo/cimongo"); 30 | parent::__construct($rules); 31 | } 32 | 33 | /** 34 | * is_unique 35 | * 36 | */ 37 | public function is_unique($str, $field) 38 | { 39 | list($table, $field)=explode('.', $field); 40 | $query = $this->CI->cimongo->limit(1)->get_where($table, array($field => $str)); 41 | 42 | return $query->num_rows() === 0; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /libraries/MY_Session.php: -------------------------------------------------------------------------------- 1 | CI =& get_instance(); 33 | $this->CI->load->config('cimongo'); 34 | $this->sess_use_mongo = $this->CI->config->item('sess_use_mongo'); 35 | $this->sess_collection_name = $this->CI->config->item('sess_collection_name'); 36 | $this->CI->load->library("cimongo/cimongo"); 37 | parent::__construct(); 38 | 39 | } 40 | 41 | /** 42 | * Fetch the current session data if it exists 43 | * 44 | * @access public 45 | * @return bool 46 | */ 47 | function sess_read() 48 | { 49 | // Fetch the cookie 50 | $session = $this->CI->input->cookie($this->sess_cookie_name); 51 | 52 | // No cookie? Goodbye cruel world!... 53 | if ($session === FALSE) 54 | { 55 | log_message('debug', 'A session cookie was not found.'); 56 | return FALSE; 57 | } 58 | 59 | // Decrypt the cookie data 60 | if ($this->sess_encrypt_cookie == TRUE) 61 | { 62 | $session = $this->CI->encrypt->decode($session); 63 | } 64 | else 65 | { 66 | // encryption was not used, so we need to check the md5 hash 67 | $hash = substr($session, strlen($session)-32); // get last 32 chars 68 | $session = substr($session, 0, strlen($session)-32); 69 | 70 | // Does the md5 hash match? This is to prevent manipulation of session data in userspace 71 | if ($hash !== md5($session.$this->encryption_key)) 72 | { 73 | log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.'); 74 | $this->sess_destroy(); 75 | return FALSE; 76 | } 77 | } 78 | 79 | // Unserialize the session array 80 | $session = $this->_unserialize($session); 81 | 82 | // Is the session data we unserialized an array with the correct format? 83 | if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity'])) 84 | { 85 | $this->sess_destroy(); 86 | return FALSE; 87 | } 88 | 89 | // Is the session current? 90 | if (($session['last_activity'] + $this->sess_expiration) < $this->now) 91 | { 92 | $this->sess_destroy(); 93 | return FALSE; 94 | } 95 | 96 | // Does the IP Match? 97 | if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address()) 98 | { 99 | $this->sess_destroy(); 100 | return FALSE; 101 | } 102 | 103 | // Does the User Agent Match? 104 | if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120))) 105 | { 106 | $this->sess_destroy(); 107 | return FALSE; 108 | } 109 | 110 | // Is there a corresponding session in the DB? 111 | if ($this->sess_use_mongo === TRUE) 112 | { 113 | $this->CI->cimongo->where(array('session_id'=>$session['session_id'])); 114 | 115 | if ($this->sess_match_ip == TRUE) 116 | { 117 | $this->CI->cimongo->where(array('ip_address'=>$session['ip_address'])); 118 | } 119 | 120 | if ($this->sess_match_useragent == TRUE) 121 | { 122 | $this->CI->cimongo->where(array('user_agent'=>$session['user_agent'])); 123 | } 124 | 125 | $query = $this->CI->cimongo->get($this->sess_collection_name); 126 | 127 | // No result? Kill it! 128 | if ($query->num_rows() == 0) 129 | { 130 | $this->sess_destroy(); 131 | return FALSE; 132 | } 133 | 134 | // Is there custom data? If so, add it to the main session array 135 | $row = $query->row(); 136 | if (isset($row->user_data) AND $row->user_data != '') 137 | { 138 | $custom_data = $this->_unserialize($row->user_data); 139 | 140 | if (is_array($custom_data)) 141 | { 142 | foreach ($custom_data as $key => $val) 143 | { 144 | $session[$key] = $val; 145 | } 146 | } 147 | } 148 | } 149 | 150 | // Session is valid! 151 | $this->userdata = $session; 152 | unset($session); 153 | 154 | return TRUE; 155 | } 156 | 157 | 158 | /** 159 | * Write the session data 160 | * 161 | * @access public 162 | * @return void 163 | */ 164 | function sess_write() 165 | { 166 | // Are we saving custom data to the DB? If not, all we do is update the cookie 167 | if ($this->sess_use_mongo === FALSE) 168 | { 169 | $this->_set_cookie(); 170 | return; 171 | } 172 | 173 | // set the custom userdata, the session data we will set in a second 174 | $custom_userdata = $this->userdata; 175 | $cookie_userdata = array(); 176 | 177 | // Before continuing, we need to determine if there is any custom data to deal with. 178 | // Let's determine this by removing the default indexes to see if there's anything left in the array 179 | // and set the session data while we're at it 180 | foreach (array('session_id','ip_address','user_agent','last_activity') as $val) 181 | { 182 | unset($custom_userdata[$val]); 183 | $cookie_userdata[$val] = $this->userdata[$val]; 184 | } 185 | 186 | // Did we find any custom data? If not, we turn the empty array into a string 187 | // since there's no reason to serialize and store an empty array in the DB 188 | if (count($custom_userdata) === 0) 189 | { 190 | $custom_userdata = ''; 191 | } 192 | else 193 | { 194 | // Serialize the custom data array so we can store it 195 | $custom_userdata = $this->_serialize($custom_userdata); 196 | } 197 | 198 | // Run the update query 199 | $this->CI->cimongo->where(array('session_id'=>$this->userdata['session_id'])); 200 | $this->CI->cimongo->update($this->sess_collection_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata)); 201 | 202 | // Write the cookie. Notice that we manually pass the cookie data array to the 203 | // _set_cookie() function. Normally that function will store $this->userdata, but 204 | // in this case that array contains custom data, which we do not want in the cookie. 205 | $this->_set_cookie($cookie_userdata); 206 | } 207 | 208 | /** 209 | * Create a new session 210 | * 211 | * @access public 212 | * @return void 213 | */ 214 | function sess_create() 215 | { 216 | $sessid = ''; 217 | while (strlen($sessid) < 32) 218 | { 219 | $sessid .= mt_rand(0, mt_getrandmax()); 220 | } 221 | 222 | // To make the session ID even more secure we'll combine it with the user's IP 223 | $sessid .= $this->CI->input->ip_address(); 224 | 225 | $this->userdata = array( 226 | 'session_id' => md5(uniqid($sessid, TRUE)), 227 | 'ip_address' => $this->CI->input->ip_address(), 228 | 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), 229 | 'last_activity' => $this->now, 230 | 'user_data' => '' 231 | ); 232 | 233 | 234 | // Save the data to the DB if needed 235 | if ($this->sess_use_mongo === TRUE) 236 | { 237 | $this->CI->cimongo->insert($this->sess_collection_name, $this->userdata); 238 | } 239 | 240 | // Write the cookie 241 | $this->_set_cookie(); 242 | } 243 | 244 | 245 | /** 246 | * Update an existing session 247 | * 248 | * @access public 249 | * @return void 250 | */ 251 | function sess_update() 252 | { 253 | // We only update the session every five minutes by default 254 | if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) 255 | { 256 | return; 257 | } 258 | 259 | // Save the old session id so we know which record to 260 | // update in the database if we need it 261 | $old_sessid = $this->userdata['session_id']; 262 | $new_sessid = ''; 263 | while (strlen($new_sessid) < 32) 264 | { 265 | $new_sessid .= mt_rand(0, mt_getrandmax()); 266 | } 267 | 268 | // To make the session ID even more secure we'll combine it with the user's IP 269 | $new_sessid .= $this->CI->input->ip_address(); 270 | 271 | // Turn it into a hash 272 | $new_sessid = md5(uniqid($new_sessid, TRUE)); 273 | 274 | // Update the session data in the session data array 275 | $this->userdata['session_id'] = $new_sessid; 276 | $this->userdata['last_activity'] = $this->now; 277 | 278 | // _set_cookie() will handle this for us if we aren't using database sessions 279 | // by pushing all userdata to the cookie. 280 | $cookie_data = NULL; 281 | 282 | // Update the session ID and last_activity field in the DB if needed 283 | if ($this->sess_use_mongo === TRUE) 284 | { 285 | // set cookie explicitly to only have our session data 286 | $cookie_data = array(); 287 | foreach (array('session_id','ip_address','user_agent','last_activity') as $val) 288 | { 289 | $cookie_data[$val] = $this->userdata[$val]; 290 | } 291 | 292 | $this->CI->cimongo->where(array("session_id"=>$old_sessid))->update($this->sess_collection_name, array('last_activity' => $this->now, 'session_id' => $new_sessid)); 293 | } 294 | 295 | // Write the cookie 296 | $this->_set_cookie($cookie_data); 297 | } 298 | 299 | /** 300 | * Destroy the current session 301 | * 302 | * @access public 303 | * @return void 304 | */ 305 | function sess_destroy() 306 | { 307 | // Kill the session DB row 308 | if ($this->sess_use_mongo === TRUE AND isset($this->userdata['session_id'])) 309 | { 310 | $this->CI->cimongo->where(array('session_id'=>$this->userdata['session_id'])); 311 | $this->CI->cimongo->delete($this->sess_collection_name); 312 | } 313 | 314 | // Kill the cookie 315 | setcookie( 316 | $this->sess_cookie_name, 317 | addslashes(serialize(array())), 318 | ($this->now - 31500000), 319 | $this->cookie_path, 320 | $this->cookie_domain, 321 | 0 322 | ); 323 | } 324 | 325 | 326 | /** 327 | * Garbage collection 328 | * 329 | * This deletes expired session rows from database 330 | * if the probability percentage is met 331 | * 332 | * @access public 333 | * @return void 334 | */ 335 | function _sess_gc() 336 | { 337 | if ($this->sess_use_mongo != TRUE) 338 | { 339 | return; 340 | } 341 | 342 | srand(time()); 343 | if ((rand() % 100) < $this->gc_probability) 344 | { 345 | $expire = $this->now - $this->sess_expiration; 346 | 347 | 348 | $this->CI->cimongo->where(array("last_activity" =>array('$lt'=>$expire))); 349 | $this->CI->cimongo->delete($this->sess_collection_name); 350 | 351 | log_message('debug', 'Session garbage collection performed.'); 352 | } 353 | } 354 | 355 | 356 | } -------------------------------------------------------------------------------- /libraries/cimongo/Cimongo.php: -------------------------------------------------------------------------------- 1 | db=$this->cimongo 44 | * 45 | */ 46 | public function close() { 47 | 48 | } 49 | 50 | /** 51 | * Get the documents based upon the passed parameters 52 | * 53 | * @since v1.0.0 54 | */ 55 | public function get($collection = "", $limit = FALSE, $offset = FALSE) { 56 | if (empty($collection)) { 57 | //FIXME theow exception instead show error 58 | show_error("In order to retreive documents from MongoDB, a collection name must be passed", 500); 59 | } 60 | $cursor = $this->db->selectCollection($collection)->find($this->wheres, $this->selects); 61 | $cimongo_cursor = new Cimongo_cursor($cursor); 62 | 63 | $this->limit = ($limit !== FALSE && is_numeric($limit)) ? $limit : $this->limit; 64 | if ($this->limit !== FALSE) { 65 | $cimongo_cursor->limit($this->limit); 66 | } 67 | 68 | $this->offset = ($offset !== FALSE && is_numeric($offset)) ? $offset : $this->offset; 69 | if ($this->offset !== FALSE) { 70 | $cimongo_cursor->skip($this->offset); 71 | } 72 | if (!empty($this->sorts) && count($this->sorts) > 0) { 73 | $cimongo_cursor->sort($this->sorts); 74 | } 75 | 76 | $this->_clear(); 77 | 78 | return $cimongo_cursor; 79 | } 80 | 81 | /** 82 | * Get the documents based upon the passed parameters 83 | * 84 | * @since v1.0.0 85 | */ 86 | public function get_where($collection = "", $where = array(), $limit = FALSE, $offset = FALSE) { 87 | return $this->where($where)->get($collection, $limit, $offset); 88 | } 89 | 90 | /** 91 | * Determine which fields to include (_id is always returned) 92 | * 93 | * @since v1.0.0 94 | */ 95 | public function select($includes = array()) { 96 | if (!is_array($includes)) { 97 | $includes = array(); 98 | } 99 | if (!empty($includes)) { 100 | foreach ($includes as $col) { 101 | $this->selects[$col] = TRUE; 102 | } 103 | } 104 | return $this; 105 | } 106 | 107 | /** 108 | * where clause: 109 | * 110 | * Passa an array of field=>value, every condition will be merged in AND statement 111 | * e.g.: 112 | * $this->cimongo->where(array('foo'=> 'bar', 'user'=>'arny')->get("users") 113 | * 114 | * if you need more complex clause you can pass an array composed exactly like mongoDB needs, followed by a boolean TRUE parameter. 115 | * e.g.: 116 | * $where_clause = array( 117 | * '$or'=>array( 118 | * array("user"=>'arny'), 119 | * array("facebook.id"=>array('$gt'=>1,'$lt'=>5000)), 120 | * array('faceboo.usernamek'=>new MongoRegex("/^arny.$/")) 121 | * ), 122 | * email"=>"a.arnodo@gmail.com" 123 | * ); 124 | * 125 | * 126 | * $this->cimongo->where($where_clause, TRUE)->get("users") 127 | * 128 | * @since v1.0.0 129 | * 130 | * 131 | */ 132 | public function where($wheres = array(), $native = FALSE) { 133 | if ($native === TRUE && is_array($wheres)) { 134 | $this->wheres = $wheres; 135 | } elseif (is_array($wheres)) { 136 | foreach ($wheres as $where => $value) { 137 | $this->_where_init($where); 138 | $this->wheres[$where] = $value; 139 | } 140 | } 141 | return $this; 142 | } 143 | 144 | /** 145 | * Get the documents where the value of a $field may be something else 146 | * 147 | * @since v1.0.0 148 | */ 149 | public function or_where($wheres = array()) { 150 | $this->_where_init('$or'); 151 | if (is_array($wheres) && count($wheres) > 0) { 152 | foreach ($wheres as $wh => $val) { 153 | $this->wheres['$or'][] = array($wh => $val); 154 | } 155 | } 156 | return $this; 157 | } 158 | 159 | /** 160 | * Get the documents where the value of a $field is in a given $in array(). 161 | * 162 | * @since v1.0.0 163 | */ 164 | public function where_in($field = "", $in = array()) { 165 | $this->_where_init($field); 166 | $this->wheres[$field]['$in'] = $in; 167 | return $this; 168 | } 169 | 170 | /** 171 | * Get the documents where the value of a $field is not in a given $in array(). 172 | * 173 | * @since v1.0.0 174 | */ 175 | public function where_not_in($field = "", $in = array()) { 176 | $this->_where_init($field); 177 | $this->wheres[$field]['$nin'] = $in; 178 | return $this; 179 | } 180 | 181 | /** 182 | * 183 | * Get the documents where the (string) value of a $field is like a value. The defaults 184 | * allow for a case-insensitive search. 185 | * 186 | * @param $flags 187 | * Allows for the typical regular expression flags: 188 | * i = case insensitive 189 | * m = multiline 190 | * x = can contain comments 191 | * l = locale 192 | * s = dotall, "." matches everything, including newlines 193 | * u = match unicode 194 | * 195 | * @param $enable_start_wildcard 196 | * If set to anything other than TRUE, a starting line character "^" will be prepended 197 | * to the search value, representing only searching for a value at the start of 198 | * a new line. 199 | * 200 | * @param $enable_end_wildcard 201 | * If set to anything other than TRUE, an ending line character "$" will be appended 202 | * to the search value, representing only searching for a value at the end of 203 | * a line. 204 | * 205 | * @usage : $this->cimongo->like('foo', 'bar', 'im', FALSE, TRUE); 206 | * @since v1.0.0 207 | * 208 | */ 209 | public function like($field = "", $value = "", $flags = "i", $enable_start_wildcard = TRUE, $enable_end_wildcard = TRUE) { 210 | $field = (string) trim($field); 211 | $this->_where_init($field); 212 | $value = (string) trim($value); 213 | $value = quotemeta($value); 214 | 215 | if ($enable_start_wildcard !== TRUE) { 216 | $value = "^" . $value; 217 | } 218 | if ($enable_end_wildcard !== TRUE) { 219 | $value .= "$"; 220 | } 221 | $regex = "/$value/$flags"; 222 | $this->wheres[$field] = new MongoRegex($regex); 223 | return $this; 224 | } 225 | 226 | /** 227 | * The same as the aboce but multiple instances are joined by OR: 228 | * 229 | * @since v1.0.0 230 | */ 231 | public function or_like($field, $like = array(),$flags = "i") { 232 | $this->_where_init('$or'); 233 | if (is_array($like) && count($like) > 0) { 234 | foreach ($like as $admitted) { 235 | $this->wheres['$or'][] = array($field => new MongoRegex("/$admitted/$flags")); 236 | } 237 | } else { 238 | $this->wheres['$or'][] = array($field => new MongoRegex("/$like/$flags")); 239 | } 240 | return $this; 241 | } 242 | 243 | /** 244 | * The same as the aboce but multiple instances are joined by NOT LIKE: 245 | * 246 | * @since v1.0.0 247 | */ 248 | public function not_like($field, $like = array()) { 249 | $this->_where_init($field); 250 | if (is_array($like) && count($like) > 0) { 251 | foreach ($like as $admitted) { 252 | $this->wheres[$field]['$nin'][] = new MongoRegex("/$admitted/"); 253 | } 254 | } 255 | return $this; 256 | } 257 | 258 | /** 259 | * 260 | * Sort the documents based on the parameters passed. To set values to descending order, 261 | * you must pass values of either -1, FALSE, 'desc', or 'DESC', else they will be 262 | * set to 1 (ASC). 263 | * 264 | * @usage : $this->cimongo->order_by(array('name' => 'ASC'))->get('users'); 265 | * @since v1.0.0 266 | */ 267 | public function order_by($fields = array()) { 268 | foreach ($fields as $field => $val) { 269 | if ($val === -1 || $val === FALSE || strtolower($val) === 'desc') { 270 | $this->sorts[$field] = -1; 271 | } 272 | if ($val === 1 || $val === TRUE || strtolower($val) === 'asc') { 273 | $this->sorts[$field] = 1; 274 | } 275 | } 276 | return $this; 277 | } 278 | 279 | /** 280 | * 281 | * Count all the documents in a collection 282 | * 283 | * @usage : $this->cimongo->count_all('users'); 284 | * @since v1.0.0 285 | */ 286 | public function count_all($collection = "") { 287 | if (empty($collection)) { 288 | show_error("In order to retreive a count of documents from MongoDB, a collection name must be passed", 500); 289 | } 290 | 291 | $cursor = $this->db->selectCollection($collection)->find(); 292 | $cimongo_cursor = new Cimongo_cursor($cursor); 293 | $count = $cimongo_cursor->count(TRUE); 294 | $this->_clear(); 295 | return $count; 296 | } 297 | 298 | /** 299 | * 300 | * Count the documents based upon the passed parameters 301 | * 302 | * @since v1.0.0 303 | */ 304 | public function count_all_results($collection = "") { 305 | if (empty($collection)) { 306 | show_error("In order to retreive a count of documents from MongoDB, a collection name must be passed", 500); 307 | } 308 | 309 | $cursor = $this->db->selectCollection($collection)->find($this->wheres); 310 | $cimongo_cursor = new Cimongo_cursor($cursor); 311 | if ($this->limit !== FALSE) { 312 | $cimongo_cursor->limit($this->limit); 313 | } 314 | if ($this->offset !== FALSE) { 315 | $cimongo_cursor->skip($this->offset); 316 | } 317 | $this->_clear(); 318 | return $cimongo_cursor->count(TRUE); 319 | } 320 | 321 | /** 322 | * 323 | * Insert a new document into the passed collection 324 | * 325 | * @since v1.0.0 326 | */ 327 | public function insert($collection = "", $insert = array()) { 328 | if (empty($collection)) { 329 | show_error("No Mongo collection selected to insert into", 500); 330 | } 331 | 332 | if (count($insert) == 0) { 333 | show_error("Nothing to insert into Mongo collection or insert is not an array", 500); 334 | } 335 | $this->_inserted_id = FALSE; 336 | try { 337 | $query = $this->db->selectCollection($collection)->insert($insert, array("w" => $this->query_safety)); 338 | if (isset($insert['_id'])) { 339 | $this->_inserted_id = $insert['_id']; 340 | return TRUE; 341 | } else { 342 | return FALSE; 343 | } 344 | } catch (MongoException $e) { 345 | show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500); 346 | } catch (MongoCursorException $e) { 347 | show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500); 348 | } 349 | } 350 | 351 | /** 352 | * 353 | * Insert a multiple new document into the passed collection 354 | * 355 | * @since v1.0.0 356 | */ 357 | public function insert_batch($collection = "", $insert = array()) { 358 | if (empty($collection)) { 359 | show_error("No Mongo collection selected to insert into", 500); 360 | } 361 | if (count($insert) == 0) { 362 | show_error("Nothing to insert into Mongo collection or insert is not an array", 500); 363 | } 364 | try { 365 | $query = $this->db->selectCollection($collection)->batchInsert($insert, array("w" => $this->query_safety)); 366 | if (is_array($query)) { 367 | return $query["err"] === NULL; 368 | } else { 369 | return $query; 370 | } 371 | } catch (MongoException $e) { 372 | show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500); 373 | } catch (MongoCursorException $e) { 374 | show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500); 375 | } catch (MongoCursorTimeoutException $e) { 376 | show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500); 377 | } 378 | } 379 | 380 | /** 381 | * 382 | * Sets a field to a value 383 | * 384 | * @usage: $this->cimongo->where(array('blog_id'=>123))->set(array('posted'=>1)->update('users'); 385 | * @since v1.0.0 386 | */ 387 | public function set($fields = array()) { 388 | if (is_array($fields)) { 389 | $this->_update_init('$set'); 390 | foreach ($fields as $field => $value) { 391 | $this->updates['$set'][$field] = $value; 392 | } 393 | } 394 | return $this; 395 | } 396 | 397 | /** 398 | * 399 | * Update a single document 400 | * 401 | * @since v1.0.0 402 | */ 403 | public function update($collection = "", $data = array(), $options = array()) { 404 | if (empty($collection)) { 405 | show_error("No Mongo collection selected to update", 500); 406 | } 407 | if (is_array($data) && count($data) > 0) { 408 | $this->_update_init('$set'); 409 | $this->updates['$set'] += $data; 410 | } 411 | if (count($this->updates) == 0) { 412 | show_error("Nothing to update in Mongo collection or update is not an array", 500); 413 | } 414 | try { 415 | $options = array_merge(array("w" => $this->query_safety, 'multiple' => FALSE), $options); 416 | $this->db->selectCollection($collection)->update($this->wheres, $this->updates, $options); 417 | $this->_clear(); 418 | return TRUE; 419 | } catch (MongoCursorException $e) { 420 | show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500); 421 | } catch (MongoCursorException $e) { 422 | show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500); 423 | } catch (MongoCursorTimeoutException $e) { 424 | show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500); 425 | } 426 | } 427 | 428 | /** 429 | * 430 | * Update more than one document 431 | * 432 | * @since v1.0.0 433 | */ 434 | public function update_batch($collection = "", $data = array()) { 435 | return $this->update($collection, $data, array('multiple' => TRUE)); 436 | } 437 | 438 | /** 439 | * 440 | * Delete document from the passed collection based upon certain criteria 441 | * 442 | * @since v1.0.0 443 | */ 444 | public function delete($collection = "", $options = array()) { 445 | if (empty($collection)) { 446 | show_error("No Mongo collection selected to delete from", 500); 447 | } 448 | try { 449 | $options = array_merge(array("w" => $this->query_safety), $options); 450 | $this->db->selectCollection($collection)->remove($this->wheres, $options); 451 | $this->_clear(); 452 | return TRUE; 453 | } catch (MongoCursorException $e) { 454 | show_error("Delete of data into MongoDB failed: {$e->getMessage()}", 500); 455 | } catch (MongoCursorTimeoutException $e) { 456 | show_error("Delete of data into MongoDB failed: {$e->getMessage()}", 500); 457 | } 458 | } 459 | 460 | /** 461 | * 462 | * Delete more than one document 463 | * 464 | * @since v1.3.0 465 | */ 466 | public function delete_batch($collection = "", $options = array()) { 467 | return $this->delete($collection, array('justOne' => FALSE)); 468 | } 469 | 470 | /** 471 | * 472 | * Limit results 473 | * 474 | * @since v1.1.0 475 | */ 476 | public function limit($limit = FALSE) { 477 | if ($limit && is_numeric($limit)) { 478 | $this->limit = $limit; 479 | } 480 | return $this; 481 | } 482 | 483 | /** 484 | * 485 | * Returns the last inserted document's id 486 | * 487 | * @since v1.1.0 488 | */ 489 | public function insert_id() { 490 | return $this->_inserted_id; 491 | } 492 | 493 | } 494 | -------------------------------------------------------------------------------- /libraries/cimongo/Cimongo_base.php: -------------------------------------------------------------------------------- 1 | CI =& get_instance(); 57 | $this->connection_string(); 58 | $this->connect(); 59 | } 60 | 61 | /** 62 | * Switch DB 63 | * 64 | * @since v1.0.0 65 | */ 66 | public function switch_db($database = ''){ 67 | if (empty($database)){ 68 | show_error("To switch MongoDB databases, a new database name must be specified", 500); 69 | } 70 | $this->dbname = $database; 71 | try{ 72 | $this->db = $this->connection->{$this->dbname}; 73 | return (TRUE); 74 | }catch (Exception $e){ 75 | show_error("Unable to switch Mongo Databases: {$e->getMessage()}", 500); 76 | } 77 | } 78 | 79 | /** 80 | * Drop DB 81 | * 82 | * @since v1.0.0 83 | */ 84 | public function drop_db($database = ''){ 85 | if (empty($database)){ 86 | show_error('Failed to drop MongoDB database because name is empty', 500); 87 | }else{ 88 | try{ 89 | $this->connection->{$database}->drop(); 90 | return TRUE; 91 | }catch (Exception $e){ 92 | show_error("Unable to drop Mongo database `{$database}`: {$e->getMessage()}", 500); 93 | } 94 | 95 | } 96 | } 97 | 98 | /** 99 | * Drop collection 100 | * 101 | * @since v1.0.0 102 | */ 103 | public function drop_collection($db = "", $col = ""){ 104 | if (empty($db)){ 105 | show_error('Failed to drop MongoDB collection because database name is empty', 500); 106 | } 107 | if (empty($col)){ 108 | show_error('Failed to drop MongoDB collection because collection name is empty', 500); 109 | }else{ 110 | try{ 111 | $this->connection->{$db}->{$col}->drop(); 112 | return TRUE; 113 | }catch (Exception $e) 114 | { 115 | show_error("Unable to drop Mongo collection '$col': {$e->getMessage()}", 500); 116 | } 117 | } 118 | 119 | return $this; 120 | } 121 | 122 | 123 | /** 124 | * Connect to MongoDB 125 | * 126 | * @since v1.0.0 127 | */ 128 | private function connect(){ 129 | $options = array(); 130 | try{ 131 | $this->connection = new MongoClient($this->connection_string, $options); 132 | $this->db = $this->connection->{$this->dbname}; 133 | return $this; 134 | }catch (MongoConnectionException $e){ 135 | show_error("Unable to connect to MongoDB: {$e->getMessage()}", 500); 136 | } 137 | } 138 | 139 | /** 140 | * Create connection string 141 | * 142 | * @since v1.0.0 143 | */ 144 | private function connection_string(){ 145 | $this->CI->config->load("cimongo"); 146 | $this->host = trim($this->CI->config->item('host')); 147 | $this->port = trim($this->CI->config->item('port')); 148 | $this->user = trim($this->CI->config->item('user')); 149 | $this->pass = trim($this->CI->config->item('pass')); 150 | $this->dbname = trim($this->CI->config->item('db')); 151 | $this->query_safety = $this->CI->config->item('query_safety'); 152 | $dbhostflag = (bool)$this->CI->config->item('db_flag'); 153 | 154 | $connection_string = "mongodb://"; 155 | 156 | if (empty($this->host)){ 157 | show_error("The Host must be set to connect to MongoDB", 500); 158 | } 159 | 160 | if (empty($this->dbname)){ 161 | show_error("The Database must be set to connect to MongoDB", 500); 162 | } 163 | 164 | if ( ! empty($this->user) && ! empty($this->pass)){ 165 | $connection_string .= "{$this->user}:{$this->pass}@"; 166 | } 167 | 168 | if (isset($this->port) && ! empty($this->port)){ 169 | $connection_string .= "{$this->host}:{$this->port}"; 170 | }else{ 171 | $connection_string .= "{$this->host}"; 172 | } 173 | 174 | if ($dbhostflag === TRUE){ 175 | $this->connection_string = trim($connection_string) . '/' . $this->dbname; 176 | }else{ 177 | $this->connection_string = trim($connection_string); 178 | } 179 | } 180 | 181 | 182 | /** 183 | * Reset class variables 184 | * 185 | * @since v1.0.0 186 | */ 187 | protected function _clear() 188 | { 189 | $this->selects = array(); 190 | $this->updates = array(); 191 | $this->wheres = array(); 192 | $this->limit = FALSE; 193 | $this->offset = FALSE; 194 | $this->sorts = array(); 195 | } 196 | 197 | /** 198 | * Initializie where clause for the specified field 199 | * 200 | * @since v1.0.0 201 | */ 202 | protected function _where_init($param){ 203 | if (!isset($this->wheres[$param])){ 204 | $this->wheres[$param] = array(); 205 | } 206 | } 207 | 208 | /** 209 | * Initializie update clause for the specified method 210 | * 211 | * @since v1.0.0 212 | */ 213 | protected function _update_init($method){ 214 | if ( ! isset($this->updates[$method])){ 215 | $this->updates[$method] = array(); 216 | } 217 | } 218 | 219 | /** 220 | * Handler for exception 221 | * 222 | * @since v1.1.0 223 | */ 224 | protected function _handle_exception($message,$as_object=TRUE){ 225 | if($as_object){ 226 | $res = new stdClass(); 227 | $res->has_error=TRUE; 228 | $res->error_message=$message; 229 | }else{ 230 | $res = array( 231 | "has_error"=>TRUE, 232 | "error_message"=>$message 233 | ); 234 | } 235 | return $res; 236 | 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /libraries/cimongo/Cimongo_cursor.php: -------------------------------------------------------------------------------- 1 | _cursor = $cursor; 40 | } 41 | 42 | /** 43 | * Returns query results as an object 44 | * 45 | * @since v1.0.0 46 | */ 47 | public function result($as_object=TRUE){ 48 | $result = array(); 49 | try { 50 | foreach ($this->_cursor as $doc){ 51 | $result[]=$as_object?$this->_array_to_object($doc):$doc; 52 | } 53 | }catch (Exception $exception){ 54 | return $this->_handle_exception($exception->getMessage(),$as_object); 55 | } 56 | return $result; 57 | 58 | } 59 | 60 | /** 61 | * Check if cursor is iterable, but maybe this could be done better FIXME 62 | * 63 | * @since v1.1.0 64 | */ 65 | public function has_error(){ 66 | try { 67 | $this->_cursor->next(); 68 | }catch (Exception $exception){ 69 | return $this->_handle_exception($exception->getMessage(),$as_object); 70 | } 71 | return FALSE; 72 | 73 | } 74 | 75 | /** 76 | * Returns query results as an array 77 | * 78 | * @since v1.0.0 79 | */ 80 | public function result_array(){ 81 | return $this->result(FALSE); 82 | 83 | } 84 | 85 | /** 86 | * Returns query results as an object 87 | * 88 | * @since v1.0.0 89 | */ 90 | public function result_object(){ 91 | return $this->result(); 92 | 93 | } 94 | 95 | /** 96 | * Returns the number of the documents fetched 97 | * 98 | * @since v1.0.0 99 | */ 100 | public function num_rows(){ 101 | return $this->count(TRUE); 102 | } 103 | 104 | /** 105 | * Returns the document at the specified index as an object 106 | * 107 | * @since v1.0.0 108 | */ 109 | public function row($index=0, $class=NULL, $as_object=TRUE){ 110 | $size = $this->_cursor->count(); 111 | $this->_cursor->reset(); 112 | $res = array(); 113 | for($i=0;$i<$size;$i++){ 114 | $this->_cursor->next(); 115 | if($i==$index && $index<=$size){ 116 | $res = $as_object?(object)$this->_cursor->current():$this->_cursor->current(); 117 | break; 118 | } 119 | } 120 | return $res; 121 | } 122 | 123 | /** 124 | * Returns the document at the specified index as an array 125 | * 126 | * @since v1.0.0 127 | */ 128 | public function row_array($index=0, $class=NULL){ 129 | return $this->row($index, NULL, FALSE); 130 | } 131 | 132 | /** 133 | * Skip the specified number of documents 134 | * 135 | * @since v1.0.0 136 | */ 137 | public function skip($x = FALSE){ 138 | if ($x !== FALSE && is_numeric($x) && $x >= 1){ 139 | return $this->_cursor->skip((int)$x); 140 | } 141 | return $this->_cursor; 142 | } 143 | 144 | 145 | /** 146 | * Limit results to the specified number 147 | * 148 | * @since v1.0.0 149 | */ 150 | public function limit($x = FALSE){ 151 | if ($x !== FALSE && is_numeric($x) && $x >= 1) 152 | { 153 | return $this->_cursor->limit((int)$x); 154 | } 155 | return $this->_cursor; 156 | } 157 | 158 | /** 159 | * Sort by the field 160 | * 161 | * @since v1.0.0 162 | */ 163 | public function sort($fields) { 164 | return $this->_cursor->sort($fields); 165 | } 166 | 167 | /** 168 | * Count the results 169 | * 170 | * @since v1.0.0 171 | */ 172 | public function count($foundOnly = FALSE) { 173 | $count = array(); 174 | try { 175 | $count = $this->_cursor->count($foundOnly); 176 | }catch (MongoCursorException $exception){ 177 | show_error($exception->getMessage(), 500); 178 | }catch (MongoConnectionException $exception){ 179 | show_error($exception->getMessage(), 500); 180 | } 181 | catch (MongoCursorTimeoutException $exception){ 182 | show_error($exception->getMessage(), 500); 183 | } 184 | return $count; 185 | } 186 | 187 | /** 188 | * Private method to convert an array into an object 189 | * 190 | * @since v1.0.0 191 | */ 192 | private function _array_to_object($array) { 193 | if(!is_array($array)) { 194 | return $array; 195 | } 196 | 197 | $object = new stdClass(); 198 | if (is_array($array) && count($array) > 0) { 199 | foreach ($array as $name=>$value) { 200 | $name = strtolower(trim($name)); 201 | if (!empty($name)) { 202 | $object->$name = $value; 203 | } 204 | } 205 | return $object; 206 | } 207 | else { 208 | return FALSE; 209 | } 210 | } 211 | } -------------------------------------------------------------------------------- /libraries/cimongo/Cimongo_extras.php: -------------------------------------------------------------------------------- 1 | cimongo->command(array('geoNear'=>'buildings', 'near'=>array(53.228482, -0.547847), 'num' => 10, 'nearSphere'=>true)); 47 | * @since v1.0.0 48 | */ 49 | public function command($query = array()){ 50 | try{ 51 | $run = $this->db->command($query); 52 | return $run; 53 | }catch (MongoCursorException $e){ 54 | show_error("MongoDB command failed to execute: {$e->getMessage()}", 500); 55 | } 56 | } 57 | 58 | /** 59 | * Runs a MongoDB Aggregate. 60 | * See the MongoDB documentation for more usage scenarios: 61 | * http://docs.mongodb.org/manual/core/aggregation 62 | * @usage : $this->cimongo->aggregate('users', array(array('$project' => array('_id' => 1)))); 63 | * @since v1.0.0 64 | */ 65 | public function aggregate($collection = "", $opt) { 66 | if (empty($collection)) { 67 | show_error("No Mongo collection selected to insert into", 500); 68 | } 69 | try{ 70 | $c = $this->db->selectCollection($collection); 71 | return $c->aggregate($opt); 72 | } catch (MongoException $e) { 73 | show_error("MongoDB failed: {$e->getMessage()}", 500); 74 | } 75 | } 76 | 77 | /** 78 | * Ensure an index of the keys in a collection with optional parameters. To set values to descending order, 79 | * you must pass values of either -1, FALSE, 'desc', or 'DESC', else they will be 80 | * set to 1 (ASC). 81 | * 82 | * @usage : $this->cimongo->ensure_index($collection, array('first_name' => 'ASC', 'last_name' => -1), array('unique' => TRUE)); 83 | * @since v1.0.0 84 | */ 85 | public function ensure_index($collection = "", $keys = array(), $options = array()){ 86 | if(empty($collection)){ 87 | show_error("No Mongo collection specified to add index to", 500); 88 | } 89 | if(empty($keys) || !is_array($keys)){ 90 | show_error("Index could not be created to MongoDB Collection because no keys were specified", 500); 91 | } 92 | foreach ($keys as $col => $val){ 93 | if($val == -1 || $val === FALSE || strtolower($val) == 'desc'){ 94 | $keys[$col] = -1; 95 | }else{ 96 | $keys[$col] = 1; 97 | } 98 | } 99 | if ($this->db->{$collection}->ensureIndex($keys, $options) == TRUE){ 100 | $this->_clear(); 101 | return $this; 102 | } 103 | else{ 104 | show_error("An error occured when trying to add an index to MongoDB Collection", 500); 105 | } 106 | } 107 | 108 | 109 | /** 110 | * Remove an index of the keys in a collection. To set values to descending order, 111 | * you must pass values of either -1, FALSE, 'desc', or 'DESC', else they will be 112 | * set to 1 (ASC). 113 | * 114 | * @usage : $this->cimongo->remove_index($collection, array('first_name' => 'ASC', 'last_name' => -1)); 115 | * @since v1.0.0 116 | */ 117 | public function remove_index($collection = "", $keys = array()){ 118 | if (empty($collection)) { 119 | show_error("No Mongo collection specified to remove index from", 500); 120 | } 121 | if (empty($keys) || !is_array($keys)) { 122 | show_error("Index could not be removed from MongoDB Collection because no keys were specified", 500); 123 | } 124 | if ($this->db->{$collection}->deleteIndex($keys, $options) == TRUE){ 125 | $this->_clear(); 126 | return $this; 127 | } 128 | else{ 129 | show_error("An error occured when trying to remove an index from MongoDB Collection", 500); 130 | } 131 | } 132 | 133 | /** 134 | * Remove all indexes from a collection 135 | * 136 | * @since v1.0.0 137 | */ 138 | public function remove_all_indexes($collection = ""){ 139 | if (empty($collection)){ 140 | show_error("No Mongo collection specified to remove all indexes from", 500); 141 | } 142 | $this->db->{$collection}->deleteIndexes(); 143 | $this->_clear(); 144 | return $this; 145 | } 146 | 147 | /** 148 | * List all indexes in a collection 149 | * 150 | * @since v1.0.0 151 | */ 152 | public function list_indexes($collection = ""){ 153 | if (empty($collection)){ 154 | show_error("No Mongo collection specified to remove all indexes from", 500); 155 | } 156 | return $this->db->{$collection}->getIndexInfo(); 157 | } 158 | 159 | /** 160 | * Get mongo object from database reference using MongoDBRef 161 | * 162 | * @usage : $this->cimongo->get_dbref($object); 163 | * @since v1.0.0 164 | */ 165 | public function get_dbref($obj){ 166 | if (empty($obj) OR !isset($obj)){ 167 | show_error('To use MongoDBRef::get() ala get_dbref() you must pass a valid reference object', 500); 168 | } 169 | 170 | if ($this->CI->config->item('mongo_return') == 'object'){ 171 | return (object) MongoDBRef::get($this->db, $obj); 172 | } 173 | else{ 174 | return (array) MongoDBRef::get($this->db, $obj); 175 | } 176 | } 177 | 178 | /** 179 | * Create mongo dbref object to store later 180 | * 181 | * @usage : $this->cimongo->create_dbref($collection, $id); 182 | * @since v1.0.0 183 | */ 184 | public function create_dbref($collection = "", $id = "", $database = FALSE ){ 185 | if (empty($collection)) { 186 | show_error("In order to retreive documents from MongoDB, a collection name must be passed", 500); 187 | } 188 | if (empty($id) OR !isset($id)) 189 | { 190 | show_error('To use MongoDBRef::create() ala create_dbref() you must pass a valid id field of the object which to link', 500); 191 | } 192 | 193 | $db = $database ? $database : $this->db; 194 | 195 | if ($this->CI->config->item('mongo_return') == 'object'){ 196 | return (object) MongoDBRef::create($collection, $id, $db); 197 | }else{ 198 | return (array) MongoDBRef::get($this->db, $obj); 199 | } 200 | } 201 | 202 | /** 203 | * Get the documents where the value of a $field is greater than $x 204 | * @since v1.0.0 205 | */ 206 | public function where_gt($field = "", $x){ 207 | $this->_where_init($field); 208 | $this->wheres[$field]['$gt'] = $x; 209 | return $this; 210 | } 211 | 212 | /** 213 | * Get the documents where the value of a $field is greater than or equal to $x 214 | * @since v1.0.0 215 | */ 216 | public function where_gte($field = "", $x){ 217 | $this->_where_init($field); 218 | $this->wheres[$field]['$gte'] = $x; 219 | return $this; 220 | } 221 | 222 | /** 223 | * Get the documents where the value of a $field is less than $x 224 | * @since v1.0.0 225 | */ 226 | public function where_lt($field = "", $x){ 227 | $this->_where_init($field); 228 | $this->wheres[$field]['$lt'] = $x; 229 | return $this; 230 | } 231 | 232 | /** 233 | * Get the documents where the value of a $field is less than or equal to $x 234 | * @since v1.0.0 235 | */ 236 | public function where_lte($field = "", $x){ 237 | $this->_where_init($field); 238 | $this->wheres[$field]['$lte'] = $x; 239 | return $this; 240 | } 241 | 242 | /** 243 | * Get the documents where the value of a $field is between $x and $y 244 | * @since v1.0.0 245 | */ 246 | public function where_between($field = "", $x, $y){ 247 | $this->_where_init($field); 248 | $this->wheres[$field]['$gte'] = $x; 249 | $this->wheres[$field]['$lte'] = $y; 250 | return $this; 251 | } 252 | 253 | /** 254 | * Get the documents where the value of a $field is between but not equal to $x and $y 255 | * @since v1.0.0 256 | */ 257 | public function where_between_ne($field = "", $x, $y){ 258 | $this->_where_init($field); 259 | $this->wheres[$field]['$gt'] = $x; 260 | $this->wheres[$field]['$lt'] = $y; 261 | return $this; 262 | } 263 | 264 | /** 265 | * Get the documents where the value of a $field is not equal to $x 266 | * @since v1.0.0 267 | */ 268 | public function where_ne($field = '', $x){ 269 | $this->_where_init($field); 270 | $this->wheres[$field]['$ne'] = $x; 271 | return $this; 272 | } 273 | 274 | /** 275 | * Get the documents nearest to an array of coordinates (collection must have a geospatial index) 276 | * @since v1.0.0 277 | */ 278 | function where_near($field = '', $co = array()){ 279 | $this->__where_init($field); 280 | $this->where[$what]['$near'] = $co; 281 | return $this; 282 | } 283 | 284 | /** 285 | * Increments the value of a field 286 | * @since v1.0.0 287 | */ 288 | public function inc($fields = array(), $value = 0){ 289 | $this->_update_init('$inc'); 290 | if (is_string($fields)){ 291 | $this->updates['$inc'][$fields] = $value; 292 | }elseif(is_array($fields)){ 293 | foreach ($fields as $field => $value){ 294 | $this->updates['$inc'][$field] = $value; 295 | } 296 | } 297 | return $this; 298 | } 299 | 300 | /** 301 | * Decrements the value of a field 302 | * @since v1.0.0 303 | */ 304 | public function dec($fields = array(), $value = 0){ 305 | $this->_update_init('$dec'); 306 | if (is_string($fields)){ 307 | $this->updates['$dec'][$fields] = $value; 308 | }elseif (is_array($fields)){ 309 | foreach ($fields as $field => $value){ 310 | $this->updates['$dec'][$field] = $value; 311 | } 312 | } 313 | return $this; 314 | } 315 | 316 | /** 317 | * Unset the value of a field(s) 318 | * @since v1.0.0 319 | */ 320 | 321 | public function unset_field($fields){ 322 | $this->_update_init('$unset'); 323 | if (is_string($fields)){ 324 | $this->updates['$unset'][$fields] = 1; 325 | }elseif (is_array($fields)){ 326 | foreach ($fields as $field) { 327 | $this->updates['$unset'][$field] = 1; 328 | } 329 | } 330 | return $this; 331 | } 332 | 333 | /** 334 | * Adds value to the array only if its not in the array already 335 | * 336 | * @usage: $this->cimongo->where(array('blog_id'=>123))->addtoset('tags', 'php')->update('blog_posts'); 337 | * @usage: $this->cimongo->where(array('blog_id'=>123))->addtoset('tags', array('php', 'codeigniter', 'mongodb'))->update('blog_posts'); 338 | * @since v1.0.0 339 | */ 340 | public function addtoset($field, $values){ 341 | $this->_update_init('$addToSet'); 342 | if (is_string($values)){ 343 | $this->updates['$addToSet'][$field] = $values; 344 | }elseif (is_array($values)){ 345 | $this->updates['$addToSet'][$field] = array('$each' => $values); 346 | } 347 | return $this; 348 | } 349 | 350 | /** 351 | * Pushes values into a field (field must be an array) 352 | * 353 | * @usage: $this->cimongo->where(array('blog_id'=>123))->push('comments', array('text'=>'Hello world'))->update('blog_posts'); 354 | * @usage: $this->cimongo->where(array('blog_id'=>123))->push(array('comments' => array('text'=>'Hello world')), 'viewed_by' => array('Alex')->update('blog_posts'); 355 | * @since v1.0.0 356 | */ 357 | 358 | public function push($fields, $value = array()){ 359 | $this->_update_init('$push'); 360 | if (is_string($fields)){ 361 | $this->updates['$push'][$fields] = $value; 362 | }elseif (is_array($fields)){ 363 | foreach ($fields as $field => $value){ 364 | $this->updates['$push'][$field] = $value; 365 | } 366 | } 367 | return $this; 368 | } 369 | 370 | /** 371 | * Pushes ALL values into a field (field must be an array) 372 | * 373 | * @since v1.0.0 374 | */ 375 | public function push_all($fields, $value = array()) { 376 | $this->_update_init('$pushAll'); 377 | if (is_string($fields)){ 378 | $this->updates['$pushAll'][$fields] = $value; 379 | }elseif (is_array($fields)){ 380 | foreach ($fields as $field => $value){ 381 | $this->updates['$pushAll'][$field] = $value; 382 | } 383 | } 384 | return $this; 385 | } 386 | 387 | /** 388 | * Pops the last value from a field (field must be an array 389 | * 390 | * @usage: $this->cimongo->where(array('blog_id'=>123))->pop('comments')->update('blog_posts'); 391 | * @usage: $this->cimongo->where(array('blog_id'=>123))->pop(array('comments', 'viewed_by'))->update('blog_posts'); 392 | * @since v1.0.0 393 | */ 394 | public function pop($field){ 395 | $this->_update_init('$pop'); 396 | if (is_string($field)){ 397 | $this->updates['$pop'][$field] = -1; 398 | } 399 | elseif (is_array($field)){ 400 | foreach ($field as $pop_field){ 401 | $this->updates['$pop'][$pop_field] = -1; 402 | } 403 | } 404 | return $this; 405 | } 406 | 407 | /** 408 | * Removes by an array by the value of a field 409 | * 410 | * @usage: $this->cimongo->pull('comments', array('comment_id'=>123))->update('blog_posts'); 411 | * @since v1.0.0 412 | */ 413 | public function pull($field = "", $value = array()){ 414 | $this->_update_init('$pull'); 415 | $this->updates['$pull'] = array($field => $value); 416 | return $this; 417 | } 418 | 419 | /** 420 | * Removes ALL by an array by the value of a field 421 | * 422 | * @since v1.0.0 423 | */ 424 | public function pull_all($field = "", $value = array()){ 425 | $this->_update_init('$pullAll'); 426 | $this->updates['$pullAll'] = array($field => $value); 427 | return $this; 428 | } 429 | 430 | /** 431 | * Rename a field 432 | * 433 | * @since v1.0.0 434 | */ 435 | public function rename_field($old, $new){ 436 | $this->_update_init('$rename'); 437 | $this->updates['$rename'][] = array($old => $new); 438 | return $this; 439 | } 440 | } 441 | -------------------------------------------------------------------------------- /spark.info: -------------------------------------------------------------------------------- 1 | name: cimongo 2 | version: 1.3.0 3 | compatibility: 2.1.0 4 | tags: ["mongodb", "database", "nosql", "active record"] --------------------------------------------------------------------------------