Skip to content

Commit 5c6705b

Browse files
committed
PHPLIB-112: Support typeMap option for findAndModify operations
1 parent e7a5e3c commit 5c6705b

15 files changed

+138
-61
lines changed

docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ source:
1414
file: apiargs-common-option.yaml
1515
ref: maxTimeMS
1616
---
17+
source:
18+
file: apiargs-MongoDBCollection-common-option.yaml
19+
ref: typeMap
20+
post: |
21+
This will be used for the returned result document.
22+
---
1723
source:
1824
file: apiargs-MongoDBCollection-common-option.yaml
1925
ref: writeConcern

docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ interface: phpmethod
3131
operation: ~
3232
optional: true
3333
---
34+
source:
35+
file: apiargs-MongoDBCollection-common-option.yaml
36+
ref: typeMap
37+
post: |
38+
This will be used for the returned result document.
39+
---
3440
source:
3541
file: apiargs-MongoDBCollection-common-option.yaml
3642
ref: upsert

docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ interface: phpmethod
3131
operation: ~
3232
optional: true
3333
---
34+
source:
35+
file: apiargs-MongoDBCollection-common-option.yaml
36+
ref: typeMap
37+
post: |
38+
This will be used for the returned result document.
39+
---
3440
source:
3541
file: apiargs-MongoDBCollection-common-option.yaml
3642
ref: upsert

docs/includes/extracts-bson-deserialization-base.yaml

Lines changed: 0 additions & 12 deletions
This file was deleted.

docs/includes/extracts-bson-deserialization.yaml

Lines changed: 0 additions & 21 deletions
This file was deleted.

docs/reference/method/MongoDBCollection-findOneAndDelete.txt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@ Definition
2929

3030
.. include:: /includes/apiargs/MongoDBCollection-method-findOneAndDelete-option.rst
3131

32-
.. include:: /includes/extracts/bson-deserialization-findOneAndDelete.rst
33-
3432
Return Values
3533
-------------
3634

37-
An object for the document that was deleted, or ``null`` if no document matched
38-
the query.
35+
An array or object for the document that was deleted, or ``null`` if no document
36+
matched the query. The return type will depend on the ``typeMap`` option.
3937

4038
Errors/Exceptions
4139
-----------------

docs/reference/method/MongoDBCollection-findOneAndReplace.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,13 @@ Definition
2929

3030
.. include:: /includes/apiargs/MongoDBCollection-method-findOneAndReplace-option.rst
3131

32-
.. include:: /includes/extracts/bson-deserialization-findOneAndReplace.rst
33-
3432
Return Values
3533
-------------
3634

37-
An object for either the original or the replaced document, depending on the
38-
specified value of the ``returnDocument`` option. By default, the original
35+
An array object for either the original or the replaced document, depending on
36+
the specified value of the ``returnDocument`` option. By default, the original
3937
document is returned. If no document matched the query, ``null`` is returned.
38+
The return type will depend on the ``typeMap`` option.
4039

4140
Errors/Exceptions
4241
-----------------

docs/reference/method/MongoDBCollection-findOneAndUpdate.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,13 @@ Definition
2929

3030
.. include:: /includes/apiargs/MongoDBCollection-method-findOneAndUpdate-option.rst
3131

32-
.. include:: /includes/extracts/bson-deserialization-findOneAndUpdate.rst
33-
3432
Return Values
3533
-------------
3634

37-
An object for either the original or the updated document, depending on the
38-
specified value of the ``returnDocument`` option. By default, the original
35+
An array or object for either the original or the updated document, depending on
36+
the specified value of the ``returnDocument`` option. By default, the original
3937
document is returned. If no document matched the query, ``null`` is returned.
38+
The return type will depend on the ``typeMap`` option.
4039

4140
Errors/Exceptions
4241
-----------------

src/Collection.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -553,14 +553,11 @@ public function findOne($filter = [], array $options = [])
553553
*
554554
* The document to return may be null if no document matched the filter.
555555
*
556-
* Note: BSON deserialization of the returned document does not yet support
557-
* a custom type map (depends on: https://jira.mongodb.org/browse/PHPC-314).
558-
*
559556
* @see FindOneAndDelete::__construct() for supported options
560557
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
561558
* @param array|object $filter Query by which to filter documents
562559
* @param array $options Command options
563-
* @return object|null
560+
* @return array|object|null
564561
* @throws UnexpectedValueException if the command response was malformed
565562
* @throws UnsupportedException if options are not supported by the selected server
566563
* @throws InvalidArgumentException for parameter/option parsing errors
@@ -574,6 +571,10 @@ public function findOneAndDelete($filter, array $options = [])
574571
$options['writeConcern'] = $this->writeConcern;
575572
}
576573

574+
if ( ! isset($options['typeMap'])) {
575+
$options['typeMap'] = $this->typeMap;
576+
}
577+
577578
$operation = new FindOneAndDelete($this->databaseName, $this->collectionName, $filter, $options);
578579

579580
return $operation->execute($server);
@@ -588,15 +589,12 @@ public function findOneAndDelete($filter, array $options = [])
588589
* FindOneAndReplace::RETURN_DOCUMENT_AFTER for the "returnDocument" option
589590
* to return the updated document.
590591
*
591-
* Note: BSON deserialization of the returned document does not yet support
592-
* a custom type map (depends on: https://jira.mongodb.org/browse/PHPC-314).
593-
*
594592
* @see FindOneAndReplace::__construct() for supported options
595593
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
596594
* @param array|object $filter Query by which to filter documents
597595
* @param array|object $replacement Replacement document
598596
* @param array $options Command options
599-
* @return object|null
597+
* @return array|object|null
600598
* @throws UnexpectedValueException if the command response was malformed
601599
* @throws UnsupportedException if options are not supported by the selected server
602600
* @throws InvalidArgumentException for parameter/option parsing errors
@@ -610,6 +608,10 @@ public function findOneAndReplace($filter, $replacement, array $options = [])
610608
$options['writeConcern'] = $this->writeConcern;
611609
}
612610

611+
if ( ! isset($options['typeMap'])) {
612+
$options['typeMap'] = $this->typeMap;
613+
}
614+
613615
$operation = new FindOneAndReplace($this->databaseName, $this->collectionName, $filter, $replacement, $options);
614616

615617
return $operation->execute($server);
@@ -624,15 +626,12 @@ public function findOneAndReplace($filter, $replacement, array $options = [])
624626
* FindOneAndUpdate::RETURN_DOCUMENT_AFTER for the "returnDocument" option
625627
* to return the updated document.
626628
*
627-
* Note: BSON deserialization of the returned document does not yet support
628-
* a custom type map (depends on: https://jira.mongodb.org/browse/PHPC-314).
629-
*
630629
* @see FindOneAndReplace::__construct() for supported options
631630
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
632631
* @param array|object $filter Query by which to filter documents
633632
* @param array|object $update Update to apply to the matched document
634633
* @param array $options Command options
635-
* @return object|null
634+
* @return array|object|null
636635
* @throws UnexpectedValueException if the command response was malformed
637636
* @throws UnsupportedException if options are not supported by the selected server
638637
* @throws InvalidArgumentException for parameter/option parsing errors
@@ -646,6 +645,10 @@ public function findOneAndUpdate($filter, $update, array $options = [])
646645
$options['writeConcern'] = $this->writeConcern;
647646
}
648647

648+
if ( ! isset($options['typeMap'])) {
649+
$options['typeMap'] = $this->typeMap;
650+
}
651+
649652
$operation = new FindOneAndUpdate($this->databaseName, $this->collectionName, $filter, $update, $options);
650653

651654
return $operation->execute($server);

src/Operation/FindAndModify.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class FindAndModify implements Executable
6060
* * sort (document): Determines which document the operation modifies if
6161
* the query selects multiple documents.
6262
*
63+
* * typeMap (array): Type map for BSON deserialization.
64+
*
6365
* * update (document): Update or replacement to apply to the matched
6466
* document. This option cannot be set if the remove option is true.
6567
*
@@ -117,6 +119,10 @@ public function __construct($databaseName, $collectionName, array $options)
117119
throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object');
118120
}
119121

122+
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
123+
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
124+
}
125+
120126
if (isset($options['update']) && ! is_array($options['update']) && ! is_object($options['update'])) {
121127
throw InvalidArgumentException::invalidType('"update" option', $options['update'], 'array or object');
122128
}
@@ -143,7 +149,7 @@ public function __construct($databaseName, $collectionName, array $options)
143149
*
144150
* @see Executable::execute()
145151
* @param Server $server
146-
* @return object|null
152+
* @return array|object|null
147153
* @throws UnexpectedValueException if the command response was malformed
148154
* @throws UnsupportedException if collation or write concern is used and unsupported
149155
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
@@ -180,6 +186,10 @@ public function execute(Server $server)
180186
throw new UnexpectedValueException('findAndModify command did not return a "value" document');
181187
}
182188

189+
if (isset($this->options['typeMap'])) {
190+
return \MongoDB\apply_type_map_to_document($result->value, $this->options['typeMap']);
191+
}
192+
183193
return $result->value;
184194
}
185195

src/Operation/FindOneAndDelete.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class FindOneAndDelete implements Executable
3737
* * sort (document): Determines which document the operation modifies if
3838
* the query selects multiple documents.
3939
*
40+
* * typeMap (array): Type map for BSON deserialization.
41+
*
4042
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
4143
*
4244
* This is not supported for server versions < 3.2 and will result in an
@@ -76,7 +78,7 @@ public function __construct($databaseName, $collectionName, $filter, array $opti
7678
*
7779
* @see Executable::execute()
7880
* @param Server $server
79-
* @return object|null
81+
* @return array|object|null
8082
* @throws UnsupportedException if collation or write concern is used and unsupported
8183
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
8284
*/

src/Operation/FindOneAndReplace.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class FindOneAndReplace implements Executable
4949
* * sort (document): Determines which document the operation modifies if
5050
* the query selects multiple documents.
5151
*
52+
* * typeMap (array): Type map for BSON deserialization.
53+
*
5254
* * upsert (boolean): When true, a new document is created if no document
5355
* matches the query. The default is false.
5456
*
@@ -116,7 +118,7 @@ public function __construct($databaseName, $collectionName, $filter, $replacemen
116118
*
117119
* @see Executable::execute()
118120
* @param Server $server
119-
* @return object|null
121+
* @return array|object|null
120122
* @throws UnsupportedException if collation or write concern is used and unsupported
121123
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
122124
*/

src/Operation/FindOneAndUpdate.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class FindOneAndUpdate implements Executable
4949
* * sort (document): Determines which document the operation modifies if
5050
* the query selects multiple documents.
5151
*
52+
* * typeMap (array): Type map for BSON deserialization.
53+
*
5254
* * upsert (boolean): When true, a new document is created if no document
5355
* matches the query. The default is false.
5456
*
@@ -116,7 +118,7 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar
116118
*
117119
* @see Executable::execute()
118120
* @param Server $server
119-
* @return object|null
121+
* @return array|object|null
120122
* @throws UnsupportedException if collation or write concern is used and unsupported
121123
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
122124
*/
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\Operation;
4+
5+
use MongoDB\Driver\BulkWrite;
6+
use MongoDB\Model\BSONDocument;
7+
use MongoDB\Operation\FindAndModify;
8+
9+
class FindAndModifyFunctionalTest extends FunctionalTestCase
10+
{
11+
/**
12+
* @dataProvider provideTypeMapOptionsAndExpectedDocument
13+
*/
14+
public function testTypeMapOption(array $typeMap, $expectedDocument)
15+
{
16+
$this->createFixtures(1);
17+
18+
$operation = new FindAndModify(
19+
$this->getDatabaseName(),
20+
$this->getCollectionName(),
21+
[
22+
'remove' => true,
23+
'typeMap' => $typeMap,
24+
]
25+
);
26+
$document = $operation->execute($this->getPrimaryServer());
27+
28+
$this->assertEquals($expectedDocument, $document);
29+
}
30+
31+
public function provideTypeMapOptionsAndExpectedDocument()
32+
{
33+
return [
34+
[
35+
['root' => 'array', 'document' => 'array'],
36+
['_id' => 1, 'x' => ['foo' => 'bar']],
37+
],
38+
[
39+
['root' => 'object', 'document' => 'array'],
40+
(object) ['_id' => 1, 'x' => ['foo' => 'bar']],
41+
],
42+
[
43+
['root' => 'array', 'document' => 'stdClass'],
44+
['_id' => 1, 'x' => (object) ['foo' => 'bar']],
45+
],
46+
[
47+
['root' => 'MongoDB\Model\BSONDocument', 'document' => 'object'],
48+
new BSONDocument(['_id' => 1, 'x' => (object) ['foo' => 'bar']]),
49+
],
50+
];
51+
}
52+
53+
/**
54+
* Create data fixtures.
55+
*
56+
* @param integer $n
57+
*/
58+
private function createFixtures($n)
59+
{
60+
$bulkWrite = new BulkWrite(['ordered' => true]);
61+
62+
for ($i = 1; $i <= $n; $i++) {
63+
$bulkWrite->insert([
64+
'_id' => $i,
65+
'x' => (object) ['foo' => 'bar'],
66+
]);
67+
}
68+
69+
$result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite);
70+
71+
$this->assertEquals($n, $result->getInsertedCount());
72+
}
73+
}

tests/Operation/FindAndModifyTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ public function provideInvalidConstructorOptions()
5151
$options[][] = ['sort' => $value];
5252
}
5353

54+
foreach ($this->getInvalidArrayValues() as $value) {
55+
$options[][] = ['typeMap' => $value];
56+
}
57+
5458
foreach ($this->getInvalidDocumentValues() as $value) {
5559
$options[][] = ['update' => $value];
5660
}

0 commit comments

Comments
 (0)