Skip to content

Commit 00fe7eb

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 7665b36 commit 00fe7eb

File tree

3 files changed

+146
-64
lines changed

3 files changed

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

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)