Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

new version includes per-collection sharding

  • Loading branch information...
commit 00b3385e02fd662207ec14104721e59d8c281a7e 1 parent 4202beb
Ian White authored September 28, 2010
224  Db.php
@@ -5,25 +5,108 @@
5 5
  *
6 6
  * @package SimpleMongoPhp
7 7
  * @author Ian White (ibwhite@gmail.com)
8  
- * @version 1.0
  8
+ * @version 1.2
9 9
  *
10  
- * Copyright 2009 Ian White
11  
- * 
12  
- * Licensed under the Apache License, Version 2.0 (the "License");
13  
- * you may not use this file except in compliance with the License.
14  
- * You may obtain a copy of the License at
15  
- * 
16  
- *     http://www.apache.org/licenses/LICENSE-2.0
  10
+ * This is a simple library to wrap around the Mongo API and make it a little more convenient
  11
+ * to use for a PHP web application.
17 12
  *
18  
- * Unless required by applicable law or agreed to in writing, software
19  
- * distributed under the License is distributed on an "AS IS" BASIS,
20  
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  
- * See the License for the specific language governing permissions and
22  
- * limitations under the License.
23  
- *   
  13
+ * To set up, all you need to do is:
  14
+ *    - include() or require() this file
  15
+ *    - call Db::addConnection()
  16
+ *
  17
+ * Example usage:
  18
+ *   $mongo = new Mongo();
  19
+ *   Db::addConnection($mongo, 'lost');
  20
+ *
  21
+ *   Db::drop('people');
  22
+ *   Db::batchInsert('people', array(
  23
+ *     array('name' => 'Jack', 'sex' => 'M', 'goodguy' => true),
  24
+ *     array('name' => 'Kate', 'sex' => 'F', 'goodguy' => true),
  25
+ *     array('name' => 'Locke', 'sex' => 'M', 'goodguy' => true),
  26
+ *     array('name' => 'Hurley', 'sex' => 'M', 'goodguy' => true),
  27
+ *     array('name' => 'Ben', 'sex' => 'M', 'goodguy' => false),
  28
+ *   ));
  29
+ *   foreach (Db::find('people', array('goodguy' => true), array('sort' => array('name' => 1))) as $p) {
  30
+ *     echo $p['name'] " is a good guy!\n";
  31
+ *   }
  32
+ *   $ben = Db::findOne('people', array('name' => 'Ben'));
  33
+ *   $locke = Db::findOne('people', array('name' => 'Locke'));
  34
+ *   $ben['enemy'] = Db::createRef('people', $locke);
  35
+ *   $ben['goodguy'] = null;
  36
+ *   Db::save('people', $ben);
  37
+ *
  38
+ * See the Dbo.php class for how you could do the same thing with data objects.
  39
+ *
  40
+ * This library may be freely distributed and modified for any purpose.
24 41
  **/
25  
- 
26 42
 class Db {
  43
+    static $connections;
  44
+    static $read_slave = false;
  45
+
  46
+    static function getConnectionInfo($collection = null, $read_only = false) {
  47
+        $info = null;
  48
+
  49
+        // in read-only mode, check for a slave config if set to read slave
  50
+        if ($read_only && self::$read_slave) {
  51
+            if (isset(self::$connections["$collection/slave"])) {
  52
+                $info = self::$connections["$collection/slave"];
  53
+            } else if (isset(self::$connections['/slave'])) {
  54
+                $info = self::$connections['/slave'];
  55
+            }
  56
+        }
  57
+
  58
+        if (!$info) {
  59
+            if (isset(self::$connections[$collection])) {
  60
+                $info = self::$connections[$collection];
  61
+            } else if (isset(self::$connections[''])) {
  62
+                $info = self::$connections[''];
  63
+            } else if (isset($GLOBALS['mongo'])) {
  64
+                $info = array($GLOBALS['mongo'], MONGODB_NAME); // backwards compat
  65
+            } else {
  66
+                throw new Exception('No connection configuration, call Db::addConnection()');
  67
+            }
  68
+        }
  69
+
  70
+        return $info;
  71
+    }
  72
+
  73
+    static function getDb($collection, $read_only = false) {
  74
+        $info = self::getConnectionInfo($collection, $read_only);
  75
+        list($mongo, $db_name) = $info;
  76
+        if (!$mongo->connected) {
  77
+            $mongo->connect();
  78
+        }
  79
+        return $mongo->selectDB($db_name);
  80
+    }
  81
+
  82
+    static function getCollection($collection, $read_only = false) {
  83
+        $info = self::getConnectionInfo($collection, $read_only);
  84
+        list($mongo, $db_name) = $info;
  85
+        if (!$mongo->connected) {
  86
+            $mongo->connect();
  87
+        }
  88
+        return $mongo->selectCollection($db_name, $collection);
  89
+    }
  90
+
  91
+    static function addConnection($mongo, $db_name, $collections = null, $slave = false) {
  92
+        $append = $slave ? '/slave' : '';
  93
+        if (!$collections) {
  94
+            self::$connections[$append] = array($mongo, $db_name);
  95
+        } else {
  96
+            foreach ($collections as $c) {
  97
+                self::$connections["$c$append"] = array($mongo, $db_name);
  98
+            }
  99
+        }
  100
+    }
  101
+
  102
+    static function addSlaveConnection($mongo, $db_name, $collections = null) {
  103
+        self::addConnection($mongo, $db_name, $collections, true);
  104
+    }
  105
+    
  106
+    static function readSlave($setting = true) {
  107
+        self::$read_slave = $setting;
  108
+    }
  109
+    
27 110
     /**
28 111
      * Returns a MongoId from a string, MongoId, array, or Dbo object
29 112
      *
@@ -74,8 +157,7 @@ static function createRef($collection, $id) {
74 157
      * @return array
75 158
      **/
76 159
     static function getRef($dbref) {
77  
-        global $mongo;
78  
-        $db = $mongo->selectDB(MONGODB_NAME);
  160
+        $db = self::getDb($dbref['$ref'], true);
79 161
         return $db->getDBRef($dbref);
80 162
     }
81 163
 
@@ -117,17 +199,16 @@ static function expandRefs($value) {
117 199
      * @return MongoCursor
118 200
      **/
119 201
     static function find($collection, $query = array(), $options = array()) {
120  
-        global $mongo;
121  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  202
+        $col = self::getCollection($collection, true);
122 203
         $fields = isset($options['fields']) ? $options['fields'] : array();
123 204
         $result = $col->find($query, $fields);
124  
-        if (isset($options['sort'])) {
  205
+        if (isset($options['sort']) && $options['sort'] !== null) {
125 206
             $result->sort($options['sort']);
126 207
         }
127  
-        if (isset($options['limit'])) {
  208
+        if (isset($options['limit']) && $options['limit'] !== null) {
128 209
             $result->limit($options['limit']);
129 210
         }
130  
-        if (isset($options['skip'])) {
  211
+        if (isset($options['skip']) && $options['skip'] !== null) {
131 212
             $result->skip($options['skip']);
132 213
         }
133 214
         return $result;
@@ -197,8 +278,7 @@ static function findAssoc($collection, $key_field, $value_field, $query = array(
197 278
      * @return array
198 279
      **/
199 280
     static function findOne($collection, $id) {
200  
-        global $mongo;
201  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  281
+        $col = self::getCollection($collection, true);
202 282
         if (!is_array($id)) {
203 283
             $id = array('_id' => self::id($id));
204 284
         }
@@ -213,8 +293,7 @@ static function findOne($collection, $id) {
213 293
      * @return integer
214 294
      **/
215 295
     static function count($collection, $query = array()) {
216  
-        global $mongo;
217  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  296
+        $col = self::getCollection($collection, true);
218 297
         if ($query) {
219 298
             $res = $col->find($query);
220 299
             return $res->count();
@@ -231,10 +310,19 @@ static function count($collection, $query = array()) {
231 310
      * @return boolean
232 311
      **/
233 312
     static function save($collection, $data) {
234  
-        global $mongo;
235  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  313
+        $col = self::getCollection($collection);
236 314
         return $col->save($data);
237 315
     }
  316
+    
  317
+    static function insert($collection, $data) {
  318
+        $col = self::getCollection($collection);
  319
+        return $col->insert($data);
  320
+    }
  321
+
  322
+    static function lastError($collection = null, $read_only = false) {
  323
+        $db = self::getDb($collection, $read_only);
  324
+        return $db->lastError();
  325
+    }    
238 326
 
239 327
     /**
240 328
      * Shortcut for MongoCollection's update() method
@@ -245,10 +333,37 @@ static function save($collection, $data) {
245 333
      * @param boolean $upsert
246 334
      * @return boolean
247 335
      **/
248  
-    static function update($collection, $criteria, $newobj, $upsert = false) {
249  
-        global $mongo;
250  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
251  
-        return $col->update($criteria, $newobj, $upsert);
  336
+    static function update($collection, $criteria, $newobj, $options = array()) {
  337
+        $col = self::getCollection($collection);
  338
+        if ($options === true) {
  339
+            $options = array('upsert' => true);
  340
+        }
  341
+        if (!isset($options['multiple'])) {
  342
+            $options['multiple'] = false;
  343
+        }
  344
+        return $col->update($criteria, $newobj, $options);
  345
+    }
  346
+    
  347
+    static function updateConcurrent($collection, $criteria, $newobj, $options = array()) {
  348
+        $col = self::getCollection($collection);
  349
+        if (!isset($options['multiple'])) {
  350
+            $options['multiple'] = false;
  351
+        }
  352
+        $i = 0;
  353
+        foreach ($col->find($criteria, array('fields' => array('_id' => 1))) as $obj) {
  354
+            $col->update(array('_id' => $obj['_id']), $newobj);
  355
+            if (empty($options['multiple'])) {
  356
+                return;
  357
+            }
  358
+            if (!empty($options['count_mod']) && $i % $options['count_mod'] == 0) {
  359
+                if (!empty($options['count_callback'])) {
  360
+                    call_user_func($options['count_callback'], $i);
  361
+                } else {
  362
+                    echo '.';
  363
+                }
  364
+            }
  365
+            $i++;
  366
+        }
252 367
     }
253 368
 
254 369
     /**
@@ -272,8 +387,7 @@ static function upsert($collection, $criteria, $newobj) {
272 387
      * @return boolean
273 388
      **/
274 389
     static function remove($collection, $criteria, $just_one = false) {
275  
-        global $mongo;
276  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  390
+        $col = self::getCollection($collection);
277 391
         if (!is_array($criteria)) {
278 392
             $criteria = array('_id' => self::id($criteria));
279 393
         }
@@ -287,8 +401,7 @@ static function remove($collection, $criteria, $just_one = false) {
287 401
      * @return boolean
288 402
      **/
289 403
     static function drop($collection) {
290  
-        global $mongo;
291  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  404
+        $col = self::getCollection($collection);
292 405
         return $col->drop();
293 406
     }
294 407
 
@@ -300,11 +413,15 @@ static function drop($collection) {
300 413
      * @return boolean
301 414
      **/
302 415
     static function batchInsert($collection, $array) {
303  
-        global $mongo;
304  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  416
+        $col = self::getCollection($collection);
305 417
         return $col->batchInsert($array);
306 418
     }
307 419
 
  420
+    static function group($collection, array $keys, array $initial, $reduce, array $condition = array()) {
  421
+        $col = self::getCollection($collection, true);
  422
+        return $col->group($keys, $initial, $reduce, $condition);
  423
+    }
  424
+
308 425
     /**
309 426
      * Shortcut for MongoCollection's ensureIndex() method
310 427
      *
@@ -312,32 +429,21 @@ static function batchInsert($collection, $array) {
312 429
      * @param array $keys
313 430
      * @return boolean
314 431
      **/
315  
-    static function ensureIndex($collection, $keys) {
316  
-        global $mongo;
317  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
318  
-        return $col->ensureIndex($keys);
  432
+    static function ensureIndex($collection, $keys, $options = array()) {
  433
+        $col = self::getCollection($collection);
  434
+        return $col->ensureIndex($keys, $options);
319 435
     }
320 436
 
321 437
     /**
322  
-     * Ensure a unique index (there is no direct way to do this in the MongoCollection API now)
  438
+     * Ensure a unique index
323 439
      *
324 440
      * @param string $collection
325 441
      * @param array $keys
326 442
      * @return boolean
327 443
      **/
328  
-    static function ensureUniqueIndex($collection, $keys) {
329  
-        global $mongo;
330  
-        $name_parts = array();
331  
-        foreach ($keys as $k => $v) {
332  
-            $name_parts[] = $k;
333  
-            $name_parts[] = $v;
334  
-        }
335  
-        $name = implode('_', $name_parts);
336  
-        $col = $mongo->selectCollection(MONGODB_NAME, 'system.indexes');
337  
-        $col->save(array('ns' => MONGODB_NAME . ".$collection",
338  
-                         'key' => $keys,
339  
-                         'name' => $name,
340  
-                         'unique' => true));
  444
+    static function ensureUniqueIndex($collection, $keys, $options = array()) {
  445
+        $options['unique'] = true;
  446
+        return self::ensureIndex($collection, $keys, $options);
341 447
     }
342 448
 
343 449
     /**
@@ -347,8 +453,7 @@ static function ensureUniqueIndex($collection, $keys) {
347 453
      * @return array
348 454
      **/
349 455
     static function getIndexInfo($collection) {
350  
-        global $mongo;
351  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  456
+        $col = self::getCollection($collection, true);
352 457
         return $col->getIndexInfo();
353 458
     }
354 459
 
@@ -359,8 +464,7 @@ static function getIndexInfo($collection) {
359 464
      * @return boolean
360 465
      **/
361 466
     static function deleteIndexes($collection) {
362  
-        global $mongo;
363  
-        $col = $mongo->selectCollection(MONGODB_NAME, $collection);
  467
+        $col = self::getCollection($collection);
364 468
         return $col->deleteIndexes();
365 469
     }
366 470
 }
232  Dbo.php
... ...
@@ -1,28 +1,49 @@
1 1
 <?php
2 2
 
3 3
 /**
4  
- * Class Db
  4
+ * Class Dbo
5 5
  *
6 6
  * @package SimpleMongoPhp
7 7
  * @author Ian White (ibwhite@gmail.com)
8  
- * @version 1.1
  8
+ * @version 1.2
9 9
  *
10  
- * Copyright 2009 Ian White
11  
- * 
12  
- * Licensed under the Apache License, Version 2.0 (the "License");
13  
- * you may not use this file except in compliance with the License.
14  
- * You may obtain a copy of the License at
15  
- * 
16  
- *     http://www.apache.org/licenses/LICENSE-2.0
  10
+ * This is a simple library to allow you to work with simple data objects.
17 11
  *
18  
- * Unless required by applicable law or agreed to in writing, software
19  
- * distributed under the License is distributed on an "AS IS" BASIS,
20  
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  
- * See the License for the specific language governing permissions and
22  
- * limitations under the License.
23  
- *   
  12
+ * To set up, all you need to do is:
  13
+ *    - include() or require() the Db.php file, and this file
  14
+ *    - call Db::addConnection()
  15
+ *    - create any number of data object classes that extend Dbo
  16
+ *    - call Dbo::addClass(<class name>, <collection name>) for each class
  17
+ *
  18
+ * Example usage (this code does basically the same thing as the sample code in Db.php)
  19
+ *   $mongo = new Mongo();
  20
+ *   define('MONGODB_NAME', 'lost');
  21
+ *   class LostPerson extends Dbo {
  22
+ *     function rollCall() {
  23
+ *       echo "$this->name is a " . ($this->goodguy ? 'good' : 'bad') . " guy!\n";
  24
+ *     }
  25
+ *   }
  26
+ *   Dbo::addClass('LostPerson', 'people');
  27
+ *
  28
+ *   Db::drop('people');
  29
+ *   Db::batchInsert('people', array(
  30
+ *     array('name' => 'Jack', 'sex' => 'M', 'goodguy' => true),
  31
+ *     array('name' => 'Kate', 'sex' => 'F', 'goodguy' => true),
  32
+ *     array('name' => 'Locke', 'sex' => 'M', 'goodguy' => true),
  33
+ *     array('name' => 'Hurley', 'sex' => 'M', 'goodguy' => true),
  34
+ *     array('name' => 'Ben', 'sex' => 'M', 'goodguy' => false),
  35
+ *   ));
  36
+ *   foreach (Dbo::find('LostPerson', array('goodguy' => true), array('sort' => array('name' => 1))) as $p) {
  37
+ *     $p->rollCall();
  38
+ *   }
  39
+ *   $ben = Dbo::findOne('LostPerson', array('name' => 'Ben'));
  40
+ *   $locke = Dbo::findOne('LostPerson', array('name' => 'Locke'));
  41
+ *   $ben->enemy = Dbo::toRef($locke);
  42
+ *   $ben->goodguy = null;
  43
+ *   Dbo::save($ben);
  44
+ *
  45
+ * This library may be freely distributed and modified for any purpose.
24 46
  **/
25  
-
26 47
 class Dbo {
27 48
     public $_data = array();
28 49
     
@@ -66,40 +87,12 @@ function __get($field) {
66 87
     function __set($field, $value) {
67 88
         $i = strpos($field, '.');
68 89
         if ($i !== false) {
69  
-            return $this->_setDotNotation($field, $value, $this->_data);
  90
+            $this->_setDotNotation($field, $value, $this->_data);
70 91
         } else {
71 92
             return $this->_data[$field] = $value;
72 93
         }
73 94
     }
74 95
     
75  
-    private function _getDotNotation($fields, &$current) {
76  
-        $i = strpos($fields, '.');
77  
-        if ($i !== false) {
78  
-            $field = substr($fields, 0, $i);
79  
-            if (!isset($current[$field])) {
80  
-                return null;
81  
-            }
82  
-            $current =& $current[$field];
83  
-            return $this->_getDotNotation(substr($fields, $i+1), $current);
84  
-        } else {
85  
-            return isset($current[$fields]) ? $current[$fields] : null;
86  
-        }
87  
-    }
88  
-    
89  
-    private function _setDotNotation($fields, $value, &$current) {
90  
-        $i = strpos($fields, '.');
91  
-        if ($i !== false) {
92  
-            $field = substr($fields, 0, $i);
93  
-            if (!isset($current[$field])) {
94  
-                $current[$field] = array();
95  
-            }
96  
-            $current =& $current[$field];
97  
-            return $this->_setDotNotation(substr($fields, $i+1), $value, $current);
98  
-        } else {
99  
-            return $current[$fields] = $value;
100  
-        }
101  
-    }
102  
-    
103 96
     /**
104 97
      * isset() overload, checks if a field value is set
105 98
      *
@@ -119,6 +112,15 @@ function __isset($field) {
119 112
     function __unset($field) {
120 113
         unset($this->_data[$field]);
121 114
     }
  115
+    
  116
+    /**
  117
+     * Returns all attributes as array
  118
+     *
  119
+     * @return array
  120
+     */
  121
+    function getAttributes() {
  122
+        return $this->_data;
  123
+    }
122 124
 
123 125
     /**
124 126
      * This function will be called immediately prior to saving an object.
@@ -126,20 +128,61 @@ function __unset($field) {
126 128
      * Override in subclasses to, for example, set a created_time timestamp, or update dependent
127 129
      * fields, or validate the data, or whatever you like.
128 130
      *
129  
-     **/
  131
+     */
130 132
     function presave() {
131 133
     }
132 134
     
  135
+    function preremove() {        
  136
+    }
  137
+    
133 138
     /**
134  
-     * This function will be called immediately prior to removing an object.
  139
+     * Reload this object's data from db
135 140
      * 
136  
-     * Override in subclasses to, for example, delete related records, or throw an Exception
137  
-     * for objects that simply should not be removed.
138  
-    **/
139  
-    function preremove() {
140  
-        
  141
+     * @return void
  142
+     */
  143
+    public function reload()
  144
+    {
  145
+        if (isset($this->_id)) {
  146
+            $class = get_class($this);
  147
+            $collection = self::getCollection($class);
  148
+            $this->_data = Db::findOne($collection, $this->_id);
  149
+        }
  150
+    }
  151
+    
  152
+    
  153
+// Guts
  154
+    
  155
+    private function _getDotNotation($fields, &$current) {
  156
+        $i = strpos($fields, '.');
  157
+        if ($i !== false) {
  158
+            $field = substr($fields, 0, $i);
  159
+            if (!isset($current[$field])) {
  160
+                return null;
  161
+            }
  162
+            $current =& $current[$field];
  163
+            return $this->_getDotNotation(substr($fields, $i+1), $current);
  164
+        } else {
  165
+            return isset($current[$fields]) ? $current[$fields] : null;
  166
+        }
  167
+    }
  168
+    
  169
+    private function _setDotNotation($fields, $value, &$current) {
  170
+        $i = strpos($fields, '.');
  171
+        if ($i !== false) {
  172
+            $field = substr($fields, 0, $i);
  173
+            if (!isset($current[$field])) {
  174
+                $current[$field] = array();
  175
+            }
  176
+            $current =& $current[$field];
  177
+            return $this->_setDotNotation(substr($fields, $i+1), $value, $current);
  178
+        } else {
  179
+            $current[$fields] = $value;
  180
+        }
141 181
     }
142 182
 
  183
+    
  184
+// Static functions
  185
+    
143 186
     /**
144 187
      * Register that a class belongs with a collection.
145 188
      *
@@ -288,29 +331,73 @@ static function getRef($dbref) {
288 331
         $data = Db::getRef($dbref);
289 332
         return $data ? new $class($data) : null;
290 333
     }
  334
+    
  335
+    /**
  336
+     * Looks up references to the same collection in one query and returns data objects
  337
+     * of the correct class
  338
+     *
  339
+     * @param  string $collection
  340
+     * @param  array  $ids
  341
+     * @return array
  342
+     */
  343
+    static function getRefs($collection, array $ids) {
  344
+        $class = self::getClass($collection);
  345
+        $data = Db::find($collection, array(
  346
+            '_id' => array('$in' => $ids)
  347
+        ));
  348
+        $objects = array();
  349
+        foreach ($data as $id => $record) {
  350
+            $objects[ array_search($id, $ids) ] = new $class($record);
  351
+        }
  352
+        ksort($objects);
  353
+        return $objects;
  354
+    }
291 355
 
292 356
     /**
293 357
      * Recursively looks up the database references in e.g. an array of database references,
294 358
      * returning all references as data objects
295 359
      *
296 360
      * @param mixed $value
  361
+     * @param boolean $keep_nulls
297 362
      * @return mixed
298 363
      **/
299  
-    static function expandRefs($value) {
300  
-        if (is_array($value)) {
301  
-            if (Db::isRef($value)) {
302  
-                return self::getRef($value);
303  
-            } else {
304  
-                foreach ($value as $k => $v) {
305  
-                    $value[$k] = self::expandRefs($v);
306  
-                }
  364
+    static function expandRefs($value, $keep_nulls = false) {
  365
+        if (Db::isRef($value)) {
  366
+            return self::getRef($value);
  367
+        }
  368
+        elseif (is_array($value)) {
  369
+            // TODO: Temporay fix, remove this later
  370
+            if (empty($value) || ($value[0] instanceof Dbo)) 
  371
+                return $value;
  372
+
  373
+            // Check if all referenced objects are of the same type
  374
+            $reference_map = array();
  375
+            foreach ($value as $reference) {
  376
+                $ref_collection = $reference['$ref'];
  377
+                isset($reference_map[$ref_collection]) ||
  378
+                    $reference_map[$ref_collection] = array();
  379
+                $ref_id = $reference['$id'];
  380
+                $reference_map[$ref_collection][] = $ref_id;
  381
+            }
  382
+            $referenced_collections = array_keys($reference_map);
  383
+            if (count($referenced_collections) == 1) {
  384
+                $referenced_collection = $referenced_collections[0];
  385
+                $referenced_ids = $reference_map[$referenced_collection];
  386
+                $entries = self::getRefs($referenced_collection, $referenced_ids);
307 387
             }
308  
-        } else if ($value instanceof Dbo) {
309  
-            foreach ($value->_data as $k => $v) {
310  
-                $value->_data[$k] = self::expandRefs($v);
  388
+            else {
  389
+                $entries = array();
  390
+                foreach ($reference_map as $collection => $ids) {
  391
+                    $entries = array_merge($entries, self::getRefs($collection, $ids));
  392
+                }
311 393
             }
  394
+            return $keep_nulls ? $entries : array_filter($entries);
312 395
         }
313  
-        return $value;
  396
+        // Empty array or null
  397
+        elseif (!$value) {
  398
+            return $value;
  399
+        }
  400
+        throw new Exception("Don't know how to expand: " . gettype($value));
314 401
     }
315 402
 
316 403
     /**
@@ -330,8 +417,8 @@ static function toRef($value) {
330 417
             }
331 418
         }
332 419
         return $value;
333  
-    }
334  
-  }
  420
+    }  
  421
+}
335 422
 
336 423
 /**
337 424
 * Helper iterator class for Dbo::find(), implements the Iterator interface so you can
@@ -372,4 +459,17 @@ function valid() {
372 459
     function count() {
373 460
         return $this->resultset->count();
374 461
     }
  462
+    
  463
+    function skip($num) {
  464
+        return $this->resultset->skip($num);
  465
+    }
  466
+    
  467
+    function toArray() {
  468
+        $models = array();
  469
+        foreach ($this as $id => $model) {
  470
+            $models[$id] = $model;
  471
+        }
  472
+        reset($this);
  473
+        return $models;
  474
+    }
375 475
 }
19  README
@@ -46,8 +46,7 @@ chaining, because this is easier to cache.
46 46
 
47 47
 To set up, all you need to do is:
48 48
   - include() Db.php
49  
-  - define a global variable named $mongo that represents your Mongo connection
50  
-  - define('MONGODB_NAME', <name of your database>);
  49
+  - call Db::addConnection(<new Mongo object>, <name of your database>)
51 50
   
52 51
 Example usage:
53 52
   $mongo = new Mongo();
@@ -85,15 +84,13 @@ instead of associative arrays.
85 84
 
86 85
 To set up, all you need to do is:
87 86
   - include() or require() both Db.php and Dbo.php
88  
-  - define a global variable named $mongo that represents your Mongo connection object
89  
-  - define('MONGODB_NAME', <the name of your database>);
  87
+  - call Db::addConnection(<new Mongo object>, <name of your database>)
90 88
   - create any number of data object classes that extend Dbo
91 89
   - call Dbo::addClass(<class name>, <collection name>) for each class
92 90
 
93 91
 
94 92
 Example usage (this code does basically the same thing as the code above)
95  
-  $mongo = new Mongo();
96  
-  define('MONGODB_NAME', 'lost');
  93
+  Db::addConnection(new Mongo(), 'lost');
97 94
   class LostPerson extends Dbo {
98 95
     function rollCall() {
99 96
       echo "$this->name is a " . ($this->goodguy ? 'good' : 'bad') . " guy!\n";
@@ -146,6 +143,16 @@ You could retrieve how good Jack is at surgery one of two ways:
146 143
   
147 144
  - Added preremove() hook to go with presave()
148 145
  - Made Dboiterator Countable
  146
+ 
  147
+1.2 - 9/29/2010
  148
+ - No dependency on the MONGODB_NAME or $mongo globals
  149
+ - Support for by-collection sharding -- set different collections
  150
+ to talk to different Mongo instances using Db::addConnection() --
  151
+ useful for poor-man's sharding such as having a different box for
  152
+ your analytics collection
  153
+ - Support for readSlave() -- tell a script to perform all reads
  154
+ on a slave and writes on a master (will add replica set SLAVE_OK
  155
+ support when that gets added to Mongo)
149 156
 
150 157
 
151 158
 License Information

0 notes on commit 00b3385

Please sign in to comment.
Something went wrong with that request. Please try again.