Skip to content

[PHPLIB-112] Configurable type map for findAndModify and non-cursor aggregate commands #300

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ source:
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: typeMap
post: |
.. note::

This is not supported for inline aggregation results (i.e. ``useCursor``
option is ``false`` or the server version is < 2.6).
---
arg_name: option
name: useCursor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ source:
file: apiargs-common-option.yaml
ref: maxTimeMS
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: typeMap
post: |
This will be used for the returned result document.
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: writeConcern
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: typeMap
post: |
This will be used for the returned result document.
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: upsert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: typeMap
post: |
This will be used for the returned result document.
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: upsert
Expand Down
12 changes: 0 additions & 12 deletions docs/includes/extracts-bson-deserialization-base.yaml

This file was deleted.

21 changes: 0 additions & 21 deletions docs/includes/extracts-bson-deserialization.yaml

This file was deleted.

8 changes: 0 additions & 8 deletions docs/reference/method/MongoDBCollection-aggregate.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,6 @@ MongoDB server version and whether the ``useCursor`` option is specified. If
``result`` array from the command response document. In both cases, the return
value will be :php:`Traversable <traversable>`.

.. note::

BSON deserialization of inline aggregation results (i.e. not using a command
cursor) does not yet support a ``typeMap`` option. Classes implementing
:php:`MongoDB\\BSON\\Persistable <mongodb-bson-persistable>` will still be
deserialized according to the
:php:`Persistence <mongodb.persistence.deserialization>` specification.

.. todo: add examples

See Also
Expand Down
6 changes: 2 additions & 4 deletions docs/reference/method/MongoDBCollection-findOneAndDelete.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ Definition

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

.. include:: /includes/extracts/bson-deserialization-findOneAndDelete.rst

Return Values
-------------

An object for the document that was deleted, or ``null`` if no document matched
the query.
An array or object for the document that was deleted, or ``null`` if no document
matched the query. The return type will depend on the ``typeMap`` option.

Errors/Exceptions
-----------------
Expand Down
7 changes: 3 additions & 4 deletions docs/reference/method/MongoDBCollection-findOneAndReplace.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ Definition

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

.. include:: /includes/extracts/bson-deserialization-findOneAndReplace.rst

Return Values
-------------

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

Errors/Exceptions
-----------------
Expand Down
7 changes: 3 additions & 4 deletions docs/reference/method/MongoDBCollection-findOneAndUpdate.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ Definition

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

.. include:: /includes/extracts/bson-deserialization-findOneAndUpdate.rst

Return Values
-------------

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

Errors/Exceptions
-----------------
Expand Down
31 changes: 15 additions & 16 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,6 @@ public function __toString()
* returned; otherwise, an ArrayIterator is returned, which wraps the
* "result" array from the command response document.
*
* Note: BSON deserialization of inline aggregation results (i.e. not using
* a command cursor) does not yet support a custom type map
* (depends on: https://jira.mongodb.org/browse/PHPC-314).
*
* @see Aggregate::__construct() for supported options
* @param array $pipeline List of pipeline operations
* @param array $options Command options
Expand Down Expand Up @@ -553,14 +549,11 @@ public function findOne($filter = [], array $options = [])
*
* The document to return may be null if no document matched the filter.
*
* Note: BSON deserialization of the returned document does not yet support
* a custom type map (depends on: https://jira.mongodb.org/browse/PHPC-314).
*
* @see FindOneAndDelete::__construct() for supported options
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
* @param array|object $filter Query by which to filter documents
* @param array $options Command options
* @return object|null
* @return array|object|null
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
Expand All @@ -574,6 +567,10 @@ public function findOneAndDelete($filter, array $options = [])
$options['writeConcern'] = $this->writeConcern;
}

if ( ! isset($options['typeMap'])) {
$options['typeMap'] = $this->typeMap;
}

$operation = new FindOneAndDelete($this->databaseName, $this->collectionName, $filter, $options);

return $operation->execute($server);
Expand All @@ -588,15 +585,12 @@ public function findOneAndDelete($filter, array $options = [])
* FindOneAndReplace::RETURN_DOCUMENT_AFTER for the "returnDocument" option
* to return the updated document.
*
* Note: BSON deserialization of the returned document does not yet support
* a custom type map (depends on: https://jira.mongodb.org/browse/PHPC-314).
*
* @see FindOneAndReplace::__construct() for supported options
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
* @param array|object $filter Query by which to filter documents
* @param array|object $replacement Replacement document
* @param array $options Command options
* @return object|null
* @return array|object|null
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
Expand All @@ -610,6 +604,10 @@ public function findOneAndReplace($filter, $replacement, array $options = [])
$options['writeConcern'] = $this->writeConcern;
}

if ( ! isset($options['typeMap'])) {
$options['typeMap'] = $this->typeMap;
}

$operation = new FindOneAndReplace($this->databaseName, $this->collectionName, $filter, $replacement, $options);

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

if ( ! isset($options['typeMap'])) {
$options['typeMap'] = $this->typeMap;
}

$operation = new FindOneAndUpdate($this->databaseName, $this->collectionName, $filter, $update, $options);

return $operation->execute($server);
Expand Down
4 changes: 2 additions & 2 deletions src/GridFS/Bucket.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ public function getFileDocumentForStream($stream)
$file = $this->getRawFileDocumentForStream($stream);

// Filter the raw document through the specified type map
return \MongoDB\BSON\toPHP(\MongoDB\BSON\fromPHP($file), $this->typeMap);
return \MongoDB\apply_type_map_to_document($file, $this->typeMap);
}

/**
Expand All @@ -302,7 +302,7 @@ public function getFileIdForStream($stream)
* the root type so we can reliably access the ID.
*/
$typeMap = ['root' => 'stdClass'] + $this->typeMap;
$file = \MongoDB\BSON\toPHP(\MongoDB\BSON\fromPHP($file), $typeMap);
$file = \MongoDB\apply_type_map_to_document($file, $typeMap);

if ( ! isset($file->_id) && ! property_exists($file, '_id')) {
throw new CorruptFileException('file._id does not exist');
Expand Down
44 changes: 44 additions & 0 deletions src/Model/TypeMapArrayIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace MongoDB\Model;

use ArrayIterator;

/**
* Iterator for applying a type map to documents in inline command results.
*
* This iterator may be used to apply a type map to an array of documents
* returned by a database command (e.g. aggregate on servers < 2.6) and allows
* for functional equivalence with commands that return their results via a
* cursor (e.g. aggregate on servers >= 2.6).
*
* @internal
*/
class TypeMapArrayIterator extends ArrayIterator
{
private $typeMap;

/**
* Constructor.
*
* @param array $documents
* @param array $typeMap
*/
public function __construct(array $documents = [], array $typeMap)
{
parent::__construct($documents);

$this->typeMap = $typeMap;
}

/**
* Return the current element with the type map applied to it.
*
* @see http://php.net/arrayiterator.current
* @return array|object
*/
public function current()
{
return \MongoDB\apply_type_map_to_document(parent::current(), $this->typeMap);
}
}
11 changes: 5 additions & 6 deletions src/Operation/Aggregate.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\UnexpectedValueException;
use MongoDB\Exception\UnsupportedException;
use MongoDB\Model\TypeMapArrayIterator;
use ArrayIterator;
use stdClass;
use Traversable;
Expand Down Expand Up @@ -72,9 +73,6 @@ class Aggregate implements Executable
* * typeMap (array): Type map for BSON deserialization. This will be
* applied to the returned Cursor (it is not sent to the server).
*
* This is not supported for inline aggregation results (i.e. useCursor
* option is false or the server version is < 2.6).
*
* * useCursor (boolean): Indicates whether the command will request that
* the server provide results using a cursor. The default is true.
*
Expand Down Expand Up @@ -206,9 +204,6 @@ public function execute(Server $server)
$cursor = $server->executeCommand($this->databaseName, $command, $readPreference);

if ($isCursorSupported && $this->options['useCursor']) {
/* The type map can only be applied to command cursors until
* https://jira.mongodb.org/browse/PHPC-314 is implemented.
*/
if (isset($this->options['typeMap'])) {
$cursor->setTypeMap($this->options['typeMap']);
}
Expand All @@ -222,6 +217,10 @@ public function execute(Server $server)
throw new UnexpectedValueException('aggregate command did not return a "result" array');
}

if (isset($this->options['typeMap'])) {
return new TypeMapArrayIterator($result->result, $this->options['typeMap']);
}

return new ArrayIterator($result->result);
}

Expand Down
12 changes: 11 additions & 1 deletion src/Operation/FindAndModify.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class FindAndModify implements Executable
* * sort (document): Determines which document the operation modifies if
* the query selects multiple documents.
*
* * typeMap (array): Type map for BSON deserialization.
*
* * update (document): Update or replacement to apply to the matched
* document. This option cannot be set if the remove option is true.
*
Expand Down Expand Up @@ -117,6 +119,10 @@ public function __construct($databaseName, $collectionName, array $options)
throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object');
}

if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
}

if (isset($options['update']) && ! is_array($options['update']) && ! is_object($options['update'])) {
throw InvalidArgumentException::invalidType('"update" option', $options['update'], 'array or object');
}
Expand All @@ -143,7 +149,7 @@ public function __construct($databaseName, $collectionName, array $options)
*
* @see Executable::execute()
* @param Server $server
* @return object|null
* @return array|object|null
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if collation or write concern is used and unsupported
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
Expand Down Expand Up @@ -180,6 +186,10 @@ public function execute(Server $server)
throw new UnexpectedValueException('findAndModify command did not return a "value" document');
}

if (isset($this->options['typeMap'])) {
return \MongoDB\apply_type_map_to_document($result->value, $this->options['typeMap']);
}

return $result->value;
}

Expand Down
Loading