19
19
20
20
use ArrayIterator ;
21
21
use MongoDB \Driver \Command ;
22
+ use MongoDB \Driver \Cursor ;
22
23
use MongoDB \Driver \Exception \RuntimeException as DriverRuntimeException ;
23
24
use MongoDB \Driver \ReadConcern ;
24
25
use MongoDB \Driver \ReadPreference ;
@@ -75,6 +76,12 @@ class Aggregate implements Executable, Explainable
75
76
/** @var array */
76
77
private $ options ;
77
78
79
+ /** @var bool */
80
+ private $ isExplain ;
81
+
82
+ /** @var bool */
83
+ private $ isWrite ;
84
+
78
85
/**
79
86
* Constructs an aggregate command.
80
87
*
@@ -253,8 +260,19 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr
253
260
unset($ options ['writeConcern ' ]);
254
261
}
255
262
256
- if (! empty ($ options ['explain ' ])) {
263
+ $ this ->isExplain = ! empty ($ options ['explain ' ]);
264
+ $ this ->isWrite = is_last_pipeline_operator_write ($ pipeline ) && ! $ this ->isExplain ;
265
+
266
+ // Explain does not use a cursor
267
+ if ($ this ->isExplain ) {
257
268
$ options ['useCursor ' ] = false ;
269
+ unset($ options ['batchSize ' ]);
270
+ }
271
+
272
+ /* Ignore batchSize for writes, since no documents are returned and a
273
+ * batchSize of zero could prevent the pipeline from executing. */
274
+ if ($ this ->isWrite ) {
275
+ unset($ options ['batchSize ' ]);
258
276
}
259
277
260
278
$ this ->databaseName = (string ) $ databaseName ;
@@ -298,20 +316,14 @@ public function execute(Server $server)
298
316
}
299
317
}
300
318
301
- $ hasExplain = ! empty ($ this ->options ['explain ' ]);
302
- $ hasWriteStage = $ this ->hasWriteStage ();
303
-
304
319
$ command = new Command (
305
- $ this ->createCommandDocument ($ server, $ hasWriteStage ),
320
+ $ this ->createCommandDocument ($ server ),
306
321
$ this ->createCommandOptions ()
307
322
);
308
- $ options = $ this ->createOptions ($ hasWriteStage , $ hasExplain );
309
323
310
- $ cursor = $ hasWriteStage && ! $ hasExplain
311
- ? $ server ->executeReadWriteCommand ($ this ->databaseName , $ command , $ options )
312
- : $ server ->executeReadCommand ($ this ->databaseName , $ command , $ options );
324
+ $ cursor = $ this ->executeCommand ($ server , $ command );
313
325
314
- if ($ this ->options ['useCursor ' ] || $ hasExplain ) {
326
+ if ($ this ->options ['useCursor ' ] || $ this -> isExplain ) {
315
327
if (isset ($ this ->options ['typeMap ' ])) {
316
328
$ cursor ->setTypeMap ($ this ->options ['typeMap ' ]);
317
329
}
@@ -341,10 +353,10 @@ public function execute(Server $server)
341
353
*/
342
354
public function getCommandDocument (Server $ server )
343
355
{
344
- return $ this ->createCommandDocument ($ server, $ this -> hasWriteStage () );
356
+ return $ this ->createCommandDocument ($ server );
345
357
}
346
358
347
- private function createCommandDocument (Server $ server, bool $ hasWriteStage ): array
359
+ private function createCommandDocument (Server $ server ): array
348
360
{
349
361
$ cmd = [
350
362
'aggregate ' => $ this ->collectionName ?? 1 ,
@@ -377,10 +389,7 @@ private function createCommandDocument(Server $server, bool $hasWriteStage): arr
377
389
}
378
390
379
391
if ($ this ->options ['useCursor ' ]) {
380
- /* Ignore batchSize if pipeline includes an $out or $merge stage, as
381
- * no documents will be returned and sending a batchSize of zero
382
- * could prevent the pipeline from executing at all. */
383
- $ cmd ['cursor ' ] = isset ($ this ->options ["batchSize " ]) && ! $ hasWriteStage
392
+ $ cmd ['cursor ' ] = isset ($ this ->options ["batchSize " ])
384
393
? ['batchSize ' => $ this ->options ["batchSize " ]]
385
394
: new stdClass ();
386
395
}
@@ -400,39 +409,38 @@ private function createCommandOptions(): array
400
409
}
401
410
402
411
/**
403
- * Create options for executing the command .
412
+ * Execute the aggregate command using the appropriate Server method .
404
413
*
414
+ * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php
405
415
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
406
416
* @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php
407
- * @param boolean $hasWriteStage
408
- * @param boolean $hasExplain
409
- * @return array
410
417
*/
411
- private function createOptions ( $ hasWriteStage , $ hasExplain )
418
+ private function executeCommand ( Server $ server , Command $ command ): Cursor
412
419
{
413
420
$ options = [];
414
421
415
- if (isset ($ this ->options ['readConcern ' ])) {
416
- $ options ['readConcern ' ] = $ this ->options ['readConcern ' ];
422
+ foreach (['readConcern ' , 'readPreference ' , 'session ' ] as $ option ) {
423
+ if (isset ($ this ->options [$ option ])) {
424
+ $ options [$ option ] = $ this ->options [$ option ];
425
+ }
417
426
}
418
427
419
- if (! $ hasWriteStage && isset ($ this ->options ['readPreference ' ])) {
420
- $ options ['readPreference ' ] = $ this ->options ['readPreference ' ];
428
+ if ($ this -> isWrite && isset ($ this ->options ['writeConcern ' ])) {
429
+ $ options ['writeConcern ' ] = $ this ->options ['writeConcern ' ];
421
430
}
422
431
423
- if (isset ( $ this ->options [ ' session ' ]) ) {
424
- $ options [ ' session ' ] = $ this ->options [ ' session ' ] ;
432
+ if (! $ this ->isWrite ) {
433
+ return $ server -> executeReadCommand ( $ this ->databaseName , $ command , $ options) ;
425
434
}
426
435
427
- if ($ hasWriteStage && ! $ hasExplain && isset ($ this ->options ['writeConcern ' ])) {
428
- $ options ['writeConcern ' ] = $ this ->options ['writeConcern ' ];
436
+ /* Server::executeReadWriteCommand() does not support a "readPreference"
437
+ * option, so fall back to executeCommand(). This means that libmongoc
438
+ * will not apply any client-level options (e.g. writeConcern), but that
439
+ * should not be an issue as PHPLIB handles inheritance on its own. */
440
+ if (isset ($ options ['readPreference ' ])) {
441
+ return $ server ->executeCommand ($ this ->databaseName , $ command , $ options );
429
442
}
430
443
431
- return $ options ;
432
- }
433
-
434
- private function hasWriteStage (): bool
435
- {
436
- return is_last_pipeline_operator_write ($ this ->pipeline );
444
+ return $ server ->executeReadWriteCommand ($ this ->databaseName , $ command , $ options );
437
445
}
438
446
}
0 commit comments