Skip to content

Commit eda9c3c

Browse files
committed
Extract Collection::createIndexes() to an operation class
Additionally, this changes createIndexes() to no longer allow an empty array as input. The index management spec doesn't state that empty input must be accepted, so I'm not sure why we had that behavior.
1 parent e232ace commit eda9c3c

File tree

3 files changed

+145
-64
lines changed

3 files changed

+145
-64
lines changed

src/Collection.php

Lines changed: 5 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use MongoDB\Model\IndexInfoIteratorIterator;
1717
use MongoDB\Model\IndexInput;
1818
use MongoDB\Operation\Aggregate;
19+
use MongoDB\Operation\CreateIndexes;
1920
use MongoDB\Operation\Distinct;
2021
use Traversable;
2122

@@ -296,34 +297,16 @@ public function createIndex($key, array $options = array())
296297
*
297298
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
298299
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
299-
* @param array $indexes List of index specifications
300+
* @param array[] $indexes List of index specifications
300301
* @return string[] The names of the created indexes
301302
* @throws InvalidArgumentException if an index specification is invalid
302303
*/
303304
public function createIndexes(array $indexes)
304305
{
305-
if (empty($indexes)) {
306-
return array();
307-
}
308-
309-
foreach ($indexes as $i => $index) {
310-
if ( ! is_array($index)) {
311-
throw new UnexpectedTypeException($index, 'array');
312-
}
313-
314-
if ( ! isset($index['ns'])) {
315-
$index['ns'] = $this->ns;
316-
}
317-
318-
$indexes[$i] = new IndexInput($index);
319-
}
320-
321-
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
322-
$server = $this->manager->selectServer($readPreference);
306+
$operation = new CreateIndexes($this->dbname, $this->collname, $indexes);
307+
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
323308

324-
return (FeatureDetection::isSupported($server, FeatureDetection::API_CREATEINDEXES_CMD))
325-
? $this->createIndexesCommand($server, $indexes)
326-
: $this->createIndexesLegacy($server, $indexes);
309+
return $operation->execute($server);
327310
}
328311

329312
/**
@@ -1202,47 +1185,6 @@ protected function _update($filter, $update, $options)
12021185
return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
12031186
}
12041187

1205-
/**
1206-
* Create one or more indexes for the collection using the createIndexes
1207-
* command.
1208-
*
1209-
* @param Server $server
1210-
* @param IndexInput[] $indexes
1211-
* @return string[] The names of the created indexes
1212-
*/
1213-
private function createIndexesCommand(Server $server, array $indexes)
1214-
{
1215-
$command = new Command(array(
1216-
'createIndexes' => $this->collname,
1217-
'indexes' => $indexes,
1218-
));
1219-
$server->executeCommand($this->dbname, $command);
1220-
1221-
return array_map(function(IndexInput $index) { return (string) $index; }, $indexes);
1222-
}
1223-
1224-
/**
1225-
* Create one or more indexes for the collection by inserting into the
1226-
* "system.indexes" collection (MongoDB <2.6).
1227-
*
1228-
* @param Server $server
1229-
* @param IndexInput[] $indexes
1230-
* @return string[] The names of the created indexes
1231-
*/
1232-
private function createIndexesLegacy(Server $server, array $indexes)
1233-
{
1234-
$bulk = new BulkWrite(true);
1235-
1236-
foreach ($indexes as $index) {
1237-
// TODO: Remove this once PHPC-274 is resolved (see: PHPLIB-87)
1238-
$bulk->insert($index->bsonSerialize());
1239-
}
1240-
1241-
$server->executeBulkWrite($this->dbname . '.system.indexes', $bulk);
1242-
1243-
return array_map(function(IndexInput $index) { return (string) $index; }, $indexes);
1244-
}
1245-
12461188
/**
12471189
* Returns information for all indexes for this collection using the
12481190
* listIndexes command.

src/Operation/CreateIndexes.php

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
3+
namespace MongoDB\Operation;
4+
5+
use MongoDB\FeatureDetection;
6+
use MongoDB\Driver\Command;
7+
use MongoDB\Driver\Server;
8+
use MongoDB\Driver\BulkWrite;
9+
use MongoDB\Exception\InvalidArgumentException;
10+
use MongoDB\Exception\RuntimeException;
11+
use MongoDB\Exception\UnexpectedTypeException;
12+
use MongoDB\Model\IndexInput;
13+
14+
/**
15+
* Operation for the createIndexes command.
16+
*
17+
* @api
18+
* @see MongoDB\Collection::createIndex()
19+
* @see MongoDB\Collection::createIndexes()
20+
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
21+
*/
22+
class CreateIndexes implements Executable
23+
{
24+
private static $wireVersionForCommand = 2;
25+
26+
private $databaseName;
27+
private $collectionName;
28+
private $indexes = array();
29+
30+
/**
31+
* Constructs an aggregate command.
32+
*
33+
* Supported options:
34+
*
35+
* * allowDiskUse (boolean): Enables writing to temporary files. When set
36+
* to true, aggregation stages can write data to the _tmp sub-directory
37+
* in the dbPath directory. The default is false.
38+
*
39+
* * batchSize (integer): The number of documents to return per batch.
40+
*
41+
* * maxTimeMS (integer): The maximum amount of time to allow the query to
42+
* run.
43+
*
44+
* * useCursor (boolean): Indicates whether the command will request that
45+
* the server provide results using a cursor. The default is true.
46+
*
47+
* For servers < 2.6, this option is ignored as aggregation cursors are
48+
* not available.
49+
*
50+
* For servers >= 2.6, this option allows users to turn off cursors if
51+
* necessary to aid in mongod/mongos upgrades.
52+
*
53+
* @param string $databaseName Database name
54+
* @param string $collectionName Collection name
55+
* @param array[] $indexes List of index specifications
56+
* @throws InvalidArgumentException
57+
*/
58+
public function __construct($databaseName, $collectionName, array $indexes)
59+
{
60+
if (empty($indexes)) {
61+
throw new InvalidArgumentException('$indexes is empty');
62+
}
63+
64+
foreach ($indexes as $index) {
65+
if ( ! is_array($index)) {
66+
throw new UnexpectedTypeException($index, 'array');
67+
}
68+
69+
if ( ! isset($index['ns'])) {
70+
$index['ns'] = $databaseName . '.' . $collectionName;
71+
}
72+
73+
$this->indexes[] = new IndexInput($index);
74+
}
75+
76+
$this->databaseName = (string) $databaseName;
77+
$this->collectionName = (string) $collectionName;
78+
}
79+
80+
/**
81+
* Execute the operation.
82+
*
83+
* @see Executable::execute()
84+
* @param Server $server
85+
* @return string[] The names of the created indexes
86+
*/
87+
public function execute(Server $server)
88+
{
89+
if (FeatureDetection::isSupported($server, self::$wireVersionForCommand)) {
90+
$this->executeCommand($server);
91+
} else {
92+
$this->executeLegacy($server);
93+
}
94+
95+
return array_map(function(IndexInput $index) { return (string) $index; }, $this->indexes);
96+
}
97+
98+
/**
99+
* Create one or more indexes for the collection using the createIndexes
100+
* command.
101+
*
102+
* @param Server $server
103+
*/
104+
private function executeCommand(Server $server)
105+
{
106+
$command = new Command(array(
107+
'createIndexes' => $this->collectionName,
108+
'indexes' => $this->indexes,
109+
));
110+
111+
$cursor = $server->executeCommand($this->databaseName, $command);
112+
$result = current($cursor->toArray());
113+
114+
if (empty($result['ok'])) {
115+
throw new RuntimeException(isset($result['errmsg']) ? $result['errmsg'] : 'Unknown error');
116+
}
117+
}
118+
119+
/**
120+
* Create one or more indexes for the collection by inserting into the
121+
* "system.indexes" collection (MongoDB <2.6).
122+
*
123+
* @param Server $server
124+
* @param IndexInput[] $indexes
125+
*/
126+
private function executeLegacy(Server $server, array $indexes)
127+
{
128+
$bulk = new BulkWrite(true);
129+
130+
foreach ($this->indexes as $index) {
131+
$bulk->insert($index);
132+
}
133+
134+
$server->executeBulkWrite($this->databaseName . '.system.indexes', $bulk);
135+
}
136+
}

tests/Collection/IndexManagementFunctionalTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ public function testCreateIndexes()
8585
});
8686
}
8787

88-
public function testCreateIndexesWithEmptyInputIsNop()
88+
/**
89+
* @expectedException MongoDB\Exception\InvalidArgumentException
90+
*/
91+
public function testCreateIndexesRequiresAtLeastOneIndex()
8992
{
9093
$this->assertSame(array(), $this->collection->createIndexes(array()));
9194
}

0 commit comments

Comments
 (0)