Skip to content

Commit f8b67ff

Browse files
committed
PHPLIB-109: Extract ReplaceOne, UpdateOne, and UpdateMany operation classes
1 parent ef4a1e2 commit f8b67ff

File tree

9 files changed

+508
-47
lines changed

9 files changed

+508
-47
lines changed

src/Collection.php

Lines changed: 39 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
use MongoDB\Operation\InsertMany;
3030
use MongoDB\Operation\InsertOne;
3131
use MongoDB\Operation\ListIndexes;
32+
use MongoDB\Operation\ReplaceOne;
33+
use MongoDB\Operation\UpdateMany;
34+
use MongoDB\Operation\UpdateOne;
3235
use Traversable;
3336

3437
class Collection
@@ -609,79 +612,68 @@ public function listIndexes(array $options = array())
609612
}
610613

611614
/**
612-
* Replace one document
615+
* Replaces at most one document matching the filter.
613616
*
617+
* @see ReplaceOne::__construct() for supported options
614618
* @see http://docs.mongodb.org/manual/reference/command/update/
615-
* @see Collection::getWriteOptions() for supported $options
616-
*
617-
* @param array $filter The document to be replaced
618-
* @param array $update The document to replace with
619-
* @param array $options Additional options
619+
* @param array|object $filter Query by which to filter documents
620+
* @param array|object $replacement Replacement document
621+
* @param array $options Command options
620622
* @return UpdateResult
621623
*/
622-
public function replaceOne(array $filter, array $update, array $options = array())
624+
public function replaceOne($filter, $replacement, array $options = array())
623625
{
624-
$firstKey = key($update);
625-
if (isset($firstKey[0]) && $firstKey[0] == '$') {
626-
throw new InvalidArgumentException("First key in \$update must NOT be a \$operator");
626+
if ( ! isset($options['writeConcern']) && isset($this->wc)) {
627+
$options['writeConcern'] = $this->wc;
627628
}
628-
$wr = $this->_update($filter, $update, $options + array("multi" => false));
629629

630-
return new UpdateResult($wr);
630+
$operation = new ReplaceOne($this->dbname, $this->collname, $filter, $replacement, $options);
631+
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
632+
633+
return $operation->execute($server);
631634
}
632635

633636
/**
634-
* Update one document
635-
* NOTE: Will update ALL documents matching $filter
637+
* Updates all documents matching the filter.
636638
*
639+
* @see UpdateMany::__construct() for supported options
637640
* @see http://docs.mongodb.org/manual/reference/command/update/
638-
* @see Collection::getWriteOptions() for supported $options
639-
*
640-
* @param array $filter The document to be replaced
641-
* @param array $update An array of update operators to apply to the document
642-
* @param array $options Additional options
641+
* @param array|object $filter Query by which to filter documents
642+
* @param array|object $replacement Update to apply to the matched documents
643+
* @param array $options Command options
643644
* @return UpdateResult
644645
*/
645-
public function updateMany(array $filter, $update, array $options = array())
646+
public function updateMany($filter, $update, array $options = array())
646647
{
647-
$wr = $this->_update($filter, $update, $options + array("multi" => true));
648+
if ( ! isset($options['writeConcern']) && isset($this->wc)) {
649+
$options['writeConcern'] = $this->wc;
650+
}
648651

649-
return new UpdateResult($wr);
652+
$operation = new UpdateMany($this->dbname, $this->collname, $filter, $update, $options);
653+
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
654+
655+
return $operation->execute($server);
650656
}
651657

652658
/**
653-
* Update one document
654-
* NOTE: Will update at most ONE document matching $filter
659+
* Updates at most one document matching the filter.
655660
*
661+
* @see ReplaceOne::__construct() for supported options
656662
* @see http://docs.mongodb.org/manual/reference/command/update/
657-
* @see Collection::getWriteOptions() for supported $options
658-
*
659-
* @param array $filter The document to be replaced
660-
* @param array $update An array of update operators to apply to the document
661-
* @param array $options Additional options
663+
* @param array|object $filter Query by which to filter documents
664+
* @param array|object $replacement Update to apply to the matched document
665+
* @param array $options Command options
662666
* @return UpdateResult
663667
*/
664-
public function updateOne(array $filter, array $update, array $options = array())
668+
public function updateOne($filter, $update, array $options = array())
665669
{
666-
$firstKey = key($update);
667-
if (!isset($firstKey[0]) || $firstKey[0] != '$') {
668-
throw new InvalidArgumentException("First key in \$update must be a \$operator");
670+
if ( ! isset($options['writeConcern']) && isset($this->wc)) {
671+
$options['writeConcern'] = $this->wc;
669672
}
670-
$wr = $this->_update($filter, $update, $options + array("multi" => false));
671673

672-
return new UpdateResult($wr);
673-
}
674-
675-
/**
676-
* Internal helper for replacing/updating one/many documents
677-
* @internal
678-
*/
679-
protected function _update($filter, $update, $options)
680-
{
681-
$options = array_merge($this->getWriteOptions(), $options);
674+
$operation = new UpdateOne($this->dbname, $this->collname, $filter, $update, $options);
675+
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
682676

683-
$bulk = new BulkWrite($options["ordered"]);
684-
$bulk->update($filter, $update, $options);
685-
return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
677+
return $operation->execute($server);
686678
}
687679
}

src/Operation/ReplaceOne.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace MongoDB\Operation;
4+
5+
use MongoDB\UpdateResult;
6+
use MongoDB\Driver\Server;
7+
use MongoDB\Exception\InvalidArgumentException;
8+
use MongoDB\Exception\InvalidArgumentTypeException;
9+
10+
/**
11+
* Operation for replacing a single document with the update command.
12+
*
13+
* @api
14+
* @see MongoDB\Collection::replaceOne()
15+
* @see http://docs.mongodb.org/manual/reference/command/update/
16+
*/
17+
class ReplaceOne implements Executable
18+
{
19+
private $update;
20+
21+
/**
22+
* Constructs an update command.
23+
*
24+
* Supported options:
25+
*
26+
* * upsert (boolean): When true, a new document is created if no document
27+
* matches the query. The default is false.
28+
*
29+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
30+
*
31+
* @param string $databaseName Database name
32+
* @param string $collectionName Collection name
33+
* @param array|object $filter Query by which to filter documents
34+
* @param array|object $replacement Replacement document
35+
* @param array $options Command options
36+
* @throws InvalidArgumentException
37+
*/
38+
public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = array())
39+
{
40+
if ( ! is_array($replacement) && ! is_object($replacement)) {
41+
throw new InvalidArgumentTypeException('$replacement', $replacement, 'array or object');
42+
}
43+
44+
if (\MongoDB\is_first_key_operator($replacement)) {
45+
throw new InvalidArgumentException('First key in $replacement argument is an update operator');
46+
}
47+
48+
$this->update = new Update(
49+
$databaseName,
50+
$collectionName,
51+
$filter,
52+
$replacement,
53+
array('multi' => false) + $options
54+
);
55+
}
56+
57+
/**
58+
* Execute the operation.
59+
*
60+
* @see Executable::execute()
61+
* @param Server $server
62+
* @return UpdateResult
63+
*/
64+
public function execute(Server $server)
65+
{
66+
return $this->update->execute($server);
67+
}
68+
}

src/Operation/Update.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace MongoDB\Operation;
4+
5+
use MongoDB\UpdateResult;
6+
use MongoDB\Driver\BulkWrite;
7+
use MongoDB\Driver\Server;
8+
use MongoDB\Driver\WriteConcern;
9+
use MongoDB\Exception\InvalidArgumentException;
10+
use MongoDB\Exception\InvalidArgumentTypeException;
11+
12+
/**
13+
* Operation for the update command.
14+
*
15+
* This class is used internally by the ReplaceOne, UpdateMany, and UpdateOne
16+
* operation classes.
17+
*
18+
* @internal
19+
* @see http://docs.mongodb.org/manual/reference/command/update/
20+
*/
21+
class Update implements Executable
22+
{
23+
private $databaseName;
24+
private $collectionName;
25+
private $filter;
26+
private $update;
27+
private $options;
28+
29+
/**
30+
* Constructs a update command.
31+
*
32+
* Supported options:
33+
*
34+
* * multi (boolean): When true, updates all documents matching the query.
35+
* This option cannot be true if the $update argument is a replacement
36+
* document (i.e. contains no update operators). The default is false.
37+
*
38+
* * upsert (boolean): When true, a new document is created if no document
39+
* matches the query. The default is false.
40+
*
41+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
42+
*
43+
* @param string $databaseName Database name
44+
* @param string $collectionName Collection name
45+
* @param array|object $filter Query by which to delete documents
46+
* @param array|object $update Update to apply to the matched
47+
* document(s) or a replacement document
48+
* @param array $options Command options
49+
* @throws InvalidArgumentException
50+
*/
51+
public function __construct($databaseName, $collectionName, $filter, $update, array $options = array())
52+
{
53+
if ( ! is_array($filter) && ! is_object($filter)) {
54+
throw new InvalidArgumentTypeException('$filter', $filter, 'array or object');
55+
}
56+
57+
if ( ! is_array($update) && ! is_object($update)) {
58+
throw new InvalidArgumentTypeException('$update', $filter, 'array or object');
59+
}
60+
61+
$options += array(
62+
'multi' => false,
63+
'upsert' => false,
64+
);
65+
66+
if ( ! is_bool($options['multi'])) {
67+
throw new InvalidArgumentTypeException('"multi" option', $options['multi'], 'boolean');
68+
}
69+
70+
if ($options['multi'] && ! \MongoDB\is_first_key_operator($update)) {
71+
throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document');
72+
}
73+
74+
if ( ! is_bool($options['upsert'])) {
75+
throw new InvalidArgumentTypeException('"upsert" option', $options['upsert'], 'boolean');
76+
}
77+
78+
if (array_key_exists('writeConcern', $options) && ! $options['writeConcern'] instanceof WriteConcern) {
79+
throw new InvalidArgumentTypeException('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
80+
}
81+
82+
$this->databaseName = (string) $databaseName;
83+
$this->collectionName = (string) $collectionName;
84+
$this->filter = $filter;
85+
$this->update = $update;
86+
$this->options = $options;
87+
}
88+
89+
/**
90+
* Execute the operation.
91+
*
92+
* @see Executable::execute()
93+
* @param Server $server
94+
* @return UpdateResult
95+
*/
96+
public function execute(Server $server)
97+
{
98+
$options = array(
99+
'multi' => $this->options['multi'],
100+
'upsert' => $this->options['upsert'],
101+
);
102+
103+
$bulk = new BulkWrite();
104+
$bulk->update($this->filter, $this->update, $options);
105+
106+
$writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null;
107+
$writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern);
108+
109+
return new UpdateResult($writeResult);
110+
}
111+
}

src/Operation/UpdateMany.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace MongoDB\Operation;
4+
5+
use MongoDB\UpdateResult;
6+
use MongoDB\Driver\Server;
7+
use MongoDB\Exception\InvalidArgumentException;
8+
use MongoDB\Exception\InvalidArgumentTypeException;
9+
10+
/**
11+
* Operation for updating multiple documents with the update command.
12+
*
13+
* @api
14+
* @see MongoDB\Collection::updateMany()
15+
* @see http://docs.mongodb.org/manual/reference/command/update/
16+
*/
17+
class UpdateMany implements Executable
18+
{
19+
private $update;
20+
21+
/**
22+
* Constructs an update command.
23+
*
24+
* Supported options:
25+
*
26+
* * upsert (boolean): When true, a new document is created if no document
27+
* matches the query. The default is false.
28+
*
29+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
30+
*
31+
* @param string $databaseName Database name
32+
* @param string $collectionName Collection name
33+
* @param array|object $filter Query by which to filter documents
34+
* @param array|object $update Update to apply to the matched documents
35+
* @param array $options Command options
36+
* @throws InvalidArgumentException
37+
*/
38+
public function __construct($databaseName, $collectionName, $filter, $update, array $options = array())
39+
{
40+
if ( ! is_array($update) && ! is_object($update)) {
41+
throw new InvalidArgumentTypeException('$update', $update, 'array or object');
42+
}
43+
44+
if ( ! \MongoDB\is_first_key_operator($update)) {
45+
throw new InvalidArgumentException('First key in $update argument is not an update operator');
46+
}
47+
48+
$this->update = new Update(
49+
$databaseName,
50+
$collectionName,
51+
$filter,
52+
$update,
53+
array('multi' => true) + $options
54+
);
55+
}
56+
57+
/**
58+
* Execute the operation.
59+
*
60+
* @see Executable::execute()
61+
* @param Server $server
62+
* @return UpdateResult
63+
*/
64+
public function execute(Server $server)
65+
{
66+
return $this->update->execute($server);
67+
}
68+
}

0 commit comments

Comments
 (0)