Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongo-php-library
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sinan
mongo-php-library
Commits
9739904e
Commit
9739904e
authored
Jun 26, 2018
by
Jeremy Mikola
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #544
parents
c0d35516
eb2cd59f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
52 changed files
with
1097 additions
and
267 deletions
+1097
-267
apiargs-MongoDBClient-common-option.yaml
docs/includes/apiargs-MongoDBClient-common-option.yaml
+37
-0
apiargs-MongoDBClient-method-dropDatabase-option.yaml
...des/apiargs-MongoDBClient-method-dropDatabase-option.yaml
+4
-10
apiargs-MongoDBClient-method-watch-option.yaml
docs/includes/apiargs-MongoDBClient-method-watch-option.yaml
+44
-0
apiargs-MongoDBClient-method-watch-param.yaml
docs/includes/apiargs-MongoDBClient-method-watch-param.yaml
+8
-0
apiargs-MongoDBCollection-common-option.yaml
docs/includes/apiargs-MongoDBCollection-common-option.yaml
+4
-17
apiargs-MongoDBCollection-method-watch-option.yaml
...cludes/apiargs-MongoDBCollection-method-watch-option.yaml
+19
-50
apiargs-MongoDBCollection-method-watch-param.yaml
...ncludes/apiargs-MongoDBCollection-method-watch-param.yaml
+4
-9
apiargs-MongoDBDatabase-common-option.yaml
docs/includes/apiargs-MongoDBDatabase-common-option.yaml
+23
-0
apiargs-MongoDBDatabase-method-createCollection-option.yaml
...iargs-MongoDBDatabase-method-createCollection-option.yaml
+1
-1
apiargs-MongoDBDatabase-method-watch-option.yaml
...includes/apiargs-MongoDBDatabase-method-watch-option.yaml
+44
-0
apiargs-MongoDBDatabase-method-watch-param.yaml
.../includes/apiargs-MongoDBDatabase-method-watch-param.yaml
+8
-0
apiargs-common-option.yaml
docs/includes/apiargs-common-option.yaml
+17
-0
apiargs-method-watch-option.yaml
docs/includes/apiargs-method-watch-option.yaml
+81
-0
apiargs-method-watch-param.yaml
docs/includes/apiargs-method-watch-param.yaml
+13
-0
MongoDBClient.txt
docs/reference/class/MongoDBClient.txt
+1
-0
MongoDBDatabase.txt
docs/reference/class/MongoDBDatabase.txt
+1
-0
MongoDBClient-watch.txt
docs/reference/method/MongoDBClient-watch.txt
+121
-0
MongoDBCollection-watch.txt
docs/reference/method/MongoDBCollection-watch.txt
+11
-6
MongoDBDatabase-watch.txt
docs/reference/method/MongoDBDatabase-watch.txt
+120
-0
ChangeStream.php
src/ChangeStream.php
+40
-27
Client.php
src/Client.php
+38
-2
Database.php
src/Database.php
+32
-0
Aggregate.php
src/Operation/Aggregate.php
+9
-6
Watch.php
src/Operation/Watch.php
+134
-32
CollectionFunctionalTest.php
tests/Collection/CollectionFunctionalTest.php
+2
-1
CommandObserver.php
tests/CommandObserver.php
+3
-1
DocumentationExamplesTest.php
tests/DocumentationExamplesTest.php
+2
-2
ReadableStreamFunctionalTest.php
tests/GridFS/ReadableStreamFunctionalTest.php
+6
-6
AggregateFunctionalTest.php
tests/Operation/AggregateFunctionalTest.php
+30
-8
BulkWriteFunctionalTest.php
tests/Operation/BulkWriteFunctionalTest.php
+2
-2
CountFunctionalTest.php
tests/Operation/CountFunctionalTest.php
+4
-4
CreateCollectionFunctionalTest.php
tests/Operation/CreateCollectionFunctionalTest.php
+4
-4
CreateIndexesFunctionalTest.php
tests/Operation/CreateIndexesFunctionalTest.php
+4
-4
DatabaseCommandFunctionalTest.php
tests/Operation/DatabaseCommandFunctionalTest.php
+2
-2
DeleteFunctionalTest.php
tests/Operation/DeleteFunctionalTest.php
+2
-2
DistinctFunctionalTest.php
tests/Operation/DistinctFunctionalTest.php
+4
-4
DropCollectionFunctionalTest.php
tests/Operation/DropCollectionFunctionalTest.php
+4
-4
DropDatabaseFunctionalTest.php
tests/Operation/DropDatabaseFunctionalTest.php
+4
-4
DropIndexesFunctionalTest.php
tests/Operation/DropIndexesFunctionalTest.php
+4
-4
ExplainFunctionalTest.php
tests/Operation/ExplainFunctionalTest.php
+4
-2
FindAndModifyFunctionalTest.php
tests/Operation/FindAndModifyFunctionalTest.php
+6
-6
FindFunctionalTest.php
tests/Operation/FindFunctionalTest.php
+4
-4
InsertManyFunctionalTest.php
tests/Operation/InsertManyFunctionalTest.php
+2
-2
InsertOneFunctionalTest.php
tests/Operation/InsertOneFunctionalTest.php
+2
-2
ListCollectionsFunctionalTest.php
tests/Operation/ListCollectionsFunctionalTest.php
+2
-2
ListDatabasesFunctionalTest.php
tests/Operation/ListDatabasesFunctionalTest.php
+2
-2
ListIndexesFunctionalTest.php
tests/Operation/ListIndexesFunctionalTest.php
+2
-2
MapReduceFunctionalTest.php
tests/Operation/MapReduceFunctionalTest.php
+6
-6
UpdateFunctionalTest.php
tests/Operation/UpdateFunctionalTest.php
+2
-2
WatchFunctionalTest.php
tests/Operation/WatchFunctionalTest.php
+113
-25
WatchTest.php
tests/Operation/WatchTest.php
+18
-0
TestCase.php
tests/TestCase.php
+43
-0
No files found.
docs/includes/apiargs-MongoDBClient-common-option.yaml
0 → 100644
View file @
9739904e
arg_name
:
option
name
:
readConcern
type
:
:php:`MongoDB\\Driver\\ReadConcern <class.mongodb-driver-readconcern>`
description
:
|
:manual:`Read concern </reference/read-concern>` to use for the operation.
Defaults to the client's read concern.
This is not supported for server versions prior to 3.2 and will result in an
exception at execution time if used.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
readPreference
type
:
:php:`MongoDB\\Driver\\ReadPreference <class.mongodb-driver-readpreference>`
description
:
|
:manual:`Read preference </reference/read-preference>` to use for the
operation. Defaults to the client's read preference.
interface
:
phpmethod
operation
:
~
optional
:
true
---
source
:
file
:
apiargs-common-option.yaml
ref
:
typeMap
---
arg_name
:
option
name
:
writeConcern
type
:
:php:`MongoDB\\Driver\\WriteConcern <class.mongodb-driver-writeconcern>`
description
:
|
:manual:`Write concern </reference/write-concern>` to use for the operation.
Defaults to the client's write concern.
interface
:
phpmethod
operation
:
~
optional
:
true
...
docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml
View file @
9739904e
...
...
@@ -10,16 +10,10 @@ source:
post
:
|
This will be used for the returned command result document.
---
arg_name
:
option
name
:
writeConcern
type
:
:php:`MongoDB\\Driver\\WriteConcern <class.mongodb-driver-writeconcern>`
description
:
|
:manual:`Write concern </reference/write-concern>` to use for the operation.
Defaults to the client's write concern.
source
:
file
:
apiargs-MongoDBClient-common-option.yaml
ref
:
writeConcern
post
:
|
This is not supported for server versions prior to 3.4 and will result in an
exception at execution time if used.
interface
:
phpmethod
operation
:
~
optional
:
true
...
docs/includes/apiargs-MongoDBClient-method-watch-option.yaml
0 → 100644
View file @
9739904e
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
batchSize
---
source
:
file
:
apiargs-common-option.yaml
ref
:
collation
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
fullDocument
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
maxAwaitTimeMS
---
source
:
file
:
apiargs-MongoDBClient-common-option.yaml
ref
:
readConcern
---
source
:
file
:
apiargs-MongoDBClient-common-option.yaml
ref
:
readPreference
post
:
|
This is used for both the initial change stream aggregation and for
server selection during an automatic resume.
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
resumeAfter
---
source
:
file
:
apiargs-common-option.yaml
ref
:
session
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
startAtOperationTime
---
source
:
file
:
apiargs-MongoDBClient-common-option.yaml
ref
:
typeMap
...
docs/includes/apiargs-MongoDBClient-method-watch-param.yaml
0 → 100644
View file @
9739904e
source
:
file
:
apiargs-method-watch-param.yaml
ref
:
$pipeline
---
source
:
file
:
apiargs-method-watch-param.yaml
ref
:
$options
...
docs/includes/apiargs-MongoDBCollection-common-option.yaml
View file @
9739904e
...
...
@@ -24,27 +24,14 @@ interface: phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
collation
type
:
array|object
description
:
|
:manual:`Collation </reference/collation>` allows users to specify
language-specific rules for string comparison, such as rules for lettercase
and accent marks. When specifying collation, the ``locale`` field is
mandatory; all other collation fields are optional. For descriptions of the
fields, see :manual:`Collation Document
</reference/collation/#collation-document>`.
source
:
file
:
apiargs-common-option.yaml
ref
:
collation
post
:
|
If the collation is unspecified but the collection has a default collation,
the operation uses the collation specified for the collection. If no
collation is specified for the collection or for the operation, MongoDB uses
the simple binary comparison used in prior versions for string comparisons.
This option is available in MongoDB 3.4+ and will result in an exception at
execution time if specified for an older server version.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
readConcern
...
...
docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml
View file @
9739904e
---
arg_name
:
option
name
:
batchSize
type
:
integer
description
:
|
Specifies the maximum number of change events to return in each batch of the
response from the MongoDB cluster.
interface
:
phpmethod
operation
:
~
optional
:
true
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
batchSize
---
source
:
file
:
apiargs-
MongoDBCollection-
common-option.yaml
file
:
apiargs-common-option.yaml
ref
:
collation
---
arg_name
:
option
name
:
fullDocument
type
:
string
description
:
|
Allowed values are 'default' and 'updateLookup'. Defaults to 'default'.
When set to 'updateLookup', the change notification for partial updates will
include both a delta describing the changes to the document, as well as a
copy of the entire document that was changed from some time after the change
occurred. The following values are supported:
- ``MongoDB\Operation\Watch::FULL_DOCUMENT_DEFAULT`` (*default*)
- ``MongoDB\Operation\Watch::FULL_DOCUMENT_UPDATE_LOOKUP``
.. note::
This is an option of the ``$changeStream`` pipeline stage.
interface
:
phpmethod
operation
:
~
optional
:
true
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
fullDocument
---
arg_name
:
option
name
:
maxAwaitTimeMS
type
:
integer
description
:
|
Positive integer denoting the time limit in milliseconds for the server to
block a getMore operation if no data is available.
interface
:
phpmethod
operation
:
~
optional
:
true
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
maxAwaitTimeMS
---
source
:
file
:
apiargs-MongoDBCollection-common-option.yaml
...
...
@@ -54,23 +26,20 @@ post: |
This is used for both the initial change stream aggregation and for
server selection during an automatic resume.
---
arg_name
:
option
name
:
resumeAfter
type
:
array|object
description
:
|
Specifies the logical starting point for the new change stream.
.. note::
This is an option of the ``$changeStream`` pipeline stage.
interface
:
phpmethod
operation
:
~
optional
:
true
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
resumeAfter
---
source
:
file
:
apiargs-common-option.yaml
ref
:
session
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
startAtOperationTime
post
:
|
.. versionadded:: 1.4
---
source
:
file
:
apiargs-MongoDBCollection-common-option.yaml
ref
:
typeMap
...
...
docs/includes/apiargs-MongoDBCollection-method-watch-param.yaml
View file @
9739904e
arg_name
:
param
name
:
$pipeline
type
:
array|object
description
:
|
The pipeline of stages to append to an initial ``$changeStream`` stage.
interface
:
phpmethod
operation
:
~
optional
:
true
source
:
file
:
apiargs-method-watch-param.yaml
ref
:
$pipeline
---
source
:
file
:
apiargs-
common
-param.yaml
file
:
apiargs-
method-watch
-param.yaml
ref
:
$options
...
docs/includes/apiargs-MongoDBDatabase-common-option.yaml
View file @
9739904e
arg_name
:
option
name
:
readConcern
type
:
:php:`MongoDB\\Driver\\ReadConcern <class.mongodb-driver-readconcern>`
description
:
|
:manual:`Read concern </reference/read-concern>` to use for the operation.
Defaults to the database's read concern.
This is not supported for server versions prior to 3.2 and will result in an
exception at execution time if used.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
readPreference
type
:
:php:`MongoDB\\Driver\\ReadPreference <class.mongodb-driver-readpreference>`
description
:
|
:manual:`Read preference </reference/read-preference>` to use for the
operation. Defaults to the database's read preference.
interface
:
phpmethod
operation
:
~
optional
:
true
---
source
:
file
:
apiargs-common-option.yaml
ref
:
typeMap
...
...
docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
View file @
9739904e
...
...
@@ -28,7 +28,7 @@ operation: ~
optional
:
true
---
source
:
file
:
apiargs-
MongoDBCollection-
common-option.yaml
file
:
apiargs-common-option.yaml
ref
:
collation
pre
:
|
Specifies the :manual:`collation
...
...
docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml
0 → 100644
View file @
9739904e
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
batchSize
---
source
:
file
:
apiargs-common-option.yaml
ref
:
collation
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
fullDocument
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
maxAwaitTimeMS
---
source
:
file
:
apiargs-MongoDBDatabase-common-option.yaml
ref
:
readConcern
---
source
:
file
:
apiargs-MongoDBDatabase-common-option.yaml
ref
:
readPreference
post
:
|
This is used for both the initial change stream aggregation and for
server selection during an automatic resume.
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
resumeAfter
---
source
:
file
:
apiargs-common-option.yaml
ref
:
session
---
source
:
file
:
apiargs-method-watch-option.yaml
ref
:
startAtOperationTime
---
source
:
file
:
apiargs-MongoDBDatabase-common-option.yaml
ref
:
typeMap
...
docs/includes/apiargs-MongoDBDatabase-method-watch-param.yaml
0 → 100644
View file @
9739904e
source
:
file
:
apiargs-method-watch-param.yaml
ref
:
$pipeline
---
source
:
file
:
apiargs-method-watch-param.yaml
ref
:
$options
...
docs/includes/apiargs-common-option.yaml
View file @
9739904e
arg_name
:
option
name
:
collation
type
:
array|object
description
:
|
:manual:`Collation </reference/collation>` allows users to specify
language-specific rules for string comparison, such as rules for lettercase
and accent marks. When specifying collation, the ``locale`` field is
mandatory; all other collation fields are optional. For descriptions of the
fields, see :manual:`Collation Document
</reference/collation/#collation-document>`.
This option is available in MongoDB 3.4+ and will result in an exception at
execution time if specified for an older server version.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
maxTimeMS
type
:
integer
description
:
|
...
...
docs/includes/apiargs-method-watch-option.yaml
0 → 100644
View file @
9739904e
---
arg_name
:
option
name
:
batchSize
type
:
integer
description
:
|
Specifies the maximum number of change events to return in each batch of the
response from the MongoDB cluster.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
fullDocument
type
:
string
description
:
|
Allowed values are 'default' and 'updateLookup'. Defaults to 'default'.
When set to 'updateLookup', the change notification for partial updates will
include both a delta describing the changes to the document, as well as a
copy of the entire document that was changed from some time after the change
occurred. The following values are supported:
- ``MongoDB\Operation\Watch::FULL_DOCUMENT_DEFAULT`` (*default*)
- ``MongoDB\Operation\Watch::FULL_DOCUMENT_UPDATE_LOOKUP``
.. note::
This is an option of the ``$changeStream`` pipeline stage.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
maxAwaitTimeMS
type
:
integer
description
:
|
Positive integer denoting the time limit in milliseconds for the server to
block a getMore operation if no data is available.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
resumeAfter
type
:
array|object
description
:
|
Specifies the logical starting point for the new change stream. The ``_id``
field in documents returned by the change stream may be used here.
Using this option in conjunction with ``startAtOperationTime`` will result in
a server error. The options are mutually exclusive.
.. note::
This is an option of the ``$changeStream`` pipeline stage.
interface
:
phpmethod
operation
:
~
optional
:
true
---
arg_name
:
option
name
:
startAtOperationTime
type
:
:php:`MongoDB\\BSON\\TimestampInterface <class.mongodb-bson-timestampinterface>`
description
:
|
If specified, the change stream will only provide changes that occurred at or
after the specified timestamp. Command responses from a MongoDB 4.0+ server
include an ``operationTime`` that can be used here. By default, the
``operationTime`` returned by the initial ``aggregate`` command will be used
if available.
Using this option in conjunction with ``resumeAfter`` will result in a server
error. The options are mutually exclusive.
This is not supported for server versions prior to 4.0 and will result in an
exception at execution time if used.
.. note::
This is an option of the ``$changeStream`` pipeline stage.
interface
:
phpmethod
operation
:
~
optional
:
true
...
docs/includes/apiargs-method-watch-param.yaml
0 → 100644
View file @
9739904e
arg_name
:
param
name
:
$pipeline
type
:
array|object
description
:
|
The pipeline of stages to append to an initial ``$changeStream`` stage.
interface
:
phpmethod
operation
:
~
optional
:
true
---
source
:
file
:
apiargs-common-param.yaml
ref
:
$options
...
docs/reference/class/MongoDBClient.txt
View file @
9739904e
...
...
@@ -40,3 +40,4 @@ Methods
/reference/method/MongoDBClient-selectCollection
/reference/method/MongoDBClient-selectDatabase
/reference/method/MongoDBClient-startSession
/reference/method/MongoDBClient-watch
docs/reference/class/MongoDBDatabase.txt
View file @
9739904e
...
...
@@ -59,5 +59,6 @@ Methods
/reference/method/MongoDBDatabase-modifyCollection
/reference/method/MongoDBDatabase-selectCollection
/reference/method/MongoDBDatabase-selectGridFSBucket
/reference/method/MongoDBDatabase-watch
/reference/method/MongoDBDatabase-withOptions
docs/reference/method/MongoDBClient-watch.txt
0 → 100644
View file @
9739904e
========================
MongoDB\\Client::watch()
========================
.. versionadded:: 1.4
.. default-domain:: mongodb
.. contents:: On this page
:local:
:backlinks: none
:depth: 1
:class: singlecol
Definition
----------
.. phpmethod:: MongoDB\\Client::watch()
Executes a :manual:`change stream </changeStreams>` operation on the client.
The change stream can be watched for cluster-level changes.
.. code-block:: php
function watch(array $pipeline = [], array $options = []): MongoDB\ChangeStream
This method has the following parameters:
.. include:: /includes/apiargs/MongoDBClient-method-watch-param.rst
The ``$options`` parameter supports the following options:
.. include:: /includes/apiargs/MongoDBClient-method-watch-option.rst
Return Values
-------------
A :phpclass:`MongoDB\\ChangeStream` object, which allows for iteration of
events in the change stream via the :php:`Iterator <class.iterator>` interface.
Errors/Exceptions
-----------------
.. include:: /includes/extracts/error-unexpectedvalueexception.rst
.. include:: /includes/extracts/error-unsupportedexception.rst
.. include:: /includes/extracts/error-invalidargumentexception.rst
.. include:: /includes/extracts/error-driver-runtimeexception.rst
Examples
--------
This example reports events while iterating a change stream.
.. code-block:: php
<?php
$uri = 'mongodb://rs1.example.com,rs2.example.com/?replicaSet=myReplicaSet';
$client = new MongoDB\Client($uri);
$changeStream = $client->watch();
for ($changeStream->rewind(); true; $changeStream->next()) {
if ( ! $changeStream->valid()) {
continue;
}
$event = $changeStream->current();
if ($event['operationType'] === 'invalidate') {
break;
}
$ns = sprintf('%s.%s', $event['ns']['db'], $event['ns']['coll']);
$id = json_encode($event['documentKey']['_id']);
switch ($event['operationType']) {
case 'delete':
printf("Deleted document in %s with _id: %s\n\n", $ns, $id);
break;
case 'insert':
printf("Inserted new document in %s\n", $ns);
echo json_encode($event['fullDocument']), "\n\n";
break;
case 'replace':
printf("Replaced new document in %s with _id: %s\n", $ns, $id);
echo json_encode($event['fullDocument']), "\n\n";
break;
case 'update':
printf("Updated document in %s with _id: %s\n", $ns, $id);
echo json_encode($event['updateDescription']), "\n\n";
break;
}
}
Assuming that a document was inserted, updated, and deleted while the above
script was iterating the change stream, the output would then resemble:
.. code-block:: none
Inserted new document in app.user
{"_id":{"$oid":"5b329b6674083047cc05e607"},"username":"bob"}
Inserted new document in app.products
{"_id":{"$oid":"5b329b6a74083047cc05e608"},"name":"Widget","quantity":5}
Inserted new document in logs.messages
{"_id":{"$oid":"5b329b7374083047cc05e609"},"msg":"bob purchased a widget"}
See Also
--------
- :manual:`Aggregation Pipeline </core/aggregation-pipeline>` documentation in
the MongoDB Manual
- :manual:`Change Streams </changeStreams>` documentation in the MongoDB manual
- :manual:`Change Events </reference/change-events/>` documentation in the
MongoDB manual
docs/reference/method/MongoDBCollection-watch.txt
View file @
9739904e
...
...
@@ -18,7 +18,7 @@ Definition
.. phpmethod:: MongoDB\\Collection::watch()
Executes a :manual:`change stream </changeStreams>` operation on the
collection.
collection.
The change stream can be watched for collection-level changes.
.. code-block:: php
...
...
@@ -68,6 +68,10 @@ This example reports events while iterating a change stream.
$event = $changeStream->current();
if ($event['operationType'] === 'invalidate') {
break;
}
$ns = sprintf('%s.%s', $event['ns']['db'], $event['ns']['coll']);
$id = json_encode($event['documentKey']['_id']);
...
...
@@ -98,13 +102,14 @@ script was iterating the change stream, the output would then resemble:
.. code-block:: none
Inserted new document in test.
inventory
{"_id":{"$oid":"5
a81fc0d6118fd1af1790d32"},"name":"Widget","quantity":5
}
Inserted new document in test.
user
{"_id":{"$oid":"5
b329c4874083047cc05e60a"},"username":"bob"
}
Updated document in test.inventory with _id: {"$oid":"5a81fc0d6118fd1af1790d32"}
{"
updatedFields":{"quantity":4},"removedFields":[]
}
Inserted new document in test.products
{"
_id":{"$oid":"5b329c4d74083047cc05e60b"},"name":"Widget","quantity":5
}
Deleted document in test.inventory with _id: {"$oid":"5a81fc0d6118fd1af1790d32"}
Updated document in test.user with _id: {"$oid":"5b329a4f74083047cc05e603"}
{"updatedFields":{"username":"robert"},"removedFields":[]}
See Also
--------
...
...
docs/reference/method/MongoDBDatabase-watch.txt
0 → 100644
View file @
9739904e
==========================
MongoDB\\Database::watch()
==========================
.. versionadded:: 1.4
.. default-domain:: mongodb
.. contents:: On this page
:local:
:backlinks: none
:depth: 1
:class: singlecol
Definition
----------
.. phpmethod:: MongoDB\\Database::watch()
Executes a :manual:`change stream </changeStreams>` operation on the
database. The change stream can be watched for database-level changes.
.. code-block:: php
function watch(array $pipeline = [], array $options = []): MongoDB\ChangeStream
This method has the following parameters:
.. include:: /includes/apiargs/MongoDBDatabase-method-watch-param.rst
The ``$options`` parameter supports the following options:
.. include:: /includes/apiargs/MongoDBDatabase-method-watch-option.rst
Return Values
-------------
A :phpclass:`MongoDB\\ChangeStream` object, which allows for iteration of
events in the change stream via the :php:`Iterator <class.iterator>` interface.
Errors/Exceptions
-----------------
.. include:: /includes/extracts/error-unexpectedvalueexception.rst
.. include:: /includes/extracts/error-unsupportedexception.rst
.. include:: /includes/extracts/error-invalidargumentexception.rst
.. include:: /includes/extracts/error-driver-runtimeexception.rst
Examples
--------
This example reports events while iterating a change stream.
.. code-block:: php
<?php
$uri = 'mongodb://rs1.example.com,rs2.example.com/?replicaSet=myReplicaSet';
$database = (new MongoDB\Client($uri))->test;
$changeStream = $database->watch();
for ($changeStream->rewind(); true; $changeStream->next()) {
if ( ! $changeStream->valid()) {
continue;
}
$event = $changeStream->current();
if ($event['operationType'] === 'invalidate') {
break;
}
$ns = sprintf('%s.%s', $event['ns']['db'], $event['ns']['coll']);
$id = json_encode($event['documentKey']['_id']);
switch ($event['operationType']) {
case 'delete':
printf("Deleted document in %s with _id: %s\n\n", $ns, $id);
break;
case 'insert':
printf("Inserted new document in %s\n", $ns);
echo json_encode($event['fullDocument']), "\n\n";
break;
case 'replace':
printf("Replaced new document in %s with _id: %s\n", $ns, $id);
echo json_encode($event['fullDocument']), "\n\n";
break;
case 'update':
printf("Updated document in %s with _id: %s\n", $ns, $id);
echo json_encode($event['updateDescription']), "\n\n";
break;
}
}
Assuming that a document was inserted, updated, and deleted while the above
script was iterating the change stream, the output would then resemble:
.. code-block:: none
Inserted new document in test.inventory
{"_id":{"$oid":"5a81fc0d6118fd1af1790d32"},"name":"Widget","quantity":5}
Updated document in test.inventory with _id: {"$oid":"5a81fc0d6118fd1af1790d32"}
{"updatedFields":{"quantity":4},"removedFields":[]}
Deleted document in test.inventory with _id: {"$oid":"5a81fc0d6118fd1af1790d32"}
See Also
--------
- :manual:`Aggregation Pipeline </core/aggregation-pipeline>` documentation in
the MongoDB Manual
- :manual:`Change Streams </changeStreams>` documentation in the MongoDB manual
- :manual:`Change Events </reference/change-events/>` documentation in the
MongoDB manual
src/ChangeStream.php
View file @
9739904e
...
...
@@ -19,8 +19,9 @@ namespace MongoDB;
use
MongoDB\BSON\Serializable
;
use
MongoDB\Driver\Cursor
;
use
MongoDB\Driver\Exception\Connection
Timeout
Exception
;
use
MongoDB\Driver\Exception\ConnectionException
;
use
MongoDB\Driver\Exception\RuntimeException
;
use
MongoDB\Driver\Exception\ServerException
;
use
MongoDB\Exception\InvalidArgumentException
;
use
MongoDB\Exception\ResumeTokenException
;
use
IteratorIterator
;
...
...
@@ -35,14 +36,22 @@ use Iterator;
*/
class
ChangeStream
implements
Iterator
{
/**
* @deprecated 1.4
* @todo Remove this in 2.0 (see: PHPLIB-360)
*/
const
CURSOR_NOT_FOUND
=
43
;
private
static
$errorCodeCappedPositionLost
=
136
;
private
static
$errorCodeInterrupted
=
11601
;
private
static
$errorCodeCursorKilled
=
237
;
private
$resumeToken
;
private
$resumeCallable
;
private
$csIt
;
private
$key
=
0
;
private
$hasAdvanced
=
false
;
const
CURSOR_NOT_FOUND
=
43
;
/**
* Constructor.
*
...
...
@@ -91,7 +100,6 @@ class ChangeStream implements Iterator
*/
public
function
next
()
{
$resumable
=
false
;
try
{
$this
->
csIt
->
next
();
if
(
$this
->
valid
())
{
...
...
@@ -111,18 +119,9 @@ class ChangeStream implements Iterator
$this
->
resumeCallable
=
null
;
}
}
catch
(
RuntimeException
$e
)
{
if
(
strpos
(
$e
->
getMessage
(),
"not master"
)
!==
false
)
{
$
resumable
=
true
;
if
(
$this
->
isResumableError
(
$e
)
)
{
$
this
->
resume
()
;
}
if
(
$e
->
getCode
()
===
self
::
CURSOR_NOT_FOUND
)
{
$resumable
=
true
;
}
if
(
$e
instanceof
ConnectionTimeoutException
)
{
$resumable
=
true
;
}
}
if
(
$resumable
)
{
$this
->
resume
();
}
}
...
...
@@ -132,7 +131,6 @@ class ChangeStream implements Iterator
*/
public
function
rewind
()
{
$resumable
=
false
;
try
{
$this
->
csIt
->
rewind
();
if
(
$this
->
valid
())
{
...
...
@@ -144,18 +142,9 @@ class ChangeStream implements Iterator
$this
->
resumeCallable
=
null
;
}
}
catch
(
RuntimeException
$e
)
{
if
(
strpos
(
$e
->
getMessage
(),
"not master"
)
!==
false
)
{
$
resumable
=
true
;
if
(
$this
->
isResumableError
(
$e
)
)
{
$
this
->
resume
()
;
}
if
(
$e
->
getCode
()
===
self
::
CURSOR_NOT_FOUND
)
{
$resumable
=
true
;
}
if
(
$e
instanceof
ConnectionTimeoutException
)
{
$resumable
=
true
;
}
}
if
(
$resumable
)
{
$this
->
resume
();
}
}
...
...
@@ -201,6 +190,30 @@ class ChangeStream implements Iterator
return
$resumeToken
;
}
/**
* Determines if an exception is a resumable error.
*
* @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#resumable-error
* @param RuntimeException $exception
* @return boolean
*/
private
function
isResumableError
(
RuntimeException
$exception
)
{
if
(
$exception
instanceof
ConnectionException
)
{
return
true
;
}
if
(
!
$exception
instanceof
ServerException
)
{
return
false
;
}
if
(
in_array
(
$exception
->
getCode
(),
[
self
::
$errorCodeCappedPositionLost
,
self
::
$errorCodeCursorKilled
,
self
::
$errorCodeInterrupted
]))
{
return
false
;
}
return
true
;
}
/**
* Creates a new changeStream after a resumable server error.
*
...
...
src/Client.php
View file @
9739904e
...
...
@@ -29,6 +29,7 @@ use MongoDB\Exception\UnsupportedException;
use
MongoDB\Model\DatabaseInfoIterator
;
use
MongoDB\Operation\DropDatabase
;
use
MongoDB\Operation\ListDatabases
;
use
MongoDB\Operation\Watch
;
class
Client
{
...
...
@@ -37,9 +38,12 @@ class Client
'document'
=>
'MongoDB\Model\BSONDocument'
,
'root'
=>
'MongoDB\Model\BSONDocument'
,
];
private
static
$wireVersionForReadConcern
=
4
;
private
static
$wireVersionForWritableCommandWriteConcern
=
5
;
private
$manager
;
private
$readConcern
;
private
$readPreference
;
private
$uri
;
private
$typeMap
;
private
$writeConcern
;
...
...
@@ -81,6 +85,8 @@ class Client
unset
(
$driverOptions
[
'typeMap'
]);
$this
->
manager
=
new
Manager
(
$uri
,
$uriOptions
,
$driverOptions
);
$this
->
readConcern
=
$this
->
manager
->
getReadConcern
();
$this
->
readPreference
=
$this
->
manager
->
getReadPreference
();
$this
->
writeConcern
=
$this
->
manager
->
getWriteConcern
();
}
...
...
@@ -173,7 +179,7 @@ class Client
*/
public
function
getReadConcern
()
{
return
$this
->
manager
->
getReadConcern
()
;
return
$this
->
readConcern
;
}
/**
...
...
@@ -183,7 +189,7 @@ class Client
*/
public
function
getReadPreference
()
{
return
$this
->
manager
->
getReadPreference
()
;
return
$this
->
readPreference
;
}
/**
...
...
@@ -268,4 +274,34 @@ class Client
{
return
$this
->
manager
->
startSession
(
$options
);
}
/**
* Create a change stream for watching changes to the cluster.
*
* @see Watch::__construct() for supported options
* @param array $pipeline List of pipeline operations
* @param array $options Command options
* @return ChangeStream
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public
function
watch
(
array
$pipeline
=
[],
array
$options
=
[])
{
if
(
!
isset
(
$options
[
'readPreference'
]))
{
$options
[
'readPreference'
]
=
$this
->
readPreference
;
}
$server
=
$this
->
manager
->
selectServer
(
$options
[
'readPreference'
]);
if
(
!
isset
(
$options
[
'readConcern'
])
&&
\MongoDB\server_supports_feature
(
$server
,
self
::
$wireVersionForReadConcern
))
{
$options
[
'readConcern'
]
=
$this
->
readConcern
;
}
if
(
!
isset
(
$options
[
'typeMap'
]))
{
$options
[
'typeMap'
]
=
$this
->
typeMap
;
}
$operation
=
new
Watch
(
$this
->
manager
,
null
,
null
,
$pipeline
,
$options
);
return
$operation
->
execute
(
$server
);
}
}
src/Database.php
View file @
9739904e
...
...
@@ -34,6 +34,7 @@ use MongoDB\Operation\DropCollection;
use
MongoDB\Operation\DropDatabase
;
use
MongoDB\Operation\ListCollections
;
use
MongoDB\Operation\ModifyCollection
;
use
MongoDB\Operation\Watch
;
class
Database
{
...
...
@@ -42,6 +43,7 @@ class Database
'document'
=>
'MongoDB\Model\BSONDocument'
,
'root'
=>
'MongoDB\Model\BSONDocument'
,
];
private
static
$wireVersionForReadConcern
=
4
;
private
static
$wireVersionForWritableCommandWriteConcern
=
5
;
private
$databaseName
;
...
...
@@ -409,6 +411,36 @@ class Database
return
new
Bucket
(
$this
->
manager
,
$this
->
databaseName
,
$options
);
}
/**
* Create a change stream for watching changes to the database.
*
* @see Watch::__construct() for supported options
* @param array $pipeline List of pipeline operations
* @param array $options Command options
* @return ChangeStream
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public
function
watch
(
array
$pipeline
=
[],
array
$options
=
[])
{
if
(
!
isset
(
$options
[
'readPreference'
]))
{
$options
[
'readPreference'
]
=
$this
->
readPreference
;
}
$server
=
$this
->
manager
->
selectServer
(
$options
[
'readPreference'
]);
if
(
!
isset
(
$options
[
'readConcern'
])
&&
\MongoDB\server_supports_feature
(
$server
,
self
::
$wireVersionForReadConcern
))
{
$options
[
'readConcern'
]
=
$this
->
readConcern
;
}
if
(
!
isset
(
$options
[
'typeMap'
]))
{
$options
[
'typeMap'
]
=
$this
->
typeMap
;
}
$operation
=
new
Watch
(
$this
->
manager
,
$this
->
databaseName
,
null
,
$pipeline
,
$options
);
return
$operation
->
execute
(
$server
);
}
/**
* Get a clone of this database with different options.
*
...
...
src/Operation/Aggregate.php
View file @
9739904e
...
...
@@ -116,10 +116,13 @@ class Aggregate implements Executable
* This is not supported for server versions < 3.4 and will result in an
* exception at execution time if used.
*
* @param string $databaseName Database name
* @param string $collectionName Collection name
* @param array $pipeline List of pipeline operations
* @param array $options Command options
* Note: Collection-agnostic commands (e.g. $currentOp) may be executed by
* specifying null for the collection name.
*
* @param string $databaseName Database name
* @param string|null $collectionName Collection name
* @param array $pipeline List of pipeline operations
* @param array $options Command options
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public
function
__construct
(
$databaseName
,
$collectionName
,
array
$pipeline
,
array
$options
=
[])
...
...
@@ -220,7 +223,7 @@ class Aggregate implements Executable
}
$this
->
databaseName
=
(
string
)
$databaseName
;
$this
->
collectionName
=
(
string
)
$collectionName
;
$this
->
collectionName
=
isset
(
$collectionName
)
?
(
string
)
$collectionName
:
null
;
$this
->
pipeline
=
$pipeline
;
$this
->
options
=
$options
;
}
...
...
@@ -289,7 +292,7 @@ class Aggregate implements Executable
private
function
createCommand
(
Server
$server
)
{
$cmd
=
[
'aggregate'
=>
$this
->
collectionName
,
'aggregate'
=>
isset
(
$this
->
collectionName
)
?
$this
->
collectionName
:
1
,
'pipeline'
=>
$this
->
pipeline
,
];
$cmdOptions
=
[];
...
...
src/Operation/Watch.php
View file @
9739904e
This diff is collapsed.
Click to expand it.
tests/Collection/CollectionFunctionalTest.php
View file @
9739904e
...
...
@@ -123,7 +123,8 @@ class CollectionFunctionalTest extends FunctionalTestCase
]
);
},
function
(
stdClass
$command
)
{
function
(
array
$event
)
{
$command
=
$event
[
'started'
]
->
getCommand
();
$this
->
assertObjectHasAttribute
(
'lsid'
,
$command
);
$this
->
assertObjectHasAttribute
(
'maxTimeMS'
,
$command
);
$this
->
assertObjectHasAttribute
(
'writeConcern'
,
$command
);
...
...
tests/CommandObserver.php
View file @
9739904e
...
...
@@ -38,14 +38,16 @@ class CommandObserver implements CommandSubscriber
public
function
commandStarted
(
CommandStartedEvent
$event
)
{
$this
->
commands
[
]
=
$event
->
getCommand
()
;
$this
->
commands
[
$event
->
getRequestId
()][
'started'
]
=
$event
;
}
public
function
commandSucceeded
(
CommandSucceededEvent
$event
)
{
$this
->
commands
[
$event
->
getRequestId
()][
'succeeded'
]
=
$event
;
}
public
function
commandFailed
(
CommandFailedEvent
$event
)
{
$this
->
commands
[
$event
->
getRequestId
()][
'failed'
]
=
$event
;
}
}
tests/DocumentationExamplesTest.php
View file @
9739904e
...
...
@@ -979,7 +979,7 @@ class DocumentationExamplesTest extends FunctionalTestCase
'documentKey'
=>
[
'_id'
=>
1
],
];
$this
->
assert
Same
Document
(
$expectedChange
,
$lastChange
);
$this
->
assert
Matches
Document
(
$expectedChange
,
$lastChange
);
// Start Changestream Example 3
$resumeToken
=
(
$lastChange
!==
null
)
?
$lastChange
->
_id
:
null
;
...
...
@@ -1002,7 +1002,7 @@ class DocumentationExamplesTest extends FunctionalTestCase
'documentKey'
=>
[
'_id'
=>
2
],
];
$this
->
assert
Same
Document
(
$expectedChange
,
$nextChange
);
$this
->
assert
Matches
Document
(
$expectedChange
,
$nextChange
);
// Start Changestream Example 4
$pipeline
=
[[
'$match'
=>
[
'$or'
=>
[[
'fullDocument.username'
=>
'alice'
],
[
'operationType'
=>
'delete'
]]]]];
...
...
tests/GridFS/ReadableStreamFunctionalTest.php
View file @
9739904e
...
...
@@ -221,8 +221,8 @@ class ReadableStreamFunctionalTest extends FunctionalTestCase
$stream
->
seek
(
$offset
);
$this
->
assertSame
(
$expectedBytes
,
$stream
->
readBytes
(
$length
));
},
function
(
stdClass
$command
)
use
(
&
$commands
)
{
$commands
[]
=
key
((
array
)
$command
);
function
(
array
$event
)
use
(
&
$commands
)
{
$commands
[]
=
$event
[
'started'
]
->
getCommandName
(
);
}
);
...
...
@@ -257,8 +257,8 @@ class ReadableStreamFunctionalTest extends FunctionalTestCase
$stream
->
seek
(
$offset
);
$this
->
assertSame
(
$expectedBytes
,
$stream
->
readBytes
(
$length
));
},
function
(
stdClass
$command
)
use
(
&
$commands
)
{
$commands
[]
=
key
((
array
)
$command
);
function
(
array
$event
)
use
(
&
$commands
)
{
$commands
[]
=
$event
[
'started'
]
->
getCommandName
(
);
}
);
...
...
@@ -291,8 +291,8 @@ class ReadableStreamFunctionalTest extends FunctionalTestCase
$stream
->
seek
(
$offset
);
$this
->
assertSame
(
$expectedBytes
,
$stream
->
readBytes
(
$length
));
},
function
(
stdClass
$command
)
use
(
&
$commands
)
{
$commands
[]
=
key
((
array
)
$command
);
function
(
array
$event
)
use
(
&
$commands
)
{
$commands
[]
=
$event
[
'started'
]
->
getCommandName
(
);
}
);
...
...
tests/Operation/AggregateFunctionalTest.php
View file @
9739904e
...
...
@@ -12,6 +12,28 @@ use stdClass;
class
AggregateFunctionalTest
extends
FunctionalTestCase
{
public
function
testCurrentOpCommand
()
{
if
(
version_compare
(
$this
->
getServerVersion
(),
'3.6.0'
,
'<'
))
{
$this
->
markTestSkipped
(
'$currentOp is not supported'
);
}
(
new
CommandObserver
)
->
observe
(
function
()
{
$operation
=
new
Aggregate
(
'admin'
,
null
,
[[
'$currentOp'
=>
(
object
)
[]]]
);
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
array
$event
)
{
$this
->
assertSame
(
1
,
$event
[
'started'
]
->
getCommand
()
->
aggregate
);
}
);
}
public
function
testDefaultReadConcernIsOmitted
()
{
(
new
CommandObserver
)
->
observe
(
...
...
@@ -25,8 +47,8 @@ class AggregateFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -44,8 +66,8 @@ class AggregateFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -90,8 +112,8 @@ class AggregateFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -163,8 +185,8 @@ class AggregateFunctionalTest extends FunctionalTestCase
$this
->
assertCount
(
1
,
$results
);
$this
->
assertObjectHasAttribute
(
'stages'
,
current
(
$results
));
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
...
...
tests/Operation/BulkWriteFunctionalTest.php
View file @
9739904e
...
...
@@ -299,8 +299,8 @@ class BulkWriteFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/CountFunctionalTest.php
View file @
9739904e
...
...
@@ -23,8 +23,8 @@ class CountFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -87,8 +87,8 @@ class CountFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/CreateCollectionFunctionalTest.php
View file @
9739904e
...
...
@@ -20,8 +20,8 @@ class CreateCollectionFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -42,8 +42,8 @@ class CreateCollectionFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/CreateIndexesFunctionalTest.php
View file @
9739904e
...
...
@@ -140,8 +140,8 @@ class CreateIndexesFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -163,8 +163,8 @@ class CreateIndexesFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/DatabaseCommandFunctionalTest.php
View file @
9739904e
...
...
@@ -24,8 +24,8 @@ class DatabaseCommandFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/DeleteFunctionalTest.php
View file @
9739904e
...
...
@@ -79,8 +79,8 @@ class DeleteFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/DistinctFunctionalTest.php
View file @
9739904e
...
...
@@ -22,8 +22,8 @@ class DistinctFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -46,8 +46,8 @@ class DistinctFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/DropCollectionFunctionalTest.php
View file @
9739904e
...
...
@@ -22,8 +22,8 @@ class DropCollectionFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -69,8 +69,8 @@ class DropCollectionFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/DropDatabaseFunctionalTest.php
View file @
9739904e
...
...
@@ -22,8 +22,8 @@ class DropDatabaseFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -73,8 +73,8 @@ class DropDatabaseFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/DropIndexesFunctionalTest.php
View file @
9739904e
...
...
@@ -28,8 +28,8 @@ class DropIndexesFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -137,8 +137,8 @@ class DropIndexesFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/ExplainFunctionalTest.php
View file @
9739904e
...
...
@@ -182,7 +182,8 @@ class ExplainFunctionalTest extends FunctionalTestCase
$explainOperation
=
new
Explain
(
$this
->
getDatabaseName
(),
$operation
,
[
'typeMap'
=>
[
'root'
=>
'array'
,
'document'
=>
'array'
]]);
$explainOperation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
function
(
array
$event
)
{
$command
=
$event
[
'started'
]
->
getCommand
();
$this
->
assertObjectNotHasAttribute
(
'maxAwaitTimeMS'
,
$command
->
explain
);
$this
->
assertObjectHasAttribute
(
'tailable'
,
$command
->
explain
);
$this
->
assertObjectHasAttribute
(
'awaitData'
,
$command
->
explain
);
...
...
@@ -206,7 +207,8 @@ class ExplainFunctionalTest extends FunctionalTestCase
$explainOperation
=
new
Explain
(
$this
->
getDatabaseName
(),
$operation
,
[
'typeMap'
=>
[
'root'
=>
'array'
,
'document'
=>
'array'
]]);
$explainOperation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
function
(
array
$event
)
{
$command
=
$event
[
'started'
]
->
getCommand
();
$this
->
assertObjectHasAttribute
(
'sort'
,
$command
->
explain
);
$this
->
assertObjectNotHasAttribute
(
'modifiers'
,
$command
->
explain
);
}
...
...
tests/Operation/FindAndModifyFunctionalTest.php
View file @
9739904e
...
...
@@ -30,8 +30,8 @@ class FindAndModifyFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$server
);
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -48,8 +48,8 @@ class FindAndModifyFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -70,8 +70,8 @@ class FindAndModifyFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/FindFunctionalTest.php
View file @
9739904e
...
...
@@ -25,8 +25,8 @@ class FindFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -99,8 +99,8 @@ class FindFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/InsertManyFunctionalTest.php
View file @
9739904e
...
...
@@ -70,8 +70,8 @@ class InsertManyFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/InsertOneFunctionalTest.php
View file @
9739904e
...
...
@@ -85,8 +85,8 @@ class InsertOneFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/ListCollectionsFunctionalTest.php
View file @
9739904e
...
...
@@ -86,8 +86,8 @@ class ListCollectionsFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/ListDatabasesFunctionalTest.php
View file @
9739904e
...
...
@@ -66,8 +66,8 @@ class ListDatabasesFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/ListIndexesFunctionalTest.php
View file @
9739904e
...
...
@@ -59,8 +59,8 @@ class ListIndexesFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/MapReduceFunctionalTest.php
View file @
9739904e
...
...
@@ -31,8 +31,8 @@ class MapReduceFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'readConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
@@ -55,8 +55,8 @@ class MapReduceFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectNotHasAttribute
(
'writeConcern'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
...
...
@@ -150,8 +150,8 @@ class MapReduceFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/UpdateFunctionalTest.php
View file @
9739904e
...
...
@@ -40,8 +40,8 @@ class UpdateFunctionalTest extends FunctionalTestCase
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
command
);
function
(
array
$event
)
{
$this
->
assertObjectHasAttribute
(
'lsid'
,
$
event
[
'started'
]
->
getCommand
()
);
}
);
}
...
...
tests/Operation/WatchFunctionalTest.php
View file @
9739904e
...
...
@@ -3,6 +3,7 @@
namespace
MongoDB\Tests\Operation
;
use
MongoDB\ChangeStream
;
use
MongoDB\BSON\TimestampInterface
;
use
MongoDB\Driver\Manager
;
use
MongoDB\Driver\ReadPreference
;
use
MongoDB\Driver\Server
;
...
...
@@ -57,7 +58,7 @@ class WatchFunctionalTest extends FunctionalTestCase
'documentKey'
=>
[
'_id'
=>
2
],
];
$this
->
assert
Same
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
assert
Matches
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
killChangeStreamCursor
(
$changeStream
);
...
...
@@ -74,7 +75,7 @@ class WatchFunctionalTest extends FunctionalTestCase
'documentKey'
=>
[
'_id'
=>
3
]
];
$this
->
assert
Same
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
assert
Matches
Document
(
$expectedResult
,
$changeStream
->
current
());
}
public
function
testNextResumesAfterConnectionException
()
...
...
@@ -98,8 +99,8 @@ class WatchFunctionalTest extends FunctionalTestCase
function
()
use
(
$changeStream
)
{
$changeStream
->
next
();
},
function
(
stdClass
$command
)
use
(
&
$commands
)
{
$commands
[]
=
key
((
array
)
$command
);
function
(
array
$event
)
use
(
&
$commands
)
{
$commands
[]
=
$event
[
'started'
]
->
getCommandName
(
);
}
);
$this
->
fail
(
'ConnectionTimeoutException was not thrown'
);
...
...
@@ -130,6 +131,100 @@ class WatchFunctionalTest extends FunctionalTestCase
$this
->
assertSame
(
$expectedCommands
,
$commands
);
}
public
function
testResumeBeforeReceivingAnyResultsIncludesStartAtOperationTime
()
{
$operation
=
new
Watch
(
$this
->
manager
,
$this
->
getDatabaseName
(),
$this
->
getCollectionName
(),
[],
$this
->
defaultOptions
);
$operationTime
=
null
;
$events
=
[];
(
new
CommandObserver
)
->
observe
(
function
()
use
(
$operation
,
&
$changeStream
)
{
$changeStream
=
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
array
$event
)
use
(
&
$events
)
{
$events
[]
=
$event
;
}
);
$this
->
assertCount
(
1
,
$events
);
$this
->
assertSame
(
'aggregate'
,
$events
[
0
][
'started'
]
->
getCommandName
());
$operationTime
=
$events
[
0
][
'succeeded'
]
->
getReply
()
->
operationTime
;
$this
->
assertInstanceOf
(
TimestampInterface
::
class
,
$operationTime
);
$this
->
assertNull
(
$changeStream
->
current
());
$this
->
killChangeStreamCursor
(
$changeStream
);
$events
=
[];
(
new
CommandObserver
)
->
observe
(
function
()
use
(
$changeStream
)
{
$changeStream
->
rewind
();
},
function
(
array
$event
)
use
(
&
$events
)
{
$events
[]
=
$event
;
}
);
$this
->
assertCount
(
4
,
$events
);
$this
->
assertSame
(
'getMore'
,
$events
[
0
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'failed'
,
$events
[
0
]);
$this
->
assertSame
(
'aggregate'
,
$events
[
1
][
'started'
]
->
getCommandName
());
$this
->
assertStartAtOperationTime
(
$operationTime
,
$events
[
1
][
'started'
]
->
getCommand
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
1
]);
// Original cursor is freed immediately after the change stream resumes
$this
->
assertSame
(
'killCursors'
,
$events
[
2
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
2
]);
$this
->
assertSame
(
'getMore'
,
$events
[
3
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
3
]);
$this
->
assertNull
(
$changeStream
->
current
());
$this
->
killChangeStreamCursor
(
$changeStream
);
$events
=
[];
(
new
CommandObserver
)
->
observe
(
function
()
use
(
$changeStream
)
{
$changeStream
->
next
();
},
function
(
array
$event
)
use
(
&
$events
)
{
$events
[]
=
$event
;
}
);
$this
->
assertCount
(
4
,
$events
);
$this
->
assertSame
(
'getMore'
,
$events
[
0
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'failed'
,
$events
[
0
]);
$this
->
assertSame
(
'aggregate'
,
$events
[
1
][
'started'
]
->
getCommandName
());
$this
->
assertStartAtOperationTime
(
$operationTime
,
$events
[
1
][
'started'
]
->
getCommand
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
1
]);
// Original cursor is freed immediately after the change stream resumes
$this
->
assertSame
(
'killCursors'
,
$events
[
2
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
2
]);
$this
->
assertSame
(
'getMore'
,
$events
[
3
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
3
]);
$this
->
assertNull
(
$changeStream
->
current
());
}
private
function
assertStartAtOperationTime
(
TimestampInterface
$expectedOperationTime
,
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'pipeline'
,
$command
);
$this
->
assertInternalType
(
'array'
,
$command
->
pipeline
);
$this
->
assertArrayHasKey
(
0
,
$command
->
pipeline
);
$this
->
assertObjectHasAttribute
(
'$changeStream'
,
$command
->
pipeline
[
0
]);
$this
->
assertObjectHasAttribute
(
'startAtOperationTime'
,
$command
->
pipeline
[
0
]
->
{
'$changeStream'
});
$this
->
assertEquals
(
$expectedOperationTime
,
$command
->
pipeline
[
0
]
->
{
'$changeStream'
}
->
startAtOperationTime
);
}
public
function
testRewindResumesAfterConnectionException
()
{
/* In order to trigger a dropped connection, we'll use a new client with
...
...
@@ -148,8 +243,8 @@ class WatchFunctionalTest extends FunctionalTestCase
function
()
use
(
$changeStream
)
{
$changeStream
->
rewind
();
},
function
(
stdClass
$command
)
use
(
&
$commands
)
{
$commands
[]
=
key
((
array
)
$command
);
function
(
array
$event
)
use
(
&
$commands
)
{
$commands
[]
=
$event
[
'started'
]
->
getCommandName
(
);
}
);
$this
->
fail
(
'ConnectionTimeoutException was not thrown'
);
...
...
@@ -203,7 +298,7 @@ class WatchFunctionalTest extends FunctionalTestCase
'documentKey'
=>
[
'_id'
=>
2
],
];
$this
->
assert
Same
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
assert
Matches
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
killChangeStreamCursor
(
$changeStream
);
...
...
@@ -224,7 +319,7 @@ class WatchFunctionalTest extends FunctionalTestCase
'documentKey'
=>
[
'_id'
=>
3
],
];
$this
->
assert
Same
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
assert
Matches
Document
(
$expectedResult
,
$changeStream
->
current
());
}
public
function
testKey
()
...
...
@@ -452,7 +547,7 @@ class WatchFunctionalTest extends FunctionalTestCase
'ns'
=>
[
'db'
=>
$this
->
getDatabaseName
(),
'coll'
=>
$this
->
getCollectionName
()],
'documentKey'
=>
[
'_id'
=>
1
],
];
$this
->
assert
Same
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
assert
Matches
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
killChangeStreamCursor
(
$changeStream
);
...
...
@@ -466,7 +561,7 @@ class WatchFunctionalTest extends FunctionalTestCase
'ns'
=>
[
'db'
=>
$this
->
getDatabaseName
(),
'coll'
=>
$this
->
getCollectionName
()],
'documentKey'
=>
[
'_id'
=>
2
],
];
$this
->
assert
Same
Document
(
$expectedResult
,
$changeStream
->
current
());
$this
->
assert
Matches
Document
(
$expectedResult
,
$changeStream
->
current
());
}
/**
...
...
@@ -484,16 +579,8 @@ class WatchFunctionalTest extends FunctionalTestCase
$changeStream
->
next
();
$this
->
assertTrue
(
$changeStream
->
valid
());
$changeDocument
=
$changeStream
->
current
();
// Unset the resume token and namespace, which are intentionally omitted
if
(
is_array
(
$changeDocument
))
{
unset
(
$changeDocument
[
'_id'
],
$changeDocument
[
'ns'
]);
}
else
{
unset
(
$changeDocument
->
_id
,
$changeDocument
->
ns
);
}
$this
->
assert
Equals
(
$expectedChangeDocument
,
$changeDocument
);
$this
->
assert
MatchesDocument
(
$expectedChangeDocument
,
$changeStream
->
current
()
);
}
public
function
provideTypeMapOptionsAndExpectedChangeDocument
()
...
...
@@ -600,9 +687,10 @@ class WatchFunctionalTest extends FunctionalTestCase
function
()
use
(
$operation
,
&
$changeStream
)
{
$changeStream
=
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
$changeStream
)
use
(
&
$originalSession
)
{
if
(
isset
(
$changeStream
->
aggregate
))
{
$originalSession
=
bin2hex
((
string
)
$changeStream
->
lsid
->
id
);
function
(
array
$event
)
use
(
&
$originalSession
)
{
$command
=
$event
[
'started'
]
->
getCommand
();
if
(
isset
(
$command
->
aggregate
))
{
$originalSession
=
bin2hex
((
string
)
$command
->
lsid
->
id
);
}
}
);
...
...
@@ -614,9 +702,9 @@ class WatchFunctionalTest extends FunctionalTestCase
function
()
use
(
&
$changeStream
)
{
$changeStream
->
next
();
},
function
(
$changeStream
)
use
(
&
$sessionAfterResume
,
&
$commands
)
{
$commands
[]
=
key
((
array
)
$changeStream
);
$sessionAfterResume
[]
=
bin2hex
((
string
)
$
changeStream
->
lsid
->
id
);
function
(
array
$event
)
use
(
&
$sessionAfterResume
,
&
$commands
)
{
$commands
[]
=
$event
[
'started'
]
->
getCommandName
(
);
$sessionAfterResume
[]
=
bin2hex
((
string
)
$
event
[
'started'
]
->
getCommand
()
->
lsid
->
id
);
}
);
...
...
tests/Operation/WatchTest.php
View file @
9739904e
...
...
@@ -4,6 +4,7 @@ namespace MongoDB\Tests\Operation;
use
MongoDB\Exception\InvalidArgumentException
;
use
MongoDB\Operation\Watch
;
use
stdClass
;
/**
* Although these are unit tests, we extend FunctionalTestCase because Watch is
...
...
@@ -11,6 +12,14 @@ use MongoDB\Operation\Watch;
*/
class
WatchTest
extends
FunctionalTestCase
{
public
function
testConstructorCollectionNameShouldBeNullIfDatabaseNameIsNull
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
expectExceptionMessage
(
'$collectionName should also be null if $databaseName is null'
);
new
Watch
(
$this
->
manager
,
null
,
'foo'
,
[]);
}
public
function
testConstructorPipelineArgumentMustBeAList
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
...
...
@@ -67,10 +76,19 @@ class WatchTest extends FunctionalTestCase
$options
[][]
=
[
'session'
=>
$value
];
}
foreach
(
$this
->
getInvalidTimestampValues
()
as
$value
)
{
$options
[][]
=
[
'startAtOperationTime'
=>
$value
];
}
foreach
(
$this
->
getInvalidArrayValues
()
as
$value
)
{
$options
[][]
=
[
'typeMap'
=>
$value
];
}
return
$options
;
}
private
function
getInvalidTimestampValues
()
{
return
[
123
,
3.14
,
'foo'
,
true
,
[],
new
stdClass
];
}
}
tests/TestCase.php
View file @
9739904e
...
...
@@ -69,6 +69,49 @@ abstract class TestCase extends BaseTestCase
$this
->
assertCount
(
1
,
$errors
);
}
/**
* Asserts that a document has expected values for some fields.
*
* Only fields in the expected document will be checked. The actual document
* may contain additional fields.
*
* @param array|object $expectedDocument
* @param array|object $actualDocument
*/
protected
function
assertMatchesDocument
(
$expectedDocument
,
$actualDocument
)
{
$normalizedExpectedDocument
=
$this
->
normalizeBSON
(
$expectedDocument
);
$normalizedActualDocument
=
$this
->
normalizeBSON
(
$actualDocument
);
$extraKeys
=
[];
/* Avoid unsetting fields while we're iterating on the ArrayObject to
* work around https://bugs.php.net/bug.php?id=70246 */
foreach
(
$normalizedActualDocument
as
$key
=>
$value
)
{
if
(
!
$normalizedExpectedDocument
->
offsetExists
(
$key
))
{
$extraKeys
[]
=
$key
;
}
}
foreach
(
$extraKeys
as
$key
)
{
$normalizedActualDocument
->
offsetUnset
(
$key
);
}
$this
->
assertEquals
(
\MongoDB\BSON\toJSON
(
\MongoDB\BSON\fromPHP
(
$normalizedExpectedDocument
)),
\MongoDB\BSON\toJSON
(
\MongoDB\BSON\fromPHP
(
$normalizedActualDocument
))
);
}
/**
* Asserts that a document has expected values for all fields.
*
* The actual document will be compared directly with the expected document
* and may not contain extra fields.
*
* @param array|object $expectedDocument
* @param array|object $actualDocument
*/
protected
function
assertSameDocument
(
$expectedDocument
,
$actualDocument
)
{
$this
->
assertEquals
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment