Skip to content

Commit 21b7d92

Browse files
committed
PHPLIB-200: Support writeConcern option for commands that write
1 parent bb47c1d commit 21b7d92

17 files changed

+294
-27
lines changed

src/Client.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Client
1616
'document' => 'MongoDB\Model\BSONDocument',
1717
'root' => 'MongoDB\Model\BSONDocument',
1818
];
19+
private static $wireVersionForWritableCommandWriteConcern = 5;
1920

2021
private $manager;
2122
private $uri;
@@ -114,9 +115,14 @@ public function dropDatabase($databaseName, array $options = [])
114115
$options['typeMap'] = $this->typeMap;
115116
}
116117

117-
$operation = new DropDatabase($databaseName, $options);
118118
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
119119

120+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
121+
$options['writeConcern'] = $this->writeConcern;
122+
}
123+
124+
$operation = new DropDatabase($databaseName, $options);
125+
120126
return $operation->execute($server);
121127
}
122128

src/Collection.php

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class Collection
3939
'root' => 'MongoDB\Model\BSONDocument',
4040
];
4141
private static $wireVersionForFindAndModifyWriteConcern = 4;
42+
private static $wireVersionForWritableCommandWriteConcern = 5;
4243

4344
private $collectionName;
4445
private $databaseName;
@@ -180,9 +181,14 @@ public function aggregate(array $pipeline, array $options = [])
180181
$options['typeMap'] = $this->typeMap;
181182
}
182183

183-
$operation = new Aggregate($this->databaseName, $this->collectionName, $pipeline, $options);
184184
$server = $this->manager->selectServer($options['readPreference']);
185185

186+
if ($hasOutStage && ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
187+
$options['writeConcern'] = $this->writeConcern;
188+
}
189+
190+
$operation = new Aggregate($this->databaseName, $this->collectionName, $pipeline, $options);
191+
186192
return $operation->execute($server);
187193
}
188194

@@ -234,14 +240,18 @@ public function count($filter = [], array $options = [])
234240
* Create a single index for the collection.
235241
*
236242
* @see Collection::createIndexes()
243+
* @see CreateIndexes::__construct() for supported command options
237244
* @param array|object $key Document containing fields mapped to values,
238245
* which denote order or an index type
239246
* @param array $options Index options
240247
* @return string The name of the created index
241248
*/
242249
public function createIndex($key, array $options = [])
243250
{
244-
return current($this->createIndexes([['key' => $key] + $options]));
251+
$indexOptions = array_diff_key($options, ['writeConcern' => 1]);
252+
$commandOptions = array_intersect_key($options, ['writeConcern' => 1]);
253+
254+
return current($this->createIndexes([['key' => $key] + $indexOptions], $commandOptions));
245255
}
246256

247257
/**
@@ -263,15 +273,22 @@ public function createIndex($key, array $options = [])
263273
*
264274
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
265275
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
276+
* @see CreateIndexes::__construct() for supported command options
266277
* @param array[] $indexes List of index specifications
278+
* @param array $options Command options
267279
* @return string[] The names of the created indexes
268280
* @throws InvalidArgumentException if an index specification is invalid
269281
*/
270-
public function createIndexes(array $indexes)
282+
public function createIndexes(array $indexes, array $options = [])
271283
{
272-
$operation = new CreateIndexes($this->databaseName, $this->collectionName, $indexes);
273284
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
274285

286+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
287+
$options['writeConcern'] = $this->writeConcern;
288+
}
289+
290+
$operation = new CreateIndexes($this->databaseName, $this->collectionName, $indexes, $options);
291+
275292
return $operation->execute($server);
276293
}
277294

@@ -355,9 +372,14 @@ public function drop(array $options = [])
355372
$options['typeMap'] = $this->typeMap;
356373
}
357374

358-
$operation = new DropCollection($this->databaseName, $this->collectionName, $options);
359375
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
360376

377+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
378+
$options['writeConcern'] = $this->writeConcern;
379+
}
380+
381+
$operation = new DropCollection($this->databaseName, $this->collectionName, $options);
382+
361383
return $operation->execute($server);
362384
}
363385

@@ -382,9 +404,14 @@ public function dropIndex($indexName, array $options = [])
382404
$options['typeMap'] = $this->typeMap;
383405
}
384406

385-
$operation = new DropIndexes($this->databaseName, $this->collectionName, $indexName, $options);
386407
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
387408

409+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
410+
$options['writeConcern'] = $this->writeConcern;
411+
}
412+
413+
$operation = new DropIndexes($this->databaseName, $this->collectionName, $indexName, $options);
414+
388415
return $operation->execute($server);
389416
}
390417

@@ -401,9 +428,14 @@ public function dropIndexes(array $options = [])
401428
$options['typeMap'] = $this->typeMap;
402429
}
403430

404-
$operation = new DropIndexes($this->databaseName, $this->collectionName, '*', $options);
405431
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
406432

433+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
434+
$options['writeConcern'] = $this->writeConcern;
435+
}
436+
437+
$operation = new DropIndexes($this->databaseName, $this->collectionName, '*', $options);
438+
407439
return $operation->execute($server);
408440
}
409441

src/Database.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Database
2424
'document' => 'MongoDB\Model\BSONDocument',
2525
'root' => 'MongoDB\Model\BSONDocument',
2626
];
27+
private static $wireVersionForWritableCommandWriteConcern = 5;
2728

2829
private $databaseName;
2930
private $manager;
@@ -173,9 +174,14 @@ public function createCollection($collectionName, array $options = [])
173174
$options['typeMap'] = $this->typeMap;
174175
}
175176

176-
$operation = new CreateCollection($this->databaseName, $collectionName, $options);
177177
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
178178

179+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
180+
$options['writeConcern'] = $this->writeConcern;
181+
}
182+
183+
$operation = new CreateCollection($this->databaseName, $collectionName, $options);
184+
179185
return $operation->execute($server);
180186
}
181187

@@ -192,9 +198,14 @@ public function drop(array $options = [])
192198
$options['typeMap'] = $this->typeMap;
193199
}
194200

195-
$operation = new DropDatabase($this->databaseName, $options);
196201
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
197202

203+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
204+
$options['writeConcern'] = $this->writeConcern;
205+
}
206+
207+
$operation = new DropDatabase($this->databaseName, $options);
208+
198209
return $operation->execute($server);
199210
}
200211

@@ -212,9 +223,14 @@ public function dropCollection($collectionName, array $options = [])
212223
$options['typeMap'] = $this->typeMap;
213224
}
214225

215-
$operation = new DropCollection($this->databaseName, $collectionName, $options);
216226
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
217227

228+
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
229+
$options['writeConcern'] = $this->writeConcern;
230+
}
231+
232+
$operation = new DropCollection($this->databaseName, $collectionName, $options);
233+
218234
return $operation->execute($server);
219235
}
220236

src/Exception/UnsupportedException.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,14 @@ public static function collationNotSupported()
1313
{
1414
return new static('Collations are not supported by the server executing this operation');
1515
}
16+
17+
/**
18+
* Thrown when a command's writeConcern option is not supported by a server.
19+
*
20+
* @return self
21+
*/
22+
public static function writeConcernNotSupported()
23+
{
24+
return new static('Write concern is not supported by the server executing this command');
25+
}
1626
}

src/Operation/Aggregate.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use MongoDB\Driver\ReadConcern;
77
use MongoDB\Driver\ReadPreference;
88
use MongoDB\Driver\Server;
9+
use MongoDB\Driver\WriteConcern;
910
use MongoDB\Exception\InvalidArgumentException;
1011
use MongoDB\Exception\UnexpectedValueException;
1112
use MongoDB\Exception\UnsupportedException;
@@ -26,6 +27,7 @@ class Aggregate implements Executable
2627
private static $wireVersionForCursor = 2;
2728
private static $wireVersionForDocumentLevelValidation = 4;
2829
private static $wireVersionForReadConcern = 4;
30+
private static $wireVersionForWriteConcern = 5;
2931

3032
private $databaseName;
3133
private $collectionName;
@@ -81,6 +83,12 @@ class Aggregate implements Executable
8183
* For servers >= 2.6, this option allows users to turn off cursors if
8284
* necessary to aid in mongod/mongos upgrades.
8385
*
86+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern. This only
87+
* applies when the $out stage is specified.
88+
*
89+
* This is not supported for server versions < 3.4 and will result in an
90+
* exception at execution time if used.
91+
*
8492
* @param string $databaseName Database name
8593
* @param string $collectionName Collection name
8694
* @param array $pipeline List of pipeline operations
@@ -148,6 +156,10 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr
148156
throw InvalidArgumentException::invalidType('"useCursor" option', $options['useCursor'], 'boolean');
149157
}
150158

159+
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
160+
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
161+
}
162+
151163
if (isset($options['batchSize']) && ! $options['useCursor']) {
152164
throw new InvalidArgumentException('"batchSize" option should not be used if "useCursor" is false');
153165
}
@@ -169,14 +181,18 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr
169181
* @param Server $server
170182
* @return Traversable
171183
* @throws UnexpectedValueException if the command response was malformed
172-
* @throws UnsupportedException if collation is used and unsupported
184+
* @throws UnsupportedException if collation or write concern is used and unsupported
173185
*/
174186
public function execute(Server $server)
175187
{
176188
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
177189
throw UnsupportedException::collationNotSupported();
178190
}
179191

192+
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
193+
throw UnsupportedException::writeConcernNotSupported();
194+
}
195+
180196
$isCursorSupported = \MongoDB\server_supports_feature($server, self::$wireVersionForCursor);
181197
$readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null;
182198

@@ -240,6 +256,10 @@ private function createCommand(Server $server, $isCursorSupported)
240256
$cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']);
241257
}
242258

259+
if (isset($this->options['writeConcern'])) {
260+
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']);
261+
}
262+
243263
if ($this->options['useCursor']) {
244264
$cmd['cursor'] = isset($this->options["batchSize"])
245265
? ['batchSize' => $this->options["batchSize"]]

src/Operation/CreateCollection.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use MongoDB\Driver\Command;
66
use MongoDB\Driver\Server;
7+
use MongoDB\Driver\WriteConcern;
78
use MongoDB\Exception\InvalidArgumentException;
89
use MongoDB\Exception\UnsupportedException;
910

@@ -20,6 +21,7 @@ class CreateCollection implements Executable
2021
const NO_PADDING = 2;
2122

2223
private static $wireVersionForCollation = 5;
24+
private static $wireVersionForWriteConcern = 5;
2325

2426
private $databaseName;
2527
private $collectionName;
@@ -69,6 +71,11 @@ class CreateCollection implements Executable
6971
*
7072
* * validator (document): Validation rules or expressions.
7173
*
74+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
75+
*
76+
* This is not supported for server versions < 3.4 and will result in an
77+
* exception at execution time if used.
78+
*
7279
* @see http://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb
7380
* @see https://docs.mongodb.org/manual/core/document-validation/
7481
* @param string $databaseName Database name
@@ -130,6 +137,10 @@ public function __construct($databaseName, $collectionName, array $options = [])
130137
throw InvalidArgumentException::invalidType('"validator" option', $options['validator'], 'array or object');
131138
}
132139

140+
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
141+
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
142+
}
143+
133144
$this->databaseName = (string) $databaseName;
134145
$this->collectionName = (string) $collectionName;
135146
$this->options = $options;
@@ -141,14 +152,18 @@ public function __construct($databaseName, $collectionName, array $options = [])
141152
* @see Executable::execute()
142153
* @param Server $server
143154
* @return array|object Command result document
144-
* @throws UnsupportedException if collation is used and unsupported
155+
* @throws UnsupportedException if collation or write concern is used and unsupported
145156
*/
146157
public function execute(Server $server)
147158
{
148159
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
149160
throw UnsupportedException::collationNotSupported();
150161
}
151162

163+
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
164+
throw UnsupportedException::writeConcernNotSupported();
165+
}
166+
152167
$cursor = $server->executeCommand($this->databaseName, $this->createCommand());
153168

154169
if (isset($this->options['typeMap'])) {
@@ -179,6 +194,10 @@ private function createCommand()
179194
}
180195
}
181196

197+
if (isset($this->options['writeConcern'])) {
198+
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']);
199+
}
200+
182201
return new Command($cmd);
183202
}
184203
}

0 commit comments

Comments
 (0)