|
10 | 10 | use MongoDB\Driver\ReadPreference;
|
11 | 11 | use MongoDB\Driver\Server;
|
12 | 12 | use MongoDB\Driver\WriteConcern;
|
| 13 | +use MongoDB\Exception\InvalidArgumentException; |
| 14 | +use MongoDB\Exception\UnexpectedTypeException; |
13 | 15 | use MongoDB\Model\IndexInfoIterator;
|
14 | 16 | use MongoDB\Model\IndexInfoIteratorIterator;
|
15 |
| -use InvalidArgumentException; |
| 17 | +use stdClass; |
16 | 18 |
|
17 | 19 | class Collection
|
18 | 20 | {
|
@@ -248,34 +250,84 @@ public function count(array $filter = array(), array $options = array())
|
248 | 250 | }
|
249 | 251 |
|
250 | 252 | /**
|
251 |
| - * Create a single index in the collection. |
| 253 | + * Create a single index for the collection. |
252 | 254 | *
|
253 | 255 | * @see http://docs.mongodb.org/manual/reference/command/createIndexes/
|
254 | 256 | * @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
|
255 |
| - * @param array|object $keys |
256 |
| - * @param array $options |
| 257 | + * @see Collection::createIndexes() |
| 258 | + * @param array|object $key Document containing fields mapped to values, |
| 259 | + * which denote order or an index type |
| 260 | + * @param array $options Index options |
257 | 261 | * @return string The name of the created index
|
258 | 262 | */
|
259 |
| - public function createIndex($keys, array $options = array()) |
| 263 | + public function createIndex($key, array $options = array()) |
260 | 264 | {
|
261 |
| - // TODO |
| 265 | + return current($this->createIndexes(array(array('key' => $key) + $options))); |
262 | 266 | }
|
263 | 267 |
|
264 | 268 | /**
|
265 |
| - * Create multiple indexes in the collection. |
| 269 | + * Create one or more indexes for the collection. |
266 | 270 | *
|
267 |
| - * TODO: decide if $models should be an array of associative arrays, using |
268 |
| - * createIndex()'s parameter names as keys, or tuples, using parameters in |
269 |
| - * order (e.g. [keys, options]). |
| 271 | + * Each element in the $indexes array must have a "key" document, which |
| 272 | + * contains fields mapped to an order or type. Other options may follow. |
| 273 | + * For example: |
| 274 | + * |
| 275 | + * $indexes = [ |
| 276 | + * // Create a unique index on the "username" field |
| 277 | + * [ 'key' => [ 'username' => 1 ], 'unique' => true ], |
| 278 | + * // Create a 2dsphere index on the "loc" field with a custom name |
| 279 | + * [ 'key' => [ 'loc' => '2dsphere' ], 'name' => 'geo' ], |
| 280 | + * ]; |
| 281 | + * |
| 282 | + * If the "name" option is unspecified, a name will be generated from the |
| 283 | + * "key" document. |
270 | 284 | *
|
271 | 285 | * @see http://docs.mongodb.org/manual/reference/command/createIndexes/
|
272 | 286 | * @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
|
273 |
| - * @param array $models |
| 287 | + * @param array $indexes List of index specifications |
274 | 288 | * @return string[] The names of the created indexes
|
| 289 | + * @throws InvalidArgumentException if an index specification does not |
| 290 | + * contain a "key" document |
| 291 | + * @throws UnexpectedTypeException if an index specification is not an array |
| 292 | + * or a "key" document is not an array or |
| 293 | + * object |
275 | 294 | */
|
276 |
| - public function createIndexes(array $models) |
| 295 | + public function createIndexes(array $indexes) |
277 | 296 | {
|
278 |
| - // TODO |
| 297 | + foreach ($indexes as &$index) { |
| 298 | + if ( ! is_array($index)) { |
| 299 | + throw new UnexpectedTypeException($index, 'array'); |
| 300 | + } |
| 301 | + |
| 302 | + if ( ! isset($index['key'])) { |
| 303 | + throw new InvalidArgumentException('Required "key" document is missing from index specification'); |
| 304 | + } |
| 305 | + |
| 306 | + if ( ! is_array($index['key']) && ! is_object($index['key'])) { |
| 307 | + throw new UnexpectedTypeException($index['key'], 'array or object'); |
| 308 | + } |
| 309 | + |
| 310 | + $index['key'] = (object) $index['key']; |
| 311 | + $index['ns'] = $this->ns; |
| 312 | + |
| 313 | + if ( ! isset($index['name'])) { |
| 314 | + $index['name'] = $this->generateIndexName($index['key']); |
| 315 | + } |
| 316 | + } |
| 317 | + |
| 318 | + $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY); |
| 319 | + $server = $this->manager->selectServer($readPreference); |
| 320 | + |
| 321 | + $serverInfo = $server->getInfo(); |
| 322 | + $maxWireVersion = isset($serverInfo['maxWireVersion']) ? $serverInfo['maxWireVersion'] : 0; |
| 323 | + |
| 324 | + if ($maxWireVersion >= 2) { |
| 325 | + $this->createIndexesCommand($server, $indexes); |
| 326 | + } else { |
| 327 | + $this->createIndexesLegacy($server, $indexes); |
| 328 | + } |
| 329 | + |
| 330 | + return array_map(function(array $index) { return $index['name']; }, $indexes); |
279 | 331 | }
|
280 | 332 |
|
281 | 333 | /**
|
@@ -1163,6 +1215,58 @@ protected function _update($filter, $update, $options)
|
1163 | 1215 | return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
|
1164 | 1216 | }
|
1165 | 1217 |
|
| 1218 | + /** |
| 1219 | + * Create one or more indexes for the collection using the createIndexes |
| 1220 | + * command. |
| 1221 | + * |
| 1222 | + * @param Server $server |
| 1223 | + * @param array $indexes |
| 1224 | + */ |
| 1225 | + private function createIndexesCommand(Server $server, array $indexes) |
| 1226 | + { |
| 1227 | + $command = new Command(array( |
| 1228 | + 'createIndexes' => $this->collname, |
| 1229 | + 'indexes' => $indexes, |
| 1230 | + )); |
| 1231 | + $server->executeCommand($this->dbname, $command); |
| 1232 | + } |
| 1233 | + |
| 1234 | + /** |
| 1235 | + * Create one or more indexes for the collection by inserting into the |
| 1236 | + * "system.indexes" collection (MongoDB <2.6). |
| 1237 | + * |
| 1238 | + * @param Server $server |
| 1239 | + * @param array $indexes |
| 1240 | + */ |
| 1241 | + private function createIndexesLegacy(Server $server, array $indexes) |
| 1242 | + { |
| 1243 | + $bulk = new BulkWrite(true); |
| 1244 | + |
| 1245 | + foreach ($indexes as $index) { |
| 1246 | + $bulk->insert($index); |
| 1247 | + } |
| 1248 | + |
| 1249 | + // TODO: This inherits the client's write concern. Should we enforce {w:1} here? (see: SPEC-195) |
| 1250 | + $server->executeBulkWrite($this->dbname . '.system.indexes', $bulk); |
| 1251 | + } |
| 1252 | + |
| 1253 | + /** |
| 1254 | + * Generates an index name from its key specification. |
| 1255 | + * |
| 1256 | + * @param object $key |
| 1257 | + * @return string |
| 1258 | + */ |
| 1259 | + private function generateIndexName(stdClass $key) |
| 1260 | + { |
| 1261 | + $name = ''; |
| 1262 | + |
| 1263 | + foreach ($key as $field => $type) { |
| 1264 | + $name .= ($name != '' ? '_' : '') . $field . '_' . $type; |
| 1265 | + } |
| 1266 | + |
| 1267 | + return $name; |
| 1268 | + } |
| 1269 | + |
1166 | 1270 | /**
|
1167 | 1271 | * Returns information for all indexes for this collection using the
|
1168 | 1272 | * listIndexes command.
|
@@ -1190,7 +1294,7 @@ private function listIndexesCommand(Server $server)
|
1190 | 1294 | private function listIndexesLegacy(Server $server)
|
1191 | 1295 | {
|
1192 | 1296 | $query = new Query(array('ns' => $this->ns));
|
1193 |
| - $cursor = $server->executeQuery($namespace, $query); |
| 1297 | + $cursor = $server->executeQuery($this->ns, $query); |
1194 | 1298 | $cursor->setTypeMap(array('document' => 'array'));
|
1195 | 1299 |
|
1196 | 1300 | return new IndexInfoIteratorIterator($cursor);
|
|
0 commit comments