Skip to content

Commit 48f6d1e

Browse files
committed
PHPLIB-63: Index creation methods
1 parent e1d2621 commit 48f6d1e

File tree

4 files changed

+142
-13
lines changed

4 files changed

+142
-13
lines changed

src/Collection.php

Lines changed: 117 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
use MongoDB\Driver\ReadPreference;
1111
use MongoDB\Driver\Server;
1212
use MongoDB\Driver\WriteConcern;
13+
use MongoDB\Exception\InvalidArgumentException;
14+
use MongoDB\Exception\UnexpectedTypeException;
1315
use MongoDB\Model\IndexInfoIterator;
1416
use MongoDB\Model\IndexInfoIteratorIterator;
15-
use InvalidArgumentException;
17+
use stdClass;
1618

1719
class Collection
1820
{
@@ -248,34 +250,84 @@ public function count(array $filter = array(), array $options = array())
248250
}
249251

250252
/**
251-
* Create a single index in the collection.
253+
* Create a single index for the collection.
252254
*
253255
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
254256
* @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
257261
* @return string The name of the created index
258262
*/
259-
public function createIndex($keys, array $options = array())
263+
public function createIndex($key, array $options = array())
260264
{
261-
// TODO
265+
return current($this->createIndexes(array(array('key' => $key) + $options)));
262266
}
263267

264268
/**
265-
* Create multiple indexes in the collection.
269+
* Create one or more indexes for the collection.
266270
*
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.
270284
*
271285
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
272286
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
273-
* @param array $models
287+
* @param array $indexes List of index specifications
274288
* @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
275294
*/
276-
public function createIndexes(array $models)
295+
public function createIndexes(array $indexes)
277296
{
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);
279331
}
280332

281333
/**
@@ -1163,6 +1215,58 @@ protected function _update($filter, $update, $options)
11631215
return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
11641216
}
11651217

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+
11661270
/**
11671271
* Returns information for all indexes for this collection using the
11681272
* listIndexes command.

src/Exception/Exception.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace MongoDB\Exception;
4+
5+
interface Exception
6+
{
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace MongoDB\Exception;
4+
5+
class InvalidArgumentException extends \InvalidArgumentException implements Exception
6+
{
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace MongoDB\Exception;
4+
5+
class UnexpectedTypeException extends InvalidArgumentException
6+
{
7+
public function __construct($value, $expectedType)
8+
{
9+
parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
10+
}
11+
}

0 commit comments

Comments
 (0)