Skip to content

Commit 94361cc

Browse files
committed
PHPLIB-109: Extract ReplaceOne, UpdateOne, and UpdateMany operation classes
1 parent c1e85c4 commit 94361cc

File tree

5 files changed

+347
-49
lines changed

5 files changed

+347
-49
lines changed

src/Collection.php

Lines changed: 35 additions & 49 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
@@ -601,79 +604,62 @@ public function listIndexes(array $options = array())
601604
}
602605

603606
/**
604-
* Replace one document
607+
* Replaces at most one document matching the filter.
605608
*
609+
* @see ReplaceOne::__construct() for supported options
606610
* @see http://docs.mongodb.org/manual/reference/command/update/
607-
* @see Collection::getWriteOptions() for supported $options
608-
*
609-
* @param array $filter The document to be replaced
610-
* @param array $update The document to replace with
611-
* @param array $options Additional options
611+
* @param array|object $filter Query by which to filter documents
612+
* @param array|object $replacement Replacement document
613+
* @param array $options Command options
612614
* @return UpdateResult
613615
*/
614-
public function replaceOne(array $filter, array $update, array $options = array())
616+
public function replaceOne($filter, $replacement, array $options = array())
615617
{
616-
$firstKey = key($update);
617-
if (isset($firstKey[0]) && $firstKey[0] == '$') {
618-
throw new InvalidArgumentException("First key in \$update must NOT be a \$operator");
619-
}
620-
$wr = $this->_update($filter, $update, $options + array("multi" => false));
618+
$options += array('writeConcern' => $this->wc);
619+
620+
$operation = new ReplaceOne($this->dbname, $this->collname, $filter, $replacement, $options);
621+
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
621622

622-
return new UpdateResult($wr);
623+
return $operation->execute($server);
623624
}
624625

625626
/**
626-
* Update one document
627-
* NOTE: Will update ALL documents matching $filter
627+
* Updates all documents matching the filter.
628628
*
629+
* @see UpdateMany::__construct() for supported options
629630
* @see http://docs.mongodb.org/manual/reference/command/update/
630-
* @see Collection::getWriteOptions() for supported $options
631-
*
632-
* @param array $filter The document to be replaced
633-
* @param array $update An array of update operators to apply to the document
634-
* @param array $options Additional options
631+
* @param array|object $filter Query by which to filter documents
632+
* @param array|object $replacement Update to apply to the matched documents
633+
* @param array $options Command options
635634
* @return UpdateResult
636635
*/
637-
public function updateMany(array $filter, $update, array $options = array())
636+
public function updateMany($filter, $update, array $options = array())
638637
{
639-
$wr = $this->_update($filter, $update, $options + array("multi" => true));
638+
$options += array('writeConcern' => $this->wc);
639+
640+
$operation = new UpdateMany($this->dbname, $this->collname, $filter, $update, $options);
641+
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
640642

641-
return new UpdateResult($wr);
643+
return $operation->execute($server);
642644
}
643645

644646
/**
645-
* Update one document
646-
* NOTE: Will update at most ONE document matching $filter
647+
* Updates at most one document matching the filter.
647648
*
649+
* @see ReplaceOne::__construct() for supported options
648650
* @see http://docs.mongodb.org/manual/reference/command/update/
649-
* @see Collection::getWriteOptions() for supported $options
650-
*
651-
* @param array $filter The document to be replaced
652-
* @param array $update An array of update operators to apply to the document
653-
* @param array $options Additional options
651+
* @param array|object $filter Query by which to filter documents
652+
* @param array|object $replacement Update to apply to the matched document
653+
* @param array $options Command options
654654
* @return UpdateResult
655655
*/
656-
public function updateOne(array $filter, array $update, array $options = array())
656+
public function updateOne($filter, $update, array $options = array())
657657
{
658-
$firstKey = key($update);
659-
if (!isset($firstKey[0]) || $firstKey[0] != '$') {
660-
throw new InvalidArgumentException("First key in \$update must be a \$operator");
661-
}
662-
$wr = $this->_update($filter, $update, $options + array("multi" => false));
663-
664-
return new UpdateResult($wr);
665-
}
658+
$options += array('writeConcern' => $this->wc);
666659

667-
/**
668-
* Internal helper for replacing/updating one/many documents
669-
* @internal
670-
*/
671-
protected function _update($filter, $update, $options)
672-
{
673-
$options = array_merge($this->getWriteOptions(), $options);
660+
$operation = new UpdateOne($this->dbname, $this->collname, $filter, $update, $options);
661+
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
674662

675-
$bulk = new BulkWrite($options["ordered"]);
676-
$bulk->update($filter, $update, $options);
677-
return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
663+
return $operation->execute($server);
678664
}
679665
}

src/Operation/ReplaceOne.php

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

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

0 commit comments

Comments
 (0)