mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 21:49:15 +01:00
MDL-67385 libraries: Upgrde mongodb to version 1.5.1
This commit is contained in:
parent
5a28e4ec05
commit
02c64a4c1b
@ -25,13 +25,16 @@ use MongoDB\Exception\BadMethodCallException;
|
||||
*/
|
||||
class BulkWriteResult
|
||||
{
|
||||
/** @var WriteResult */
|
||||
private $writeResult;
|
||||
|
||||
/** @var mixed[] */
|
||||
private $insertedIds;
|
||||
|
||||
/** @var boolean */
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
* @param mixed[] $insertedIds
|
||||
*/
|
||||
|
208
cache/stores/mongodb/MongoDB/ChangeStream.php
vendored
208
cache/stores/mongodb/MongoDB/ChangeStream.php
vendored
@ -17,15 +17,15 @@
|
||||
|
||||
namespace MongoDB;
|
||||
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use Iterator;
|
||||
use MongoDB\Driver\CursorId;
|
||||
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;
|
||||
use Iterator;
|
||||
use MongoDB\Model\ChangeStreamIterator;
|
||||
use function call_user_func;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* Iterator for a change stream.
|
||||
@ -42,27 +42,39 @@ class ChangeStream implements Iterator
|
||||
*/
|
||||
const CURSOR_NOT_FOUND = 43;
|
||||
|
||||
private static $errorCodeCappedPositionLost = 136;
|
||||
private static $errorCodeInterrupted = 11601;
|
||||
private static $errorCodeCursorKilled = 237;
|
||||
/** @var array */
|
||||
private static $nonResumableErrorCodes = [
|
||||
136, // CappedPositionLost
|
||||
237, // CursorKilled
|
||||
11601, // Interrupted
|
||||
];
|
||||
|
||||
private $resumeToken;
|
||||
/** @var callable */
|
||||
private $resumeCallable;
|
||||
private $csIt;
|
||||
|
||||
/** @var ChangeStreamIterator */
|
||||
private $iterator;
|
||||
|
||||
/** @var integer */
|
||||
private $key = 0;
|
||||
|
||||
/**
|
||||
* Whether the change stream has advanced to its first result. This is used
|
||||
* to determine whether $key should be incremented after an iteration event.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $hasAdvanced = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @internal
|
||||
* @param Cursor $cursor
|
||||
* @param callable $resumeCallable
|
||||
* @param ChangeStreamIterator $iterator
|
||||
* @param callable $resumeCallable
|
||||
*/
|
||||
public function __construct(Cursor $cursor, callable $resumeCallable)
|
||||
public function __construct(ChangeStreamIterator $iterator, callable $resumeCallable)
|
||||
{
|
||||
$this->iterator = $iterator;
|
||||
$this->resumeCallable = $resumeCallable;
|
||||
$this->csIt = new IteratorIterator($cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,15 +83,29 @@ class ChangeStream implements Iterator
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->csIt->current();
|
||||
return $this->iterator->current();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \MongoDB\Driver\CursorId
|
||||
* @return CursorId
|
||||
*/
|
||||
public function getCursorId()
|
||||
{
|
||||
return $this->csIt->getInnerIterator()->getId();
|
||||
return $this->iterator->getInnerIterator()->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resume token for the iterator's current position.
|
||||
*
|
||||
* Null may be returned if no change documents have been iterated and the
|
||||
* server did not include a postBatchResumeToken in its aggregate or getMore
|
||||
* command response.
|
||||
*
|
||||
* @return array|object|null
|
||||
*/
|
||||
public function getResumeToken()
|
||||
{
|
||||
return $this->iterator->getResumeToken();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,60 +117,40 @@ class ChangeStream implements Iterator
|
||||
if ($this->valid()) {
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.next
|
||||
* @return void
|
||||
* @throws ResumeTokenException
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
try {
|
||||
$this->csIt->next();
|
||||
if ($this->valid()) {
|
||||
if ($this->hasAdvanced) {
|
||||
$this->key++;
|
||||
}
|
||||
$this->hasAdvanced = true;
|
||||
$this->resumeToken = $this->extractResumeToken($this->csIt->current());
|
||||
}
|
||||
/* If the cursorId is 0, the server has invalidated the cursor so we
|
||||
* will never perform another getMore. This means that we cannot
|
||||
* resume and we can therefore unset the resumeCallable, which will
|
||||
* free any reference to Watch. This will also free the only
|
||||
* reference to an implicit session, since any such reference
|
||||
* belongs to Watch. */
|
||||
if ((string) $this->getCursorId() === '0') {
|
||||
$this->resumeCallable = null;
|
||||
}
|
||||
$this->iterator->next();
|
||||
$this->onIteration($this->hasAdvanced);
|
||||
} catch (RuntimeException $e) {
|
||||
if ($this->isResumableError($e)) {
|
||||
$this->resume();
|
||||
}
|
||||
$this->resumeOrThrow($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.rewind
|
||||
* @return void
|
||||
* @throws ResumeTokenException
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
try {
|
||||
$this->csIt->rewind();
|
||||
if ($this->valid()) {
|
||||
$this->hasAdvanced = true;
|
||||
$this->resumeToken = $this->extractResumeToken($this->csIt->current());
|
||||
}
|
||||
// As with next(), free the callable once we know it will never be used.
|
||||
if ((string) $this->getCursorId() === '0') {
|
||||
$this->resumeCallable = null;
|
||||
}
|
||||
$this->iterator->rewind();
|
||||
/* Unlike next() and resume(), the decision to increment the key
|
||||
* does not depend on whether the change stream has advanced. This
|
||||
* ensures that multiple calls to rewind() do not alter state. */
|
||||
$this->onIteration(false);
|
||||
} catch (RuntimeException $e) {
|
||||
if ($this->isResumableError($e)) {
|
||||
$this->resume();
|
||||
}
|
||||
$this->resumeOrThrow($e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,40 +160,7 @@ class ChangeStream implements Iterator
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->csIt->valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the resume token (i.e. "_id" field) from the change document.
|
||||
*
|
||||
* @param array|document $document Change document
|
||||
* @return mixed
|
||||
* @throws InvalidArgumentException
|
||||
* @throws ResumeTokenException if the resume token is not found or invalid
|
||||
*/
|
||||
private function extractResumeToken($document)
|
||||
{
|
||||
if ( ! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
if ($document instanceof Serializable) {
|
||||
return $this->extractResumeToken($document->bsonSerialize());
|
||||
}
|
||||
|
||||
$resumeToken = is_array($document)
|
||||
? (isset($document['_id']) ? $document['_id'] : null)
|
||||
: (isset($document->_id) ? $document->_id : null);
|
||||
|
||||
if ( ! isset($resumeToken)) {
|
||||
throw ResumeTokenException::notFound();
|
||||
}
|
||||
|
||||
if ( ! is_array($resumeToken) && ! is_object($resumeToken)) {
|
||||
throw ResumeTokenException::invalidType($resumeToken);
|
||||
}
|
||||
|
||||
return $resumeToken;
|
||||
return $this->iterator->valid();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,11 +176,15 @@ class ChangeStream implements Iterator
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! $exception instanceof ServerException) {
|
||||
if (! $exception instanceof ServerException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_array($exception->getCode(), [self::$errorCodeCappedPositionLost, self::$errorCodeCursorKilled, self::$errorCodeInterrupted])) {
|
||||
if ($exception->hasErrorLabel('NonResumableChangeStreamError')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_array($exception->getCode(), self::$nonResumableErrorCodes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -215,14 +192,63 @@ class ChangeStream implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new changeStream after a resumable server error.
|
||||
* Perform housekeeping after an iteration event.
|
||||
*
|
||||
* @param boolean $incrementKey Increment $key if there is a current result
|
||||
* @throws ResumeTokenException
|
||||
*/
|
||||
private function onIteration($incrementKey)
|
||||
{
|
||||
/* If the cursorId is 0, the server has invalidated the cursor and we
|
||||
* will never perform another getMore nor need to resume since any
|
||||
* remaining results (up to and including the invalidate event) will
|
||||
* have been received in the last response. Therefore, we can unset the
|
||||
* resumeCallable. This will free any reference to Watch as well as the
|
||||
* only reference to any implicit session created therein. */
|
||||
if ((string) $this->getCursorId() === '0') {
|
||||
$this->resumeCallable = null;
|
||||
}
|
||||
|
||||
/* Return early if there is not a current result. Avoid any attempt to
|
||||
* increment the iterator's key. */
|
||||
if (! $this->valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($incrementKey) {
|
||||
$this->key++;
|
||||
}
|
||||
|
||||
$this->hasAdvanced = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreates the ChangeStreamIterator after a resumable server error.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function resume()
|
||||
{
|
||||
$newChangeStream = call_user_func($this->resumeCallable, $this->resumeToken);
|
||||
$this->csIt = $newChangeStream->csIt;
|
||||
$this->csIt->rewind();
|
||||
$this->iterator = call_user_func($this->resumeCallable, $this->getResumeToken(), $this->hasAdvanced);
|
||||
$this->iterator->rewind();
|
||||
|
||||
$this->onIteration($this->hasAdvanced);
|
||||
}
|
||||
|
||||
/**
|
||||
* Either resumes after a resumable error or re-throws the exception.
|
||||
*
|
||||
* @param RuntimeException $exception
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function resumeOrThrow(RuntimeException $exception)
|
||||
{
|
||||
if ($this->isResumableError($exception)) {
|
||||
$this->resume();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
51
cache/stores/mongodb/MongoDB/Client.php
vendored
51
cache/stores/mongodb/MongoDB/Client.php
vendored
@ -17,35 +17,55 @@
|
||||
|
||||
namespace MongoDB;
|
||||
|
||||
use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\BSONArray;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use MongoDB\Model\DatabaseInfoIterator;
|
||||
use MongoDB\Operation\DropDatabase;
|
||||
use MongoDB\Operation\ListDatabases;
|
||||
use MongoDB\Operation\Watch;
|
||||
use function is_array;
|
||||
|
||||
class Client
|
||||
{
|
||||
/** @var array */
|
||||
private static $defaultTypeMap = [
|
||||
'array' => 'MongoDB\Model\BSONArray',
|
||||
'document' => 'MongoDB\Model\BSONDocument',
|
||||
'root' => 'MongoDB\Model\BSONDocument',
|
||||
'array' => BSONArray::class,
|
||||
'document' => BSONDocument::class,
|
||||
'root' => BSONDocument::class,
|
||||
];
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWritableCommandWriteConcern = 5;
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
/** @var ReadConcern */
|
||||
private $readConcern;
|
||||
|
||||
/** @var ReadPreference */
|
||||
private $readPreference;
|
||||
|
||||
/** @var string */
|
||||
private $uri;
|
||||
|
||||
/** @var array */
|
||||
private $typeMap;
|
||||
|
||||
/** @var WriteConcern */
|
||||
private $writeConcern;
|
||||
|
||||
/**
|
||||
@ -146,13 +166,13 @@ class Client
|
||||
*/
|
||||
public function dropDatabase($databaseName, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -217,6 +237,7 @@ class Client
|
||||
* List databases.
|
||||
*
|
||||
* @see ListDatabases::__construct() for supported options
|
||||
* @param array $options
|
||||
* @return DatabaseInfoIterator
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
@ -225,7 +246,7 @@ class Client
|
||||
public function listDatabases(array $options = [])
|
||||
{
|
||||
$operation = new ListDatabases($options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -267,8 +288,8 @@ class Client
|
||||
* Start a new client session.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-manager.startsession.php
|
||||
* @param array $options Session options
|
||||
* @return MongoDB\Driver\Session
|
||||
* @param array $options Session options
|
||||
* @return Session
|
||||
*/
|
||||
public function startSession(array $options = [])
|
||||
{
|
||||
@ -286,17 +307,17 @@ class Client
|
||||
*/
|
||||
public function watch(array $pipeline = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
|
246
cache/stores/mongodb/MongoDB/Collection.php
vendored
246
cache/stores/mongodb/MongoDB/Collection.php
vendored
@ -18,24 +18,24 @@
|
||||
namespace MongoDB;
|
||||
|
||||
use MongoDB\BSON\JavascriptInterface;
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\ChangeStream;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\BSONArray;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use MongoDB\Model\IndexInfo;
|
||||
use MongoDB\Model\IndexInfoIterator;
|
||||
use MongoDB\Operation\Aggregate;
|
||||
use MongoDB\Operation\BulkWrite;
|
||||
use MongoDB\Operation\CreateIndexes;
|
||||
use MongoDB\Operation\Count;
|
||||
use MongoDB\Operation\CountDocuments;
|
||||
use MongoDB\Operation\CreateIndexes;
|
||||
use MongoDB\Operation\DeleteMany;
|
||||
use MongoDB\Operation\DeleteOne;
|
||||
use MongoDB\Operation\Distinct;
|
||||
@ -58,24 +58,52 @@ use MongoDB\Operation\UpdateMany;
|
||||
use MongoDB\Operation\UpdateOne;
|
||||
use MongoDB\Operation\Watch;
|
||||
use Traversable;
|
||||
use function array_diff_key;
|
||||
use function array_intersect_key;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function strlen;
|
||||
|
||||
class Collection
|
||||
{
|
||||
/** @var array */
|
||||
private static $defaultTypeMap = [
|
||||
'array' => 'MongoDB\Model\BSONArray',
|
||||
'document' => 'MongoDB\Model\BSONDocument',
|
||||
'root' => 'MongoDB\Model\BSONDocument',
|
||||
'array' => BSONArray::class,
|
||||
'document' => BSONDocument::class,
|
||||
'root' => BSONDocument::class,
|
||||
];
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForFindAndModifyWriteConcern = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWritableCommandWriteConcern = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcernWithWriteStage = 8;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
/** @var ReadConcern */
|
||||
private $readConcern;
|
||||
|
||||
/** @var ReadPreference */
|
||||
private $readPreference;
|
||||
|
||||
/** @var array */
|
||||
private $typeMap;
|
||||
|
||||
/** @var WriteConcern */
|
||||
private $writeConcern;
|
||||
|
||||
/**
|
||||
@ -116,11 +144,11 @@ class Collection
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -128,7 +156,7 @@ class Collection
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
$this->manager = $manager;
|
||||
@ -189,32 +217,39 @@ class Collection
|
||||
*/
|
||||
public function aggregate(array $pipeline, array $options = [])
|
||||
{
|
||||
$hasOutStage = \MongoDB\is_last_pipeline_operator_out($pipeline);
|
||||
$hasWriteStage = is_last_pipeline_operator_write($pipeline);
|
||||
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
if ($hasOutStage) {
|
||||
if ($hasWriteStage) {
|
||||
$options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY);
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
/* A "majority" read concern is not compatible with the $out stage, so
|
||||
* avoid providing the Collection's read concern if it would conflict.
|
||||
/* MongoDB 4.2 and later supports a read concern when an $out stage is
|
||||
* being used, but earlier versions do not.
|
||||
*
|
||||
* A read concern is also not compatible with transactions.
|
||||
*/
|
||||
if ( ! isset($options['readConcern']) &&
|
||||
! ($hasOutStage && $this->readConcern->getLevel() === ReadConcern::MAJORITY) &&
|
||||
\MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) &&
|
||||
server_supports_feature($server, self::$wireVersionForReadConcern) &&
|
||||
! is_in_transaction($options) &&
|
||||
( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage))
|
||||
) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
if ($hasOutStage && ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if ($hasWriteStage &&
|
||||
! isset($options['writeConcern']) &&
|
||||
server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) &&
|
||||
! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -236,12 +271,12 @@ class Collection
|
||||
*/
|
||||
public function bulkWrite(array $operations, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new BulkWrite($this->databaseName, $this->collectionName, $operations, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -262,13 +297,13 @@ class Collection
|
||||
*/
|
||||
public function count($filter = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
@ -291,13 +326,13 @@ class Collection
|
||||
*/
|
||||
public function countDocuments($filter = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
@ -357,9 +392,9 @@ class Collection
|
||||
*/
|
||||
public function createIndexes(array $indexes, array $options = [])
|
||||
{
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -382,12 +417,12 @@ class Collection
|
||||
*/
|
||||
public function deleteMany($filter, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new DeleteMany($this->databaseName, $this->collectionName, $filter, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -406,12 +441,12 @@ class Collection
|
||||
*/
|
||||
public function deleteOne($filter, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new DeleteOne($this->databaseName, $this->collectionName, $filter, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -420,9 +455,9 @@ class Collection
|
||||
* Finds the distinct values for a specified field across the collection.
|
||||
*
|
||||
* @see Distinct::__construct() for supported options
|
||||
* @param string $fieldName Field for which to return distinct values
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Command options
|
||||
* @param string $fieldName Field for which to return distinct values
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Command options
|
||||
* @return mixed[]
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if options are not supported by the selected server
|
||||
@ -431,13 +466,17 @@ class Collection
|
||||
*/
|
||||
public function distinct($fieldName, $filter = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
@ -458,13 +497,13 @@ class Collection
|
||||
*/
|
||||
public function drop(array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -478,7 +517,7 @@ class Collection
|
||||
*
|
||||
* @see DropIndexes::__construct() for supported options
|
||||
* @param string|IndexInfo $indexName Index name or model object
|
||||
* @param array $options Additional options
|
||||
* @param array $options Additional options
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if options are not supported by the selected server
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
@ -492,13 +531,13 @@ class Collection
|
||||
throw new InvalidArgumentException('dropIndexes() must be used to drop multiple indexes');
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -519,13 +558,13 @@ class Collection
|
||||
*/
|
||||
public function dropIndexes(array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -545,15 +584,15 @@ class Collection
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function EstimatedDocumentCount(array $options = [])
|
||||
public function estimatedDocumentCount(array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
@ -567,8 +606,8 @@ class Collection
|
||||
*
|
||||
* @see Explain::__construct() for supported options
|
||||
* @see http://docs.mongodb.org/manual/reference/command/explain/
|
||||
* @param Explainable $explainable Command on which to run explain
|
||||
* @param array $options Additional options
|
||||
* @param Explainable $explainable Command on which to run explain
|
||||
* @param array $options Additional options
|
||||
* @return array|object
|
||||
* @throws UnsupportedException if explainable or options are not supported by the selected server
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
@ -576,15 +615,15 @@ class Collection
|
||||
*/
|
||||
public function explain(Explainable $explainable, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
$operation = new Explain($this->databaseName, $explainable, $options);
|
||||
|
||||
@ -605,17 +644,17 @@ class Collection
|
||||
*/
|
||||
public function find($filter = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
@ -638,17 +677,17 @@ class Collection
|
||||
*/
|
||||
public function findOne($filter = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
@ -674,13 +713,13 @@ class Collection
|
||||
*/
|
||||
public function findOneAndDelete($filter, array $options = [])
|
||||
{
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
@ -711,13 +750,13 @@ class Collection
|
||||
*/
|
||||
public function findOneAndReplace($filter, $replacement, array $options = [])
|
||||
{
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
@ -748,13 +787,13 @@ class Collection
|
||||
*/
|
||||
public function findOneAndUpdate($filter, $update, array $options = [])
|
||||
{
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
@ -859,12 +898,12 @@ class Collection
|
||||
*/
|
||||
public function insertMany(array $documents, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new InsertMany($this->databaseName, $this->collectionName, $documents, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -882,12 +921,12 @@ class Collection
|
||||
*/
|
||||
public function insertOne($document, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new InsertOne($this->databaseName, $this->collectionName, $document, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -896,6 +935,7 @@ class Collection
|
||||
* Returns information for all indexes for the collection.
|
||||
*
|
||||
* @see ListIndexes::__construct() for supported options
|
||||
* @param array $options
|
||||
* @return IndexInfoIterator
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
@ -903,7 +943,7 @@ class Collection
|
||||
public function listIndexes(array $options = [])
|
||||
{
|
||||
$operation = new ListIndexes($this->databaseName, $this->collectionName, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -913,10 +953,10 @@ class Collection
|
||||
*
|
||||
* @see MapReduce::__construct() for supported options
|
||||
* @see http://docs.mongodb.org/manual/reference/command/mapReduce/
|
||||
* @param JavascriptInterface $map Map function
|
||||
* @param JavascriptInterface $reduce Reduce function
|
||||
* @param string|array|object $out Output specification
|
||||
* @param array $options Command options
|
||||
* @param JavascriptInterface $map Map function
|
||||
* @param JavascriptInterface $reduce Reduce function
|
||||
* @param string|array|object $out Output specification
|
||||
* @param array $options Command options
|
||||
* @return MapReduceResult
|
||||
* @throws UnsupportedException if options are not supported by the selected server
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
@ -925,9 +965,9 @@ class Collection
|
||||
*/
|
||||
public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = [])
|
||||
{
|
||||
$hasOutputCollection = ! \MongoDB\is_mapreduce_output_inline($out);
|
||||
$hasOutputCollection = ! is_mapreduce_output_inline($out);
|
||||
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
@ -936,20 +976,22 @@ class Collection
|
||||
$options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY);
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
/* A "majority" read concern is not compatible with inline output, so
|
||||
* avoid providing the Collection's read concern if it would conflict.
|
||||
*
|
||||
* A read concern is also not compatible with transactions.
|
||||
*/
|
||||
if ( ! isset($options['readConcern']) && ! ($hasOutputCollection && $this->readConcern->getLevel() === ReadConcern::MAJORITY) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && ! ($hasOutputCollection && $this->readConcern->getLevel() === ReadConcern::MAJORITY) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -973,12 +1015,12 @@ class Collection
|
||||
*/
|
||||
public function replaceOne($filter, $replacement, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new ReplaceOne($this->databaseName, $this->collectionName, $filter, $replacement, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -998,12 +1040,12 @@ class Collection
|
||||
*/
|
||||
public function updateMany($filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new UpdateMany($this->databaseName, $this->collectionName, $filter, $update, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -1023,12 +1065,12 @@ class Collection
|
||||
*/
|
||||
public function updateOne($filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['writeConcern'])) {
|
||||
if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new UpdateOne($this->databaseName, $this->collectionName, $filter, $update, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -1044,11 +1086,11 @@ class Collection
|
||||
*/
|
||||
public function watch(array $pipeline = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
/* Although change streams require a newer version of the server than
|
||||
* read concerns, perform the usual wire version check before inheriting
|
||||
@ -1057,11 +1099,11 @@ class Collection
|
||||
* related to change streams being unsupported instead of an
|
||||
* UnsupportedException regarding use of the "readConcern" option from
|
||||
* the Aggregate operation class. */
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
|
139
cache/stores/mongodb/MongoDB/Database.php
vendored
139
cache/stores/mongodb/MongoDB/Database.php
vendored
@ -17,17 +17,20 @@
|
||||
|
||||
namespace MongoDB;
|
||||
|
||||
use MongoDB\Collection;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\GridFS\Bucket;
|
||||
use MongoDB\Model\BSONArray;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use MongoDB\Model\CollectionInfoIterator;
|
||||
use MongoDB\Operation\Aggregate;
|
||||
use MongoDB\Operation\CreateCollection;
|
||||
use MongoDB\Operation\DatabaseCommand;
|
||||
use MongoDB\Operation\DropCollection;
|
||||
@ -35,22 +38,44 @@ use MongoDB\Operation\DropDatabase;
|
||||
use MongoDB\Operation\ListCollections;
|
||||
use MongoDB\Operation\ModifyCollection;
|
||||
use MongoDB\Operation\Watch;
|
||||
use Traversable;
|
||||
use function is_array;
|
||||
use function strlen;
|
||||
|
||||
class Database
|
||||
{
|
||||
/** @var array */
|
||||
private static $defaultTypeMap = [
|
||||
'array' => 'MongoDB\Model\BSONArray',
|
||||
'document' => 'MongoDB\Model\BSONDocument',
|
||||
'root' => 'MongoDB\Model\BSONDocument',
|
||||
'array' => BSONArray::class,
|
||||
'document' => BSONDocument::class,
|
||||
'root' => BSONDocument::class,
|
||||
];
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWritableCommandWriteConcern = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcernWithWriteStage = 8;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
/** @var ReadConcern */
|
||||
private $readConcern;
|
||||
|
||||
/** @var ReadPreference */
|
||||
private $readPreference;
|
||||
|
||||
/** @var array */
|
||||
private $typeMap;
|
||||
|
||||
/** @var WriteConcern */
|
||||
private $writeConcern;
|
||||
|
||||
/**
|
||||
@ -87,11 +112,11 @@ class Database
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -99,7 +124,7 @@ class Database
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
$this->manager = $manager;
|
||||
@ -155,6 +180,63 @@ class Database
|
||||
return $this->databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an aggregation framework pipeline on the database for pipeline
|
||||
* stages that do not require an underlying collection, such as $currentOp
|
||||
* and $listLocalSessions. Requires MongoDB >= 3.6
|
||||
*
|
||||
* @see Aggregate::__construct() for supported options
|
||||
* @param array $pipeline List of pipeline operations
|
||||
* @param array $options Command options
|
||||
* @return Traversable
|
||||
* @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
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function aggregate(array $pipeline, array $options = [])
|
||||
{
|
||||
$hasWriteStage = is_last_pipeline_operator_write($pipeline);
|
||||
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
if ($hasWriteStage) {
|
||||
$options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY);
|
||||
}
|
||||
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
/* MongoDB 4.2 and later supports a read concern when an $out stage is
|
||||
* being used, but earlier versions do not.
|
||||
*
|
||||
* A read concern is also not compatible with transactions.
|
||||
*/
|
||||
if (! isset($options['readConcern']) &&
|
||||
server_supports_feature($server, self::$wireVersionForReadConcern) &&
|
||||
! is_in_transaction($options) &&
|
||||
( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage))
|
||||
) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
if ($hasWriteStage &&
|
||||
! isset($options['writeConcern']) &&
|
||||
server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) &&
|
||||
! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new Aggregate($this->databaseName, null, $pipeline, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command on this database.
|
||||
*
|
||||
@ -167,16 +249,16 @@ class Database
|
||||
*/
|
||||
public function command($command, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$operation = new DatabaseCommand($this->databaseName, $command, $options);
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -194,13 +276,13 @@ class Database
|
||||
*/
|
||||
public function createCollection($collectionName, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -221,13 +303,13 @@ class Database
|
||||
*/
|
||||
public function drop(array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -249,13 +331,13 @@ class Database
|
||||
*/
|
||||
public function dropCollection($collectionName, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -338,7 +420,7 @@ class Database
|
||||
public function listCollections(array $options = [])
|
||||
{
|
||||
$operation = new ListCollections($this->databaseName, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
@ -350,18 +432,19 @@ class Database
|
||||
* @param string $collectionName Collection or view to modify
|
||||
* @param array $collectionOptions Collection or view options to assign
|
||||
* @param array $options Command options
|
||||
* @return array|object
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function modifyCollection($collectionName, array $collectionOptions, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
@ -422,17 +505,17 @@ class Database
|
||||
*/
|
||||
public function watch(array $pipeline = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
$server = select_server($this->manager, $options);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,12 @@ use MongoDB\Exception\BadMethodCallException;
|
||||
*/
|
||||
class DeleteResult
|
||||
{
|
||||
/** @var WriteResult */
|
||||
private $writeResult;
|
||||
|
||||
/** @var boolean */
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
*/
|
||||
public function __construct(WriteResult $writeResult)
|
||||
{
|
||||
$this->writeResult = $writeResult;
|
||||
|
@ -17,7 +17,10 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
class BadMethodCallException extends \BadMethodCallException implements Exception
|
||||
use BadMethodCallException as BaseBadMethodCallException;
|
||||
use function sprintf;
|
||||
|
||||
class BadMethodCallException extends BaseBadMethodCallException implements Exception
|
||||
{
|
||||
/**
|
||||
* Thrown when a mutable method is invoked on an immutable object.
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
interface Exception extends \MongoDB\Driver\Exception\Exception
|
||||
use MongoDB\Driver\Exception\Exception as DriverException;
|
||||
|
||||
interface Exception extends DriverException
|
||||
{
|
||||
}
|
||||
|
@ -17,7 +17,13 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
class InvalidArgumentException extends \MongoDB\Driver\Exception\InvalidArgumentException implements Exception
|
||||
use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException;
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
|
||||
class InvalidArgumentException extends DriverInvalidArgumentException implements Exception
|
||||
{
|
||||
/**
|
||||
* Thrown when an argument or option has an invalid type.
|
||||
|
@ -17,7 +17,10 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
class ResumeTokenException extends \Exception
|
||||
use function gettype;
|
||||
use function sprintf;
|
||||
|
||||
class ResumeTokenException extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* Thrown when a resume token has an invalid type.
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
class RuntimeException extends \MongoDB\Driver\Exception\RuntimeException implements Exception
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
|
||||
class RuntimeException extends DriverRuntimeException implements Exception
|
||||
{
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
class UnexpectedValueException extends \MongoDB\Driver\Exception\UnexpectedValueException implements Exception
|
||||
use MongoDB\Driver\Exception\UnexpectedValueException as DriverUnexpectedValueException;
|
||||
|
||||
class UnexpectedValueException extends DriverUnexpectedValueException implements Exception
|
||||
{
|
||||
}
|
||||
|
@ -59,6 +59,16 @@ class UnsupportedException extends RuntimeException
|
||||
return new static('Read concern is not supported by the server executing this command');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a readConcern is used with a read operation in a transaction.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function readConcernNotSupportedInTransaction()
|
||||
{
|
||||
return new static('The "readConcern" option cannot be specified within a transaction. Instead, specify it when starting the transaction.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a command's writeConcern option is not supported by a server.
|
||||
*
|
||||
@ -68,4 +78,14 @@ class UnsupportedException extends RuntimeException
|
||||
{
|
||||
return new static('Write concern is not supported by the server executing this command');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a writeConcern is used with a write operation in a transaction.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function writeConcernNotSupportedInTransaction()
|
||||
{
|
||||
return new static('The "writeConcern" option cannot be specified within a transaction. Instead, specify it when starting the transaction.');
|
||||
}
|
||||
}
|
||||
|
88
cache/stores/mongodb/MongoDB/GridFS/Bucket.php
vendored
88
cache/stores/mongodb/MongoDB/GridFS/Bucket.php
vendored
@ -19,16 +19,40 @@ namespace MongoDB\GridFS;
|
||||
|
||||
use MongoDB\Collection;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\GridFS\Exception\CorruptFileException;
|
||||
use MongoDB\GridFS\Exception\FileNotFoundException;
|
||||
use MongoDB\Model\BSONArray;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use MongoDB\Operation\Find;
|
||||
use stdClass;
|
||||
use function array_intersect_key;
|
||||
use function fopen;
|
||||
use function get_resource_type;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
use function method_exists;
|
||||
use function MongoDB\apply_type_map_to_document;
|
||||
use function MongoDB\BSON\fromPHP;
|
||||
use function MongoDB\BSON\toJSON;
|
||||
use function property_exists;
|
||||
use function sprintf;
|
||||
use function stream_context_create;
|
||||
use function stream_copy_to_stream;
|
||||
use function stream_get_meta_data;
|
||||
use function stream_get_wrappers;
|
||||
use function urlencode;
|
||||
|
||||
/**
|
||||
* Bucket provides a public API for interacting with the GridFS files and chunks
|
||||
@ -38,24 +62,50 @@ use stdClass;
|
||||
*/
|
||||
class Bucket
|
||||
{
|
||||
/** @var string */
|
||||
private static $defaultBucketName = 'fs';
|
||||
|
||||
/** @var integer */
|
||||
private static $defaultChunkSizeBytes = 261120;
|
||||
|
||||
/** @var array */
|
||||
private static $defaultTypeMap = [
|
||||
'array' => 'MongoDB\Model\BSONArray',
|
||||
'document' => 'MongoDB\Model\BSONDocument',
|
||||
'root' => 'MongoDB\Model\BSONDocument',
|
||||
'array' => BSONArray::class,
|
||||
'document' => BSONDocument::class,
|
||||
'root' => BSONDocument::class,
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
private static $streamWrapperProtocol = 'gridfs';
|
||||
|
||||
/** @var CollectionWrapper */
|
||||
private $collectionWrapper;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
/** @var string */
|
||||
private $bucketName;
|
||||
|
||||
/** @var boolean */
|
||||
private $disableMD5;
|
||||
|
||||
/** @var integer */
|
||||
private $chunkSizeBytes;
|
||||
|
||||
/** @var ReadConcern */
|
||||
private $readConcern;
|
||||
|
||||
/** @var ReadPreference */
|
||||
private $readPreference;
|
||||
|
||||
/** @var array */
|
||||
private $typeMap;
|
||||
|
||||
/** @var WriteConcern */
|
||||
private $writeConcern;
|
||||
|
||||
/**
|
||||
@ -110,11 +160,11 @@ class Bucket
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -122,7 +172,7 @@ class Bucket
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
$this->manager = $manager;
|
||||
@ -192,7 +242,7 @@ class Bucket
|
||||
*/
|
||||
public function downloadToStream($id, $destination)
|
||||
{
|
||||
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
|
||||
if (! is_resource($destination) || get_resource_type($destination) != "stream") {
|
||||
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
|
||||
}
|
||||
|
||||
@ -227,7 +277,7 @@ class Bucket
|
||||
*/
|
||||
public function downloadToStreamByName($filename, $destination, array $options = [])
|
||||
{
|
||||
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
|
||||
if (! is_resource($destination) || get_resource_type($destination) != "stream") {
|
||||
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
|
||||
}
|
||||
|
||||
@ -332,7 +382,7 @@ class Bucket
|
||||
$file = $this->getRawFileDocumentForStream($stream);
|
||||
|
||||
// Filter the raw document through the specified type map
|
||||
return \MongoDB\apply_type_map_to_document($file, $this->typeMap);
|
||||
return apply_type_map_to_document($file, $this->typeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -352,9 +402,9 @@ class Bucket
|
||||
* the root type so we can reliably access the ID.
|
||||
*/
|
||||
$typeMap = ['root' => 'stdClass'] + $this->typeMap;
|
||||
$file = \MongoDB\apply_type_map_to_document($file, $typeMap);
|
||||
$file = apply_type_map_to_document($file, $typeMap);
|
||||
|
||||
if ( ! isset($file->_id) && ! property_exists($file, '_id')) {
|
||||
if (! isset($file->_id) && ! property_exists($file, '_id')) {
|
||||
throw new CorruptFileException('file._id does not exist');
|
||||
}
|
||||
|
||||
@ -531,7 +581,7 @@ class Bucket
|
||||
? $updateResult->getMatchedCount() === 1
|
||||
: $this->collectionWrapper->findFileById($id) !== null;
|
||||
|
||||
if ( ! $found) {
|
||||
if (! $found) {
|
||||
throw FileNotFoundException::byId($id, $this->getFilesNamespace());
|
||||
}
|
||||
}
|
||||
@ -561,7 +611,7 @@ class Bucket
|
||||
*/
|
||||
public function uploadFromStream($filename, $source, array $options = [])
|
||||
{
|
||||
if ( ! is_resource($source) || get_resource_type($source) != "stream") {
|
||||
if (! is_resource($source) || get_resource_type($source) != "stream") {
|
||||
throw InvalidArgumentException::invalidType('$source', $source, 'resource');
|
||||
}
|
||||
|
||||
@ -579,10 +629,10 @@ class Bucket
|
||||
*/
|
||||
private function createPathForFile(stdClass $file)
|
||||
{
|
||||
if ( ! is_object($file->_id) || method_exists($file->_id, '__toString')) {
|
||||
if (! is_object($file->_id) || method_exists($file->_id, '__toString')) {
|
||||
$id = (string) $file->_id;
|
||||
} else {
|
||||
$id = \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP(['_id' => $file->_id]));
|
||||
$id = toJSON(fromPHP(['_id' => $file->_id]));
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
@ -631,14 +681,14 @@ class Bucket
|
||||
*/
|
||||
private function getRawFileDocumentForStream($stream)
|
||||
{
|
||||
if ( ! is_resource($stream) || get_resource_type($stream) != "stream") {
|
||||
if (! is_resource($stream) || get_resource_type($stream) != "stream") {
|
||||
throw InvalidArgumentException::invalidType('$stream', $stream, 'resource');
|
||||
}
|
||||
|
||||
$metadata = stream_get_meta_data($stream);
|
||||
|
||||
if ( ! isset ($metadata['wrapper_data']) || ! $metadata['wrapper_data'] instanceof StreamWrapper) {
|
||||
throw InvalidArgumentException::invalidType('$stream wrapper data', isset($metadata['wrapper_data']) ? $metadata['wrapper_data'] : null, 'MongoDB\Driver\GridFS\StreamWrapper');
|
||||
if (! isset($metadata['wrapper_data']) || ! $metadata['wrapper_data'] instanceof StreamWrapper) {
|
||||
throw InvalidArgumentException::invalidType('$stream wrapper data', isset($metadata['wrapper_data']) ? $metadata['wrapper_data'] : null, StreamWrapper::class);
|
||||
}
|
||||
|
||||
return $metadata['wrapper_data']->getFile();
|
||||
|
@ -18,11 +18,14 @@
|
||||
namespace MongoDB\GridFS;
|
||||
|
||||
use MongoDB\Collection;
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\UpdateResult;
|
||||
use stdClass;
|
||||
use function abs;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* CollectionWrapper abstracts the GridFS files and chunks collections.
|
||||
@ -31,10 +34,19 @@ use stdClass;
|
||||
*/
|
||||
class CollectionWrapper
|
||||
{
|
||||
/** @var string */
|
||||
private $bucketName;
|
||||
|
||||
/** @var Collection */
|
||||
private $chunksCollection;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var boolean */
|
||||
private $checkedIndexes = false;
|
||||
|
||||
/** @var Collection */
|
||||
private $filesCollection;
|
||||
|
||||
/**
|
||||
@ -121,7 +133,7 @@ class CollectionWrapper
|
||||
*
|
||||
* @see Bucket::downloadToStreamByName()
|
||||
* @see Bucket::openDownloadStreamByName()
|
||||
* @param string $filename
|
||||
* @param string $filename
|
||||
* @param integer $revision
|
||||
* @return stdClass|null
|
||||
*/
|
||||
@ -234,7 +246,7 @@ class CollectionWrapper
|
||||
*/
|
||||
public function insertChunk($chunk)
|
||||
{
|
||||
if ( ! $this->checkedIndexes) {
|
||||
if (! $this->checkedIndexes) {
|
||||
$this->ensureIndexes();
|
||||
}
|
||||
|
||||
@ -250,7 +262,7 @@ class CollectionWrapper
|
||||
*/
|
||||
public function insertFile($file)
|
||||
{
|
||||
if ( ! $this->checkedIndexes) {
|
||||
if (! $this->checkedIndexes) {
|
||||
$this->ensureIndexes();
|
||||
}
|
||||
|
||||
@ -261,7 +273,7 @@ class CollectionWrapper
|
||||
* Updates the filename field in the file document for a given ID.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param string $filename
|
||||
* @param string $filename
|
||||
* @return UpdateResult
|
||||
*/
|
||||
public function updateFilenameForId($id, $filename)
|
||||
@ -314,7 +326,7 @@ class CollectionWrapper
|
||||
|
||||
$this->checkedIndexes = true;
|
||||
|
||||
if ( ! $this->isFilesCollectionEmpty()) {
|
||||
if (! $this->isFilesCollectionEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
namespace MongoDB\GridFS\Exception;
|
||||
|
||||
use MongoDB\Exception\RuntimeException;
|
||||
use function sprintf;
|
||||
|
||||
class CorruptFileException extends RuntimeException
|
||||
{
|
||||
|
@ -18,6 +18,9 @@
|
||||
namespace MongoDB\GridFS\Exception;
|
||||
|
||||
use MongoDB\Exception\RuntimeException;
|
||||
use function MongoDB\BSON\fromPHP;
|
||||
use function MongoDB\BSON\toJSON;
|
||||
use function sprintf;
|
||||
|
||||
class FileNotFoundException extends RuntimeException
|
||||
{
|
||||
@ -43,7 +46,7 @@ class FileNotFoundException extends RuntimeException
|
||||
*/
|
||||
public static function byId($id, $namespace)
|
||||
{
|
||||
$json = \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP(['_id' => $id]));
|
||||
$json = toJSON(fromPHP(['_id' => $id]));
|
||||
|
||||
return new static(sprintf('File "%s" not found in "%s"', $json, $namespace));
|
||||
}
|
||||
|
@ -17,10 +17,17 @@
|
||||
|
||||
namespace MongoDB\GridFS;
|
||||
|
||||
use IteratorIterator;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\GridFS\Exception\CorruptFileException;
|
||||
use IteratorIterator;
|
||||
use stdClass;
|
||||
use function ceil;
|
||||
use function floor;
|
||||
use function is_integer;
|
||||
use function property_exists;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* ReadableStream abstracts the process of reading a GridFS file.
|
||||
@ -29,15 +36,34 @@ use stdClass;
|
||||
*/
|
||||
class ReadableStream
|
||||
{
|
||||
/** @var string|null */
|
||||
private $buffer;
|
||||
|
||||
/** @var integer */
|
||||
private $bufferOffset = 0;
|
||||
|
||||
/** @var integer */
|
||||
private $chunkSize;
|
||||
|
||||
/** @var integer */
|
||||
private $chunkOffset = 0;
|
||||
|
||||
/** @var IteratorIterator|null */
|
||||
private $chunksIterator;
|
||||
|
||||
/** @var CollectionWrapper */
|
||||
private $collectionWrapper;
|
||||
|
||||
/** @var float|integer */
|
||||
private $expectedLastChunkSize = 0;
|
||||
|
||||
/** @var stdClass */
|
||||
private $file;
|
||||
|
||||
/** @var integer */
|
||||
private $length;
|
||||
|
||||
/** @var integer */
|
||||
private $numChunks = 0;
|
||||
|
||||
/**
|
||||
@ -49,15 +75,15 @@ class ReadableStream
|
||||
*/
|
||||
public function __construct(CollectionWrapper $collectionWrapper, stdClass $file)
|
||||
{
|
||||
if ( ! isset($file->chunkSize) || ! is_integer($file->chunkSize) || $file->chunkSize < 1) {
|
||||
if (! isset($file->chunkSize) || ! is_integer($file->chunkSize) || $file->chunkSize < 1) {
|
||||
throw new CorruptFileException('file.chunkSize is not an integer >= 1');
|
||||
}
|
||||
|
||||
if ( ! isset($file->length) || ! is_integer($file->length) || $file->length < 0) {
|
||||
if (! isset($file->length) || ! is_integer($file->length) || $file->length < 0) {
|
||||
throw new CorruptFileException('file.length is not an integer > 0');
|
||||
}
|
||||
|
||||
if ( ! isset($file->_id) && ! property_exists($file, '_id')) {
|
||||
if (! isset($file->_id) && ! property_exists($file, '_id')) {
|
||||
throw new CorruptFileException('file._id does not exist');
|
||||
}
|
||||
|
||||
@ -202,6 +228,7 @@ class ReadableStream
|
||||
*/
|
||||
if ($lastChunkOffset > $this->chunkOffset) {
|
||||
$this->chunksIterator = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -239,7 +266,7 @@ class ReadableStream
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->chunksIterator->valid()) {
|
||||
if (! $this->chunksIterator->valid()) {
|
||||
throw CorruptFileException::missingChunk($this->chunkOffset);
|
||||
}
|
||||
|
||||
@ -253,7 +280,7 @@ class ReadableStream
|
||||
|
||||
$actualChunkSize = strlen($this->buffer);
|
||||
|
||||
$expectedChunkSize = ($this->chunkOffset === $this->numChunks - 1)
|
||||
$expectedChunkSize = $this->chunkOffset === $this->numChunks - 1
|
||||
? $this->expectedLastChunkSize
|
||||
: $this->chunkSize;
|
||||
|
||||
|
@ -17,9 +17,24 @@
|
||||
|
||||
namespace MongoDB\GridFS;
|
||||
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
use Exception;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
use stdClass;
|
||||
use function explode;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
use function is_integer;
|
||||
use function sprintf;
|
||||
use function stream_context_get_options;
|
||||
use function stream_get_wrappers;
|
||||
use function stream_wrapper_register;
|
||||
use function stream_wrapper_unregister;
|
||||
use function trigger_error;
|
||||
use const E_USER_WARNING;
|
||||
use const SEEK_CUR;
|
||||
use const SEEK_END;
|
||||
use const SEEK_SET;
|
||||
use const STREAM_IS_URL;
|
||||
|
||||
/**
|
||||
* Stream wrapper for reading and writing a GridFS file.
|
||||
@ -30,13 +45,16 @@ use stdClass;
|
||||
*/
|
||||
class StreamWrapper
|
||||
{
|
||||
/**
|
||||
* @var resource|null Stream context (set by PHP)
|
||||
*/
|
||||
/** @var resource|null Stream context (set by PHP) */
|
||||
public $context;
|
||||
|
||||
/** @var string|null */
|
||||
private $mode;
|
||||
|
||||
/** @var string|null */
|
||||
private $protocol;
|
||||
|
||||
/** @var ReadableStream|WritableStream|null */
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
@ -60,7 +78,7 @@ class StreamWrapper
|
||||
stream_wrapper_unregister($protocol);
|
||||
}
|
||||
|
||||
stream_wrapper_register($protocol, get_called_class(), \STREAM_IS_URL);
|
||||
stream_wrapper_register($protocol, static::class, STREAM_IS_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,7 +99,7 @@ class StreamWrapper
|
||||
*/
|
||||
public function stream_eof()
|
||||
{
|
||||
if ( ! $this->stream instanceof ReadableStream) {
|
||||
if (! $this->stream instanceof ReadableStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -96,6 +114,7 @@ class StreamWrapper
|
||||
* @param string $mode Mode used to open the file (only "r" and "w" are supported)
|
||||
* @param integer $options Additional flags set by the streams API
|
||||
* @param string $openedPath Not used
|
||||
* @return boolean
|
||||
*/
|
||||
public function stream_open($path, $mode, $options, &$openedPath)
|
||||
{
|
||||
@ -125,14 +144,15 @@ class StreamWrapper
|
||||
*/
|
||||
public function stream_read($length)
|
||||
{
|
||||
if ( ! $this->stream instanceof ReadableStream) {
|
||||
if (! $this->stream instanceof ReadableStream) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->stream->readBytes($length);
|
||||
} catch (Exception $e) {
|
||||
trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), \E_USER_WARNING);
|
||||
trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -145,15 +165,15 @@ class StreamWrapper
|
||||
* @param integer $whence One of SEEK_SET, SEEK_CUR, or SEEK_END
|
||||
* @return boolean True if the position was updated and false otherwise
|
||||
*/
|
||||
public function stream_seek($offset, $whence = \SEEK_SET)
|
||||
public function stream_seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
$size = $this->stream->getSize();
|
||||
|
||||
if ($whence === \SEEK_CUR) {
|
||||
if ($whence === SEEK_CUR) {
|
||||
$offset += $this->stream->tell();
|
||||
}
|
||||
|
||||
if ($whence === \SEEK_END) {
|
||||
if ($whence === SEEK_END) {
|
||||
$offset += $size;
|
||||
}
|
||||
|
||||
@ -221,14 +241,15 @@ class StreamWrapper
|
||||
*/
|
||||
public function stream_write($data)
|
||||
{
|
||||
if ( ! $this->stream instanceof WritableStream) {
|
||||
if (! $this->stream instanceof WritableStream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->stream->writeBytes($data);
|
||||
} catch (Exception $e) {
|
||||
trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), \E_USER_WARNING);
|
||||
trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -241,6 +262,7 @@ class StreamWrapper
|
||||
private function getStatTemplate()
|
||||
{
|
||||
return [
|
||||
// phpcs:disable Squiz.Arrays.ArrayDeclaration.IndexNoNewline
|
||||
0 => 0, 'dev' => 0,
|
||||
1 => 0, 'ino' => 0,
|
||||
2 => 0, 'mode' => 0,
|
||||
@ -254,6 +276,7 @@ class StreamWrapper
|
||||
10 => 0, 'ctime' => 0,
|
||||
11 => -1, 'blksize' => -1,
|
||||
12 => -1, 'blocks' => -1,
|
||||
// phpcs:enable
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,19 @@ use MongoDB\BSON\UTCDateTime;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use stdClass;
|
||||
use function array_intersect_key;
|
||||
use function hash_final;
|
||||
use function hash_init;
|
||||
use function hash_update;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\is_string_array;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* WritableStream abstracts the process of writing a GridFS file.
|
||||
@ -31,16 +44,34 @@ use stdClass;
|
||||
*/
|
||||
class WritableStream
|
||||
{
|
||||
/** @var integer */
|
||||
private static $defaultChunkSizeBytes = 261120;
|
||||
|
||||
/** @var string */
|
||||
private $buffer = '';
|
||||
|
||||
/** @var integer */
|
||||
private $chunkOffset = 0;
|
||||
|
||||
/** @var integer */
|
||||
private $chunkSize;
|
||||
|
||||
/** @var boolean */
|
||||
private $disableMD5;
|
||||
|
||||
/** @var CollectionWrapper */
|
||||
private $collectionWrapper;
|
||||
|
||||
/** @var array */
|
||||
private $file;
|
||||
|
||||
/** @var resource */
|
||||
private $hashCtx;
|
||||
|
||||
/** @var boolean */
|
||||
private $isClosed = false;
|
||||
|
||||
/** @var integer */
|
||||
private $length = 0;
|
||||
|
||||
/**
|
||||
@ -74,12 +105,12 @@ class WritableStream
|
||||
public function __construct(CollectionWrapper $collectionWrapper, $filename, array $options = [])
|
||||
{
|
||||
$options += [
|
||||
'_id' => new ObjectId,
|
||||
'_id' => new ObjectId(),
|
||||
'chunkSizeBytes' => self::$defaultChunkSizeBytes,
|
||||
'disableMD5' => false,
|
||||
];
|
||||
|
||||
if (isset($options['aliases']) && ! \MongoDB\is_string_array($options['aliases'])) {
|
||||
if (isset($options['aliases']) && ! is_string_array($options['aliases'])) {
|
||||
throw InvalidArgumentException::invalidType('"aliases" option', $options['aliases'], 'array of strings');
|
||||
}
|
||||
|
||||
@ -107,7 +138,7 @@ class WritableStream
|
||||
$this->collectionWrapper = $collectionWrapper;
|
||||
$this->disableMD5 = $options['disableMD5'];
|
||||
|
||||
if ( ! $this->disableMD5) {
|
||||
if (! $this->disableMD5) {
|
||||
$this->hashCtx = hash_init('md5');
|
||||
}
|
||||
|
||||
@ -233,9 +264,9 @@ class WritableStream
|
||||
private function fileCollectionInsert()
|
||||
{
|
||||
$this->file['length'] = $this->length;
|
||||
$this->file['uploadDate'] = new UTCDateTime;
|
||||
$this->file['uploadDate'] = new UTCDateTime();
|
||||
|
||||
if ( ! $this->disableMD5) {
|
||||
if (! $this->disableMD5) {
|
||||
$this->file['md5'] = hash_final($this->hashCtx);
|
||||
}
|
||||
|
||||
@ -265,7 +296,7 @@ class WritableStream
|
||||
'data' => new Binary($data, Binary::TYPE_GENERIC),
|
||||
];
|
||||
|
||||
if ( ! $this->disableMD5) {
|
||||
if (! $this->disableMD5) {
|
||||
hash_update($this->hashCtx, $data);
|
||||
}
|
||||
|
||||
|
@ -25,13 +25,16 @@ use MongoDB\Exception\BadMethodCallException;
|
||||
*/
|
||||
class InsertManyResult
|
||||
{
|
||||
/** @var WriteResult */
|
||||
private $writeResult;
|
||||
|
||||
/** @var mixed[] */
|
||||
private $insertedIds;
|
||||
|
||||
/** @var boolean */
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
* @param mixed[] $insertedIds
|
||||
*/
|
||||
|
@ -25,13 +25,16 @@ use MongoDB\Exception\BadMethodCallException;
|
||||
*/
|
||||
class InsertOneResult
|
||||
{
|
||||
/** @var WriteResult */
|
||||
private $writeResult;
|
||||
|
||||
/** @var mixed */
|
||||
private $insertedId;
|
||||
|
||||
/** @var boolean */
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
* @param mixed $insertedId
|
||||
*/
|
||||
|
12
cache/stores/mongodb/MongoDB/MapReduceResult.php
vendored
12
cache/stores/mongodb/MongoDB/MapReduceResult.php
vendored
@ -20,6 +20,7 @@ namespace MongoDB;
|
||||
use IteratorAggregate;
|
||||
use stdClass;
|
||||
use Traversable;
|
||||
use function call_user_func;
|
||||
|
||||
/**
|
||||
* Result class for mapReduce command results.
|
||||
@ -34,14 +35,19 @@ use Traversable;
|
||||
*/
|
||||
class MapReduceResult implements IteratorAggregate
|
||||
{
|
||||
/** @var callable */
|
||||
private $getIterator;
|
||||
|
||||
/** @var integer */
|
||||
private $executionTimeMS;
|
||||
|
||||
/** @var array */
|
||||
private $counts;
|
||||
|
||||
/** @var array */
|
||||
private $timing;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @internal
|
||||
* @param callable $getIterator Callback that returns a Traversable for mapReduce results
|
||||
* @param stdClass $result Result document from the mapReduce command
|
||||
@ -71,7 +77,7 @@ class MapReduceResult implements IteratorAggregate
|
||||
*/
|
||||
public function getExecutionTimeMS()
|
||||
{
|
||||
return $this->executionTimeMS;
|
||||
return (integer) $this->executionTimeMS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
10
cache/stores/mongodb/MongoDB/Model/BSONArray.php
vendored
10
cache/stores/mongodb/MongoDB/Model/BSONArray.php
vendored
@ -17,10 +17,12 @@
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\BSON\Unserializable;
|
||||
use ArrayObject;
|
||||
use JsonSerializable;
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\BSON\Unserializable;
|
||||
use function array_values;
|
||||
use function MongoDB\recursive_copy;
|
||||
|
||||
/**
|
||||
* Model class for a BSON array.
|
||||
@ -38,7 +40,7 @@ class BSONArray extends ArrayObject implements JsonSerializable, Serializable, U
|
||||
public function __clone()
|
||||
{
|
||||
foreach ($this as $key => $value) {
|
||||
$this[$key] = \MongoDB\recursive_copy($value);
|
||||
$this[$key] = recursive_copy($value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,7 +54,7 @@ class BSONArray extends ArrayObject implements JsonSerializable, Serializable, U
|
||||
*/
|
||||
public static function __set_state(array $properties)
|
||||
{
|
||||
$array = new static;
|
||||
$array = new static();
|
||||
$array->exchangeArray($properties);
|
||||
|
||||
return $array;
|
||||
|
@ -17,10 +17,11 @@
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\BSON\Unserializable;
|
||||
use ArrayObject;
|
||||
use JsonSerializable;
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\BSON\Unserializable;
|
||||
use function MongoDB\recursive_copy;
|
||||
|
||||
/**
|
||||
* Model class for a BSON document.
|
||||
@ -38,17 +39,18 @@ class BSONDocument extends ArrayObject implements JsonSerializable, Serializable
|
||||
public function __clone()
|
||||
{
|
||||
foreach ($this as $key => $value) {
|
||||
$this[$key] = \MongoDB\recursive_copy($value);
|
||||
$this[$key] = recursive_copy($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* This overrides the parent constructor to allow property access of entries
|
||||
* by default.
|
||||
*
|
||||
* @see http://php.net/arrayobject.construct
|
||||
* @param array $input
|
||||
* @param integer $flags
|
||||
* @param string $iterator_class
|
||||
*/
|
||||
public function __construct($input = [], $flags = ArrayObject::ARRAY_AS_PROPS, $iterator_class = 'ArrayIterator')
|
||||
{
|
||||
@ -65,7 +67,7 @@ class BSONDocument extends ArrayObject implements JsonSerializable, Serializable
|
||||
*/
|
||||
public static function __set_state(array $properties)
|
||||
{
|
||||
$document = new static;
|
||||
$document = new static();
|
||||
$document->exchangeArray($properties);
|
||||
|
||||
return $document;
|
||||
|
@ -17,22 +17,40 @@
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use Iterator;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use function is_array;
|
||||
use function MongoDB\BSON\toPHP;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use function unpack;
|
||||
|
||||
/**
|
||||
* Iterator for BSON documents.
|
||||
*/
|
||||
class BSONIterator implements Iterator
|
||||
{
|
||||
/** @var integer */
|
||||
private static $bsonSize = 4;
|
||||
|
||||
/** @var string */
|
||||
private $buffer;
|
||||
|
||||
/** @var integer */
|
||||
private $bufferLength;
|
||||
|
||||
/** @var mixed */
|
||||
private $current;
|
||||
|
||||
/** @var integer */
|
||||
private $key = 0;
|
||||
|
||||
/** @var integer */
|
||||
private $position = 0;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -54,7 +72,7 @@ class BSONIterator implements Iterator
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
if (! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = [];
|
||||
}
|
||||
|
||||
@ -129,7 +147,7 @@ class BSONIterator implements Iterator
|
||||
throw new UnexpectedValueException(sprintf('Expected %d bytes; %d remaining', $documentLength, $this->bufferLength - $this->position));
|
||||
}
|
||||
|
||||
$this->current = \MongoDB\BSON\toPHP(substr($this->buffer, $this->position, $documentLength), $this->options['typeMap']);
|
||||
$this->current = toPHP(substr($this->buffer, $this->position, $documentLength), $this->options['typeMap']);
|
||||
$this->position += $documentLength;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,11 @@ use Countable;
|
||||
use Generator;
|
||||
use Iterator;
|
||||
use Traversable;
|
||||
use function count;
|
||||
use function current;
|
||||
use function key;
|
||||
use function next;
|
||||
use function reset;
|
||||
|
||||
/**
|
||||
* Iterator for wrapping a Traversable and caching its results.
|
||||
@ -33,14 +38,19 @@ use Traversable;
|
||||
*/
|
||||
class CachingIterator implements Countable, Iterator
|
||||
{
|
||||
/** @var array */
|
||||
private $items = [];
|
||||
|
||||
/** @var Generator */
|
||||
private $iterator;
|
||||
|
||||
/** @var boolean */
|
||||
private $iteratorAdvanced = false;
|
||||
|
||||
/** @var boolean */
|
||||
private $iteratorExhausted = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Initialize the iterator and stores the first item in the cache. This
|
||||
* effectively rewinds the Traversable and the wrapping Generator, which
|
||||
* will execute up to its first yield statement. Additionally, this mimics
|
||||
@ -90,7 +100,7 @@ class CachingIterator implements Countable, Iterator
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
if ( ! $this->iteratorExhausted) {
|
||||
if (! $this->iteratorExhausted) {
|
||||
$this->iterator->next();
|
||||
$this->storeCurrentItem();
|
||||
}
|
||||
@ -128,7 +138,7 @@ class CachingIterator implements Countable, Iterator
|
||||
*/
|
||||
private function exhaustIterator()
|
||||
{
|
||||
while ( ! $this->iteratorExhausted) {
|
||||
while (! $this->iteratorExhausted) {
|
||||
$this->next();
|
||||
}
|
||||
}
|
||||
|
292
cache/stores/mongodb/MongoDB/Model/ChangeStreamIterator.php
vendored
Normal file
292
cache/stores/mongodb/MongoDB/Model/ChangeStreamIterator.php
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2019 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use IteratorIterator;
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Monitoring\CommandFailedEvent;
|
||||
use MongoDB\Driver\Monitoring\CommandStartedEvent;
|
||||
use MongoDB\Driver\Monitoring\CommandSubscriber;
|
||||
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\ResumeTokenException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function MongoDB\Driver\Monitoring\addSubscriber;
|
||||
use function MongoDB\Driver\Monitoring\removeSubscriber;
|
||||
|
||||
/**
|
||||
* ChangeStreamIterator wraps a change stream's tailable cursor.
|
||||
*
|
||||
* This iterator tracks the size of each batch in order to determine when the
|
||||
* postBatchResumeToken is applicable. It also ensures that initial calls to
|
||||
* rewind() do not execute getMore commands.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ChangeStreamIterator extends IteratorIterator implements CommandSubscriber
|
||||
{
|
||||
/** @var integer */
|
||||
private $batchPosition = 0;
|
||||
|
||||
/** @var integer */
|
||||
private $batchSize;
|
||||
|
||||
/** @var boolean */
|
||||
private $isRewindNop;
|
||||
|
||||
/** @var boolean */
|
||||
private $isValid = false;
|
||||
|
||||
/** @var object|null */
|
||||
private $postBatchResumeToken;
|
||||
|
||||
/** @var array|object|null */
|
||||
private $resumeToken;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param Cursor $cursor
|
||||
* @param integer $firstBatchSize
|
||||
* @param array|object|null $initialResumeToken
|
||||
* @param object|null $postBatchResumeToken
|
||||
*/
|
||||
public function __construct(Cursor $cursor, $firstBatchSize, $initialResumeToken, $postBatchResumeToken)
|
||||
{
|
||||
if (! is_integer($firstBatchSize)) {
|
||||
throw InvalidArgumentException::invalidType('$firstBatchSize', $firstBatchSize, 'integer');
|
||||
}
|
||||
|
||||
if (isset($initialResumeToken) && ! is_array($initialResumeToken) && ! is_object($initialResumeToken)) {
|
||||
throw InvalidArgumentException::invalidType('$initialResumeToken', $initialResumeToken, 'array or object');
|
||||
}
|
||||
|
||||
if (isset($postBatchResumeToken) && ! is_object($postBatchResumeToken)) {
|
||||
throw InvalidArgumentException::invalidType('$postBatchResumeToken', $postBatchResumeToken, 'object');
|
||||
}
|
||||
|
||||
parent::__construct($cursor);
|
||||
|
||||
$this->batchSize = $firstBatchSize;
|
||||
$this->isRewindNop = ($firstBatchSize === 0);
|
||||
$this->postBatchResumeToken = $postBatchResumeToken;
|
||||
$this->resumeToken = $initialResumeToken;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
final public function commandFailed(CommandFailedEvent $event)
|
||||
{
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
final public function commandStarted(CommandStartedEvent $event)
|
||||
{
|
||||
if ($event->getCommandName() !== 'getMore') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->batchPosition = 0;
|
||||
$this->batchSize = null;
|
||||
$this->postBatchResumeToken = null;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
final public function commandSucceeded(CommandSucceededEvent $event)
|
||||
{
|
||||
if ($event->getCommandName() !== 'getMore') {
|
||||
return;
|
||||
}
|
||||
|
||||
$reply = $event->getReply();
|
||||
|
||||
if (! isset($reply->cursor->nextBatch) || ! is_array($reply->cursor->nextBatch)) {
|
||||
throw new UnexpectedValueException('getMore command did not return a "cursor.nextBatch" array');
|
||||
}
|
||||
|
||||
$this->batchSize = count($reply->cursor->nextBatch);
|
||||
|
||||
if (isset($reply->cursor->postBatchResumeToken) && is_object($reply->cursor->postBatchResumeToken)) {
|
||||
$this->postBatchResumeToken = $reply->cursor->postBatchResumeToken;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://php.net/iteratoriterator.current
|
||||
* @return mixed
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->isValid ? parent::current() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resume token for the iterator's current position.
|
||||
*
|
||||
* Null may be returned if no change documents have been iterated and the
|
||||
* server did not include a postBatchResumeToken in its aggregate or getMore
|
||||
* command response.
|
||||
*
|
||||
* @return array|object|null
|
||||
*/
|
||||
public function getResumeToken()
|
||||
{
|
||||
return $this->resumeToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://php.net/iteratoriterator.key
|
||||
* @return mixed
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->isValid ? parent::key() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://php.net/iteratoriterator.rewind
|
||||
* @return void
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
/* Determine if advancing the iterator will execute a getMore command
|
||||
* (i.e. we are already positioned at the end of the current batch). If
|
||||
* so, rely on the APM callbacks to reset $batchPosition and update
|
||||
* $batchSize. Otherwise, we can forgo APM and manually increment
|
||||
* $batchPosition after calling next(). */
|
||||
$getMore = $this->isAtEndOfBatch();
|
||||
|
||||
if ($getMore) {
|
||||
addSubscriber($this);
|
||||
}
|
||||
|
||||
try {
|
||||
parent::next();
|
||||
$this->onIteration(! $getMore);
|
||||
} finally {
|
||||
if ($getMore) {
|
||||
removeSubscriber($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://php.net/iteratoriterator.rewind
|
||||
* @return void
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->isRewindNop) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::rewind();
|
||||
$this->onIteration(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://php.net/iteratoriterator.valid
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the resume token (i.e. "_id" field) from a change document.
|
||||
*
|
||||
* @param array|object $document Change document
|
||||
* @return array|object
|
||||
* @throws InvalidArgumentException
|
||||
* @throws ResumeTokenException if the resume token is not found or invalid
|
||||
*/
|
||||
private function extractResumeToken($document)
|
||||
{
|
||||
if (! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
if ($document instanceof Serializable) {
|
||||
return $this->extractResumeToken($document->bsonSerialize());
|
||||
}
|
||||
|
||||
$resumeToken = is_array($document)
|
||||
? (isset($document['_id']) ? $document['_id'] : null)
|
||||
: (isset($document->_id) ? $document->_id : null);
|
||||
|
||||
if (! isset($resumeToken)) {
|
||||
$this->isValid = false;
|
||||
throw ResumeTokenException::notFound();
|
||||
}
|
||||
|
||||
if (! is_array($resumeToken) && ! is_object($resumeToken)) {
|
||||
$this->isValid = false;
|
||||
throw ResumeTokenException::invalidType($resumeToken);
|
||||
}
|
||||
|
||||
return $resumeToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the iterator is positioned at the end of the batch.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function isAtEndOfBatch()
|
||||
{
|
||||
return $this->batchPosition + 1 >= $this->batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform housekeeping after an iteration event.
|
||||
*
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#updating-the-cached-resume-token
|
||||
* @param boolean $incrementBatchPosition
|
||||
*/
|
||||
private function onIteration($incrementBatchPosition)
|
||||
{
|
||||
$this->isValid = parent::valid();
|
||||
|
||||
/* Disable rewind()'s NOP behavior once we advance to a valid position.
|
||||
* This will allow the driver to throw a LogicException if rewind() is
|
||||
* called after the cursor has advanced past its first element. */
|
||||
if ($this->isRewindNop && $this->isValid) {
|
||||
$this->isRewindNop = false;
|
||||
}
|
||||
|
||||
if ($incrementBatchPosition && $this->isValid) {
|
||||
$this->batchPosition++;
|
||||
}
|
||||
|
||||
/* If the iterator is positioned at the end of the batch, apply the
|
||||
* postBatchResumeToken if it's available. This handles both the case
|
||||
* where the current batch is empty (since onIteration() will be called
|
||||
* after a successful getMore) and when the iterator has advanced to the
|
||||
* last document in its current batch. Otherwise, extract a resume token
|
||||
* from the current document if possible. */
|
||||
if ($this->isAtEndOfBatch() && $this->postBatchResumeToken !== null) {
|
||||
$this->resumeToken = $this->postBatchResumeToken;
|
||||
} elseif ($this->isValid) {
|
||||
$this->resumeToken = $this->extractResumeToken($this->current());
|
||||
}
|
||||
}
|
||||
}
|
@ -17,8 +17,9 @@
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
use ArrayAccess;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* Collection information model class.
|
||||
@ -33,11 +34,10 @@ use ArrayAccess;
|
||||
*/
|
||||
class CollectionInfo implements ArrayAccess
|
||||
{
|
||||
/** @var array */
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $info Collection info
|
||||
*/
|
||||
public function __construct(array $info)
|
||||
@ -63,6 +63,7 @@ class CollectionInfo implements ArrayAccess
|
||||
*/
|
||||
public function getCappedMax()
|
||||
{
|
||||
/* The MongoDB server might return this number as an integer or float */
|
||||
return isset($this->info['options']['max']) ? (integer) $this->info['options']['max'] : null;
|
||||
}
|
||||
|
||||
@ -73,6 +74,7 @@ class CollectionInfo implements ArrayAccess
|
||||
*/
|
||||
public function getCappedSize()
|
||||
{
|
||||
/* The MongoDB server might return this number as an integer or float */
|
||||
return isset($this->info['options']['size']) ? (integer) $this->info['options']['size'] : null;
|
||||
}
|
||||
|
||||
@ -134,21 +136,24 @@ class CollectionInfo implements ArrayAccess
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetset
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
throw BadMethodCallException::classIsImmutable(self::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetunset
|
||||
* @param mixed $key
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
throw BadMethodCallException::classIsImmutable(self::class);
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,10 @@
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
use ArrayAccess;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* Database information model class.
|
||||
*
|
||||
@ -31,11 +33,10 @@ use ArrayAccess;
|
||||
*/
|
||||
class DatabaseInfo implements ArrayAccess
|
||||
{
|
||||
/** @var array */
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $info Database info
|
||||
*/
|
||||
public function __construct(array $info)
|
||||
@ -71,6 +72,7 @@ class DatabaseInfo implements ArrayAccess
|
||||
*/
|
||||
public function getSizeOnDisk()
|
||||
{
|
||||
/* The MongoDB server might return this number as an integer or float */
|
||||
return (integer) $this->info['sizeOnDisk'];
|
||||
}
|
||||
|
||||
@ -112,21 +114,24 @@ class DatabaseInfo implements ArrayAccess
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetset
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
throw BadMethodCallException::classIsImmutable(self::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetunset
|
||||
* @param mixed $key
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
throw BadMethodCallException::classIsImmutable(self::class);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,11 @@
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use function current;
|
||||
use function key;
|
||||
use function next;
|
||||
use function reset;
|
||||
|
||||
/**
|
||||
* DatabaseInfoIterator for inline listDatabases command results.
|
||||
*
|
||||
@ -29,11 +34,10 @@ namespace MongoDB\Model;
|
||||
*/
|
||||
class DatabaseInfoLegacyIterator implements DatabaseInfoIterator
|
||||
{
|
||||
/** @var array */
|
||||
private $databases;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $databases
|
||||
*/
|
||||
public function __construct(array $databases)
|
||||
|
14
cache/stores/mongodb/MongoDB/Model/IndexInfo.php
vendored
14
cache/stores/mongodb/MongoDB/Model/IndexInfo.php
vendored
@ -17,8 +17,10 @@
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
use ArrayAccess;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
use function array_key_exists;
|
||||
use function array_search;
|
||||
|
||||
/**
|
||||
* Index information model class.
|
||||
@ -37,11 +39,10 @@ use ArrayAccess;
|
||||
*/
|
||||
class IndexInfo implements ArrayAccess
|
||||
{
|
||||
/** @var array */
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $info Index info
|
||||
*/
|
||||
public function __construct(array $info)
|
||||
@ -206,21 +207,24 @@ class IndexInfo implements ArrayAccess
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetset
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
throw BadMethodCallException::classIsImmutable(self::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetunset
|
||||
* @param mixed $key
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
throw BadMethodCallException::classIsImmutable(self::class);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,13 @@ namespace MongoDB\Model;
|
||||
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use function is_array;
|
||||
use function is_float;
|
||||
use function is_int;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\generate_index_name;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Index input model class.
|
||||
@ -32,43 +39,42 @@ use MongoDB\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class IndexInput implements Serializable
|
||||
{
|
||||
/** @var array */
|
||||
private $index;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $index Index specification
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(array $index)
|
||||
{
|
||||
if ( ! isset($index['key'])) {
|
||||
if (! isset($index['key'])) {
|
||||
throw new InvalidArgumentException('Required "key" document is missing from index specification');
|
||||
}
|
||||
|
||||
if ( ! is_array($index['key']) && ! is_object($index['key'])) {
|
||||
if (! is_array($index['key']) && ! is_object($index['key'])) {
|
||||
throw InvalidArgumentException::invalidType('"key" option', $index['key'], 'array or object');
|
||||
}
|
||||
|
||||
foreach ($index['key'] as $fieldName => $order) {
|
||||
if ( ! is_int($order) && ! is_float($order) && ! is_string($order)) {
|
||||
if (! is_int($order) && ! is_float($order) && ! is_string($order)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('order value for "%s" field within "key" option', $fieldName), $order, 'numeric or string');
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset($index['ns'])) {
|
||||
if (! isset($index['ns'])) {
|
||||
throw new InvalidArgumentException('Required "ns" option is missing from index specification');
|
||||
}
|
||||
|
||||
if ( ! is_string($index['ns'])) {
|
||||
if (! is_string($index['ns'])) {
|
||||
throw InvalidArgumentException::invalidType('"ns" option', $index['ns'], 'string');
|
||||
}
|
||||
|
||||
if ( ! isset($index['name'])) {
|
||||
$index['name'] = \MongoDB\generate_index_name($index['key']);
|
||||
if (! isset($index['name'])) {
|
||||
$index['name'] = generate_index_name($index['key']);
|
||||
}
|
||||
|
||||
if ( ! is_string($index['name'])) {
|
||||
if (! is_string($index['name'])) {
|
||||
throw InvalidArgumentException::invalidType('"name" option', $index['name'], 'string');
|
||||
}
|
||||
|
||||
@ -78,7 +84,7 @@ class IndexInput implements Serializable
|
||||
/**
|
||||
* Return the index name.
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
|
@ -1,166 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2016-2017 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace MongoDB\Model;
|
||||
|
||||
use ArrayIterator;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Iterator for applying a type map to documents in inline command results.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.append
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function append($value)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.asort
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function asort()
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.ksort
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function ksort()
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.natcasesort
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function natcasesort()
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.natsort
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function natsort()
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value from the provided offset with the type map applied.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.offsetget
|
||||
* @param mixed $offset
|
||||
* @return array|object
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return \MongoDB\apply_type_map_to_document(parent::offsetGet($offset), $this->typeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.offsetset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetSet($index, $newval)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.offsetunset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($index)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.uasort
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function uasort($cmp_function)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayiterator.uksort
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function uksort($cmp_function)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
}
|
115
cache/stores/mongodb/MongoDB/Operation/Aggregate.php
vendored
115
cache/stores/mongodb/MongoDB/Operation/Aggregate.php
vendored
@ -17,20 +17,29 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use ArrayIterator;
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\TypeMapArrayIterator;
|
||||
use ArrayIterator;
|
||||
use stdClass;
|
||||
use Traversable;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\create_field_path_type_map;
|
||||
use function MongoDB\is_last_pipeline_operator_write;
|
||||
use function MongoDB\server_supports_feature;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Operation for the aggregate command.
|
||||
@ -41,14 +50,28 @@ use Traversable;
|
||||
*/
|
||||
class Aggregate implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string|null */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $pipeline;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -63,8 +86,8 @@ class Aggregate implements Executable
|
||||
* * batchSize (integer): The number of documents to return per batch.
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation. This only applies when the $out
|
||||
* stage is specified.
|
||||
* circumvent document level validation. This only applies when an $out
|
||||
* or $merge stage is specified.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
@ -87,15 +110,14 @@ class Aggregate implements Executable
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * readConcern (MongoDB\Driver\ReadConcern): Read concern. Note that a
|
||||
* "majority" read concern is not compatible with the $out stage.
|
||||
* * readConcern (MongoDB\Driver\ReadConcern): Read concern.
|
||||
*
|
||||
* This is not supported for server versions < 3.2 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
|
||||
*
|
||||
* This option is ignored if the $out stage is specified.
|
||||
* This option is ignored if an $out or $merge stage is specified.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
@ -111,7 +133,7 @@ class Aggregate implements Executable
|
||||
* mongod/mongos upgrades.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern. This only
|
||||
* applies when the $out stage is specified.
|
||||
* applies when an $out or $merge stage is specified.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
@ -134,7 +156,7 @@ class Aggregate implements Executable
|
||||
throw new InvalidArgumentException(sprintf('$pipeline is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($operation) && ! is_object($operation)) {
|
||||
if (! is_array($operation) && ! is_object($operation)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$pipeline[%d]', $i), $operation, 'array or object');
|
||||
}
|
||||
|
||||
@ -146,7 +168,7 @@ class Aggregate implements Executable
|
||||
'useCursor' => true,
|
||||
];
|
||||
|
||||
if ( ! is_bool($options['allowDiskUse'])) {
|
||||
if (! is_bool($options['allowDiskUse'])) {
|
||||
throw InvalidArgumentException::invalidType('"allowDiskUse" option', $options['allowDiskUse'], 'boolean');
|
||||
}
|
||||
|
||||
@ -183,27 +205,27 @@ class Aggregate implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['useCursor'])) {
|
||||
if (! is_bool($options['useCursor'])) {
|
||||
throw InvalidArgumentException::invalidType('"useCursor" option', $options['useCursor'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['batchSize']) && ! $options['useCursor']) {
|
||||
@ -218,7 +240,7 @@ class Aggregate implements Executable
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
if ( ! empty($options['explain'])) {
|
||||
if (! empty($options['explain'])) {
|
||||
$options['useCursor'] = false;
|
||||
}
|
||||
|
||||
@ -240,25 +262,35 @@ class Aggregate implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
throw UnsupportedException::readConcernNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction) {
|
||||
if (isset($this->options['readConcern'])) {
|
||||
throw UnsupportedException::readConcernNotSupportedInTransaction();
|
||||
}
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
$hasExplain = ! empty($this->options['explain']);
|
||||
$hasOutStage = \MongoDB\is_last_pipeline_operator_out($this->pipeline);
|
||||
$hasWriteStage = is_last_pipeline_operator_write($this->pipeline);
|
||||
|
||||
$command = $this->createCommand($server);
|
||||
$options = $this->createOptions($hasOutStage, $hasExplain);
|
||||
$command = $this->createCommand($server, $hasWriteStage);
|
||||
$options = $this->createOptions($hasWriteStage, $hasExplain);
|
||||
|
||||
$cursor = ($hasOutStage && ! $hasExplain)
|
||||
$cursor = $hasWriteStage && ! $hasExplain
|
||||
? $server->executeReadWriteCommand($this->databaseName, $command, $options)
|
||||
: $server->executeReadCommand($this->databaseName, $command, $options);
|
||||
|
||||
@ -270,14 +302,14 @@ class Aggregate implements Executable
|
||||
return $cursor;
|
||||
}
|
||||
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
if ( ! isset($result->result) || ! is_array($result->result)) {
|
||||
throw new UnexpectedValueException('aggregate command did not return a "result" array');
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap(create_field_path_type_map($this->options['typeMap'], 'result.$'));
|
||||
}
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
return new TypeMapArrayIterator($result->result, $this->options['typeMap']);
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
if (! isset($result->result) || ! is_array($result->result)) {
|
||||
throw new UnexpectedValueException('aggregate command did not return a "result" array');
|
||||
}
|
||||
|
||||
return new ArrayIterator($result->result);
|
||||
@ -287,9 +319,10 @@ class Aggregate implements Executable
|
||||
* Create the aggregate command.
|
||||
*
|
||||
* @param Server $server
|
||||
* @param boolean $hasWriteStage
|
||||
* @return Command
|
||||
*/
|
||||
private function createCommand(Server $server)
|
||||
private function createCommand(Server $server, $hasWriteStage)
|
||||
{
|
||||
$cmd = [
|
||||
'aggregate' => isset($this->collectionName) ? $this->collectionName : 1,
|
||||
@ -299,7 +332,9 @@ class Aggregate implements Executable
|
||||
|
||||
$cmd['allowDiskUse'] = $this->options['allowDiskUse'];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
@ -322,9 +357,12 @@ class Aggregate implements Executable
|
||||
}
|
||||
|
||||
if ($this->options['useCursor']) {
|
||||
$cmd['cursor'] = isset($this->options["batchSize"])
|
||||
/* Ignore batchSize if pipeline includes an $out or $merge stage, as
|
||||
* no documents will be returned and sending a batchSize of zero
|
||||
* could prevent the pipeline from executing at all. */
|
||||
$cmd['cursor'] = isset($this->options["batchSize"]) && ! $hasWriteStage
|
||||
? ['batchSize' => $this->options["batchSize"]]
|
||||
: new stdClass;
|
||||
: new stdClass();
|
||||
}
|
||||
|
||||
return new Command($cmd, $cmdOptions);
|
||||
@ -335,10 +373,11 @@ class Aggregate implements Executable
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php
|
||||
* @param boolean $hasOutStage
|
||||
* @param boolean $hasWriteStage
|
||||
* @param boolean $hasExplain
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions($hasOutStage, $hasExplain)
|
||||
private function createOptions($hasWriteStage, $hasExplain)
|
||||
{
|
||||
$options = [];
|
||||
|
||||
@ -346,7 +385,7 @@ class Aggregate implements Executable
|
||||
$options['readConcern'] = $this->options['readConcern'];
|
||||
}
|
||||
|
||||
if ( ! $hasOutStage && isset($this->options['readPreference'])) {
|
||||
if (! $hasWriteStage && isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
@ -354,7 +393,7 @@ class Aggregate implements Executable
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if ($hasOutStage && ! $hasExplain && isset($this->options['writeConcern'])) {
|
||||
if ($hasWriteStage && ! $hasExplain && isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,23 @@ namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\BulkWriteResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_object;
|
||||
use function key;
|
||||
use function MongoDB\is_first_key_operator;
|
||||
use function MongoDB\is_pipeline;
|
||||
use function MongoDB\server_supports_feature;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Operation for executing multiple write operations.
|
||||
@ -41,15 +52,31 @@ class BulkWrite implements Executable
|
||||
const UPDATE_MANY = 'updateMany';
|
||||
const UPDATE_ONE = 'updateOne';
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForArrayFilters = 6;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array[] */
|
||||
private $operations;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/** @var boolean */
|
||||
private $isArrayFiltersUsed = false;
|
||||
|
||||
/** @var boolean */
|
||||
private $isCollationUsed = false;
|
||||
|
||||
/**
|
||||
@ -132,7 +159,7 @@ class BulkWrite implements Executable
|
||||
throw new InvalidArgumentException(sprintf('$operations is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($operation)) {
|
||||
if (! is_array($operation)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]', $i), $operation, 'array');
|
||||
}
|
||||
|
||||
@ -143,11 +170,11 @@ class BulkWrite implements Executable
|
||||
$type = key($operation);
|
||||
$args = current($operation);
|
||||
|
||||
if ( ! isset($args[0]) && ! array_key_exists(0, $args)) {
|
||||
if (! isset($args[0]) && ! array_key_exists(0, $args)) {
|
||||
throw new InvalidArgumentException(sprintf('Missing first argument for $operations[%d]["%s"]', $i, $type));
|
||||
}
|
||||
|
||||
if ( ! is_array($args[0]) && ! is_object($args[0])) {
|
||||
if (! is_array($args[0]) && ! is_object($args[0])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][0]', $i, $type), $args[0], 'array or object');
|
||||
}
|
||||
|
||||
@ -157,11 +184,11 @@ class BulkWrite implements Executable
|
||||
|
||||
case self::DELETE_MANY:
|
||||
case self::DELETE_ONE:
|
||||
if ( ! isset($args[1])) {
|
||||
if (! isset($args[1])) {
|
||||
$args[1] = [];
|
||||
}
|
||||
|
||||
if ( ! is_array($args[1])) {
|
||||
if (! is_array($args[1])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array');
|
||||
}
|
||||
|
||||
@ -170,7 +197,7 @@ class BulkWrite implements Executable
|
||||
if (isset($args[1]['collation'])) {
|
||||
$this->isCollationUsed = true;
|
||||
|
||||
if ( ! is_array($args[1]['collation']) && ! is_object($args[1]['collation'])) {
|
||||
if (! is_array($args[1]['collation']) && ! is_object($args[1]['collation'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]["collation"]', $i, $type), $args[1]['collation'], 'array or object');
|
||||
}
|
||||
}
|
||||
@ -180,23 +207,23 @@ class BulkWrite implements Executable
|
||||
break;
|
||||
|
||||
case self::REPLACE_ONE:
|
||||
if ( ! isset($args[1]) && ! array_key_exists(1, $args)) {
|
||||
if (! isset($args[1]) && ! array_key_exists(1, $args)) {
|
||||
throw new InvalidArgumentException(sprintf('Missing second argument for $operations[%d]["%s"]', $i, $type));
|
||||
}
|
||||
|
||||
if ( ! is_array($args[1]) && ! is_object($args[1])) {
|
||||
if (! is_array($args[1]) && ! is_object($args[1])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array or object');
|
||||
}
|
||||
|
||||
if (\MongoDB\is_first_key_operator($args[1])) {
|
||||
if (is_first_key_operator($args[1])) {
|
||||
throw new InvalidArgumentException(sprintf('First key in $operations[%d]["%s"][1] is an update operator', $i, $type));
|
||||
}
|
||||
|
||||
if ( ! isset($args[2])) {
|
||||
if (! isset($args[2])) {
|
||||
$args[2] = [];
|
||||
}
|
||||
|
||||
if ( ! is_array($args[2])) {
|
||||
if (! is_array($args[2])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]', $i, $type), $args[2], 'array');
|
||||
}
|
||||
|
||||
@ -206,12 +233,12 @@ class BulkWrite implements Executable
|
||||
if (isset($args[2]['collation'])) {
|
||||
$this->isCollationUsed = true;
|
||||
|
||||
if ( ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) {
|
||||
if (! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object');
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! is_bool($args[2]['upsert'])) {
|
||||
if (! is_bool($args[2]['upsert'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["upsert"]', $i, $type), $args[2]['upsert'], 'boolean');
|
||||
}
|
||||
|
||||
@ -221,23 +248,23 @@ class BulkWrite implements Executable
|
||||
|
||||
case self::UPDATE_MANY:
|
||||
case self::UPDATE_ONE:
|
||||
if ( ! isset($args[1]) && ! array_key_exists(1, $args)) {
|
||||
if (! isset($args[1]) && ! array_key_exists(1, $args)) {
|
||||
throw new InvalidArgumentException(sprintf('Missing second argument for $operations[%d]["%s"]', $i, $type));
|
||||
}
|
||||
|
||||
if ( ! is_array($args[1]) && ! is_object($args[1])) {
|
||||
if (! is_array($args[1]) && ! is_object($args[1])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! \MongoDB\is_first_key_operator($args[1])) {
|
||||
throw new InvalidArgumentException(sprintf('First key in $operations[%d]["%s"][1] is not an update operator', $i, $type));
|
||||
if (! is_first_key_operator($args[1]) && ! is_pipeline($args[1])) {
|
||||
throw new InvalidArgumentException(sprintf('First key in $operations[%d]["%s"][1] is neither an update operator nor a pipeline', $i, $type));
|
||||
}
|
||||
|
||||
if ( ! isset($args[2])) {
|
||||
if (! isset($args[2])) {
|
||||
$args[2] = [];
|
||||
}
|
||||
|
||||
if ( ! is_array($args[2])) {
|
||||
if (! is_array($args[2])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]', $i, $type), $args[2], 'array');
|
||||
}
|
||||
|
||||
@ -247,7 +274,7 @@ class BulkWrite implements Executable
|
||||
if (isset($args[2]['arrayFilters'])) {
|
||||
$this->isArrayFiltersUsed = true;
|
||||
|
||||
if ( ! is_array($args[2]['arrayFilters'])) {
|
||||
if (! is_array($args[2]['arrayFilters'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["arrayFilters"]', $i, $type), $args[2]['arrayFilters'], 'array');
|
||||
}
|
||||
}
|
||||
@ -255,12 +282,12 @@ class BulkWrite implements Executable
|
||||
if (isset($args[2]['collation'])) {
|
||||
$this->isCollationUsed = true;
|
||||
|
||||
if ( ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) {
|
||||
if (! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object');
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! is_bool($args[2]['upsert'])) {
|
||||
if (! is_bool($args[2]['upsert'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["upsert"]', $i, $type), $args[2]['upsert'], 'boolean');
|
||||
}
|
||||
|
||||
@ -281,16 +308,16 @@ class BulkWrite implements Executable
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['ordered'])) {
|
||||
if (! is_bool($options['ordered'])) {
|
||||
throw InvalidArgumentException::invalidType('"ordered" option', $options['ordered'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -314,17 +341,24 @@ class BulkWrite implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if ($this->isArrayFiltersUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
if ($this->isArrayFiltersUsed && ! server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
throw UnsupportedException::arrayFiltersNotSupported();
|
||||
}
|
||||
|
||||
if ($this->isCollationUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if ($this->isCollationUsed && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$options = ['ordered' => $this->options['ordered']];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
|
40
cache/stores/mongodb/MongoDB/Operation/Count.php
vendored
40
cache/stores/mongodb/MongoDB/Operation/Count.php
vendored
@ -18,14 +18,21 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_float;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the count command.
|
||||
@ -36,12 +43,22 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class Count implements Executable, Explainable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array|object */
|
||||
private $filter;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -85,7 +102,7 @@ class Count implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter = [], array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
@ -106,15 +123,15 @@ class Count implements Executable, Explainable
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['skip']) && ! is_integer($options['skip'])) {
|
||||
@ -143,19 +160,24 @@ class Count implements Executable, Explainable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
throw UnsupportedException::readConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['readConcern'])) {
|
||||
throw UnsupportedException::readConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$cursor = $server->executeReadCommand($this->databaseName, new Command($this->createCommandDocument()), $this->createOptions());
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
// Older server versions may return a float
|
||||
if ( ! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) {
|
||||
if (! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) {
|
||||
throw new UnexpectedValueException('count command did not return a numeric "n" value');
|
||||
}
|
||||
|
||||
@ -176,7 +198,7 @@ class Count implements Executable, Explainable
|
||||
{
|
||||
$cmd = ['count' => $this->collectionName];
|
||||
|
||||
if ( ! empty($this->filter)) {
|
||||
if (! empty($this->filter)) {
|
||||
$cmd['query'] = (object) $this->filter;
|
||||
}
|
||||
|
||||
|
@ -17,15 +17,18 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function array_intersect_key;
|
||||
use function count;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_float;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
|
||||
/**
|
||||
* Operation for obtaining an exact count of documents in a collection
|
||||
@ -36,13 +39,23 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class CountDocuments implements Executable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array|object */
|
||||
private $filter;
|
||||
private $options;
|
||||
|
||||
/** @var array */
|
||||
private $aggregateOptions;
|
||||
|
||||
/** @var array */
|
||||
private $countOptions;
|
||||
|
||||
/** @var Aggregate */
|
||||
private $aggregate;
|
||||
|
||||
/**
|
||||
* Constructs an aggregate command for counting documents
|
||||
@ -85,50 +98,26 @@ class CountDocuments implements Executable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) {
|
||||
throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) {
|
||||
throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], 'string or array or object');
|
||||
}
|
||||
|
||||
if (isset($options['limit']) && ! is_integer($options['limit'])) {
|
||||
throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['skip']) && ! is_integer($options['skip'])) {
|
||||
throw InvalidArgumentException::invalidType('"skip" option', $options['skip'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && $options['readConcern']->isDefault()) {
|
||||
unset($options['readConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->filter = $filter;
|
||||
$this->options = $options;
|
||||
|
||||
$this->aggregateOptions = array_intersect_key($options, ['collation' => 1, 'hint' => 1, 'maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]);
|
||||
$this->countOptions = array_intersect_key($options, ['limit' => 1, 'skip' => 1]);
|
||||
|
||||
$this->aggregate = $this->createAggregate();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,15 +132,7 @@ class CountDocuments implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
throw UnsupportedException::readConcernNotSupported();
|
||||
}
|
||||
|
||||
$cursor = $server->executeReadCommand($this->databaseName, new Command($this->createCommandDocument()), $this->createOptions());
|
||||
$cursor = $this->aggregate->execute($server);
|
||||
$allResults = $cursor->toArray();
|
||||
|
||||
/* If there are no documents to count, the aggregation pipeline has no items to group, and
|
||||
@ -161,7 +142,7 @@ class CountDocuments implements Executable
|
||||
}
|
||||
|
||||
$result = current($allResults);
|
||||
if ( ! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) {
|
||||
if (! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) {
|
||||
throw new UnexpectedValueException('count command did not return a numeric "n" value');
|
||||
}
|
||||
|
||||
@ -169,69 +150,24 @@ class CountDocuments implements Executable
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the count command document.
|
||||
*
|
||||
* @return array
|
||||
* @return Aggregate
|
||||
*/
|
||||
private function createCommandDocument()
|
||||
private function createAggregate()
|
||||
{
|
||||
$pipeline = [
|
||||
['$match' => (object) $this->filter]
|
||||
['$match' => (object) $this->filter],
|
||||
];
|
||||
|
||||
if (isset($this->options['skip'])) {
|
||||
$pipeline[] = ['$skip' => $this->options['skip']];
|
||||
if (isset($this->countOptions['skip'])) {
|
||||
$pipeline[] = ['$skip' => $this->countOptions['skip']];
|
||||
}
|
||||
|
||||
if (isset($this->options['limit'])) {
|
||||
$pipeline[] = ['$limit' => $this->options['limit']];
|
||||
if (isset($this->countOptions['limit'])) {
|
||||
$pipeline[] = ['$limit' => $this->countOptions['limit']];
|
||||
}
|
||||
|
||||
$pipeline[] = ['$group' => ['_id' => null, 'n' => ['$sum' => 1]]];
|
||||
$pipeline[] = ['$group' => ['_id' => 1, 'n' => ['$sum' => 1]]];
|
||||
|
||||
$cmd = [
|
||||
'aggregate' => $this->collectionName,
|
||||
'pipeline' => $pipeline,
|
||||
'cursor' => (object) [],
|
||||
];
|
||||
|
||||
if (isset($this->options['collation'])) {
|
||||
$cmd['collation'] = (object) $this->options['collation'];
|
||||
}
|
||||
|
||||
if (isset($this->options['hint'])) {
|
||||
$cmd['hint'] = is_array($this->options['hint']) ? (object) $this->options['hint'] : $this->options['hint'];
|
||||
}
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['readConcern'])) {
|
||||
$options['readConcern'] = $this->options['readConcern'];
|
||||
}
|
||||
|
||||
if (isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
return new Aggregate($this->databaseName, $this->collectionName, $pipeline, $this->aggregateOptions);
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,21 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\server_supports_feature;
|
||||
use function trigger_error;
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Operation for the create command.
|
||||
@ -37,11 +46,19 @@ class CreateCollection implements Executable
|
||||
const USE_POWER_OF_2_SIZES = 1;
|
||||
const NO_PADDING = 2;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $options = [];
|
||||
|
||||
/**
|
||||
@ -139,7 +156,7 @@ class CreateCollection implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['size']) && ! is_integer($options['size'])) {
|
||||
@ -167,7 +184,7 @@ class CreateCollection implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -194,11 +211,11 @@ class CreateCollection implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
|
@ -17,15 +17,19 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\IndexInput;
|
||||
use function array_map;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function MongoDB\server_supports_feature;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Operation for the createIndexes command.
|
||||
@ -37,13 +41,25 @@ use MongoDB\Model\IndexInput;
|
||||
*/
|
||||
class CreateIndexes implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $indexes = [];
|
||||
|
||||
/** @var boolean */
|
||||
private $isCollationUsed = false;
|
||||
|
||||
/** @var array */
|
||||
private $options = [];
|
||||
|
||||
/**
|
||||
@ -82,11 +98,11 @@ class CreateIndexes implements Executable
|
||||
throw new InvalidArgumentException(sprintf('$indexes is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($index)) {
|
||||
if (! is_array($index)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$index[%d]', $i), $index, 'array');
|
||||
}
|
||||
|
||||
if ( ! isset($index['ns'])) {
|
||||
if (! isset($index['ns'])) {
|
||||
$index['ns'] = $databaseName . '.' . $collectionName;
|
||||
}
|
||||
|
||||
@ -99,16 +115,16 @@ class CreateIndexes implements Executable
|
||||
$expectedIndex += 1;
|
||||
}
|
||||
|
||||
if (isset($options['maxTimeMS']) && !is_integer($options['maxTimeMS'])) {
|
||||
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -131,17 +147,24 @@ class CreateIndexes implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if ($this->isCollationUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if ($this->isCollationUsed && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$this->executeCommand($server);
|
||||
|
||||
return array_map(function(IndexInput $index) { return (string) $index; }, $this->indexes);
|
||||
return array_map(function (IndexInput $index) {
|
||||
return (string) $index;
|
||||
}, $this->indexes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,8 @@ use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
|
||||
/**
|
||||
* Operation for executing a database command.
|
||||
@ -32,8 +34,13 @@ use MongoDB\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class DatabaseCommand implements Executable
|
||||
{
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var array|Command|object */
|
||||
private $command;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -54,23 +61,23 @@ class DatabaseCommand implements Executable
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be
|
||||
* applied to the returned Cursor (it is not sent to the server).
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param array|object $command Command document
|
||||
* @param array $options Options for command execution
|
||||
* @param string $databaseName Database name
|
||||
* @param array|object $command Command document
|
||||
* @param array $options Options for command execution
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $command, array $options = [])
|
||||
{
|
||||
if ( ! is_array($command) && ! is_object($command)) {
|
||||
if (! is_array($command) && ! is_object($command)) {
|
||||
throw InvalidArgumentException::invalidType('$command', $command, 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -78,7 +85,7 @@ class DatabaseCommand implements Executable
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->command = ($command instanceof Command) ? $command : new Command($command);
|
||||
$this->command = $command instanceof Command ? $command : new Command($command);
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,15 @@ namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\DeleteResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the delete command.
|
||||
@ -37,12 +40,22 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class Delete implements Executable, Explainable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array|object */
|
||||
private $filter;
|
||||
|
||||
/** @var integer */
|
||||
private $limit;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -72,7 +85,7 @@ class Delete implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $limit, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
@ -85,11 +98,11 @@ class Delete implements Executable, Explainable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -113,10 +126,15 @@ class Delete implements Executable, Explainable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$bulk = new Bulk();
|
||||
$bulk->delete($this->filter, $this->createDeleteOptions());
|
||||
|
||||
|
@ -18,8 +18,8 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\DeleteResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
@ -32,6 +32,7 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class DeleteMany implements Executable, Explainable
|
||||
{
|
||||
/** @var Delete */
|
||||
private $delete;
|
||||
|
||||
/**
|
||||
|
@ -18,8 +18,8 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\DeleteResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
@ -32,6 +32,7 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class DeleteOne implements Executable, Explainable
|
||||
{
|
||||
/** @var Delete */
|
||||
private $delete;
|
||||
|
||||
/**
|
||||
|
@ -18,14 +18,20 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function MongoDB\create_field_path_type_map;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the distinct command.
|
||||
@ -36,13 +42,25 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class Distinct implements Executable, Explainable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var string */
|
||||
private $fieldName;
|
||||
|
||||
/** @var array|object */
|
||||
private $filter;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -69,6 +87,8 @@ class Distinct implements Executable, Explainable
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param string $fieldName Field for which to return distinct values
|
||||
@ -78,7 +98,7 @@ class Distinct implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $fieldName, $filter = [], array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
@ -91,15 +111,19 @@ class Distinct implements Executable, Explainable
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && $options['readConcern']->isDefault()) {
|
||||
@ -125,18 +149,28 @@ class Distinct implements Executable, Explainable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
throw UnsupportedException::readConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['readConcern'])) {
|
||||
throw UnsupportedException::readConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$cursor = $server->executeReadCommand($this->databaseName, new Command($this->createCommandDocument()), $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap(create_field_path_type_map($this->options['typeMap'], 'values.$'));
|
||||
}
|
||||
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
if ( ! isset($result->values) || ! is_array($result->values)) {
|
||||
if (! isset($result->values) || ! is_array($result->values)) {
|
||||
throw new UnexpectedValueException('distinct command did not return a "values" array');
|
||||
}
|
||||
|
||||
@ -160,7 +194,7 @@ class Distinct implements Executable, Explainable
|
||||
'key' => $this->fieldName,
|
||||
];
|
||||
|
||||
if ( ! empty($this->filter)) {
|
||||
if (! empty($this->filter)) {
|
||||
$cmd['query'] = (object) $this->filter;
|
||||
}
|
||||
|
||||
|
@ -18,12 +18,15 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the drop command.
|
||||
@ -35,11 +38,19 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class DropCollection implements Executable
|
||||
{
|
||||
/** @var string */
|
||||
private static $errorMessageNamespaceNotFound = 'ns not found';
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -67,7 +78,7 @@ class DropCollection implements Executable
|
||||
public function __construct($databaseName, $collectionName, array $options = [])
|
||||
{
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -75,7 +86,7 @@ class DropCollection implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -98,10 +109,15 @@ class DropCollection implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$command = new Command(['drop' => $this->collectionName]);
|
||||
|
||||
try {
|
||||
|
@ -18,12 +18,15 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the dropDatabase command.
|
||||
@ -35,9 +38,13 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class DropDatabase implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -64,7 +71,7 @@ class DropDatabase implements Executable
|
||||
public function __construct($databaseName, array $options = [])
|
||||
{
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -72,7 +79,7 @@ class DropDatabase implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -94,7 +101,7 @@ class DropDatabase implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
|
@ -18,12 +18,16 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the dropIndexes command.
|
||||
@ -34,11 +38,19 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class DropIndexes implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var string */
|
||||
private $indexName;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -80,7 +92,7 @@ class DropIndexes implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -88,7 +100,7 @@ class DropIndexes implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -112,10 +124,15 @@ class DropIndexes implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
|
@ -17,15 +17,12 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function array_intersect_key;
|
||||
|
||||
/**
|
||||
* Operation for obtaining an estimated count of documents in a collection
|
||||
@ -36,13 +33,18 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class EstimatedDocumentCount implements Executable, Explainable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/** @var Count */
|
||||
private $count;
|
||||
|
||||
/**
|
||||
* Constructs a count command.
|
||||
*
|
||||
@ -62,36 +64,18 @@ class EstimatedDocumentCount implements Executable, Explainable
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array $options Command options
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $options = [])
|
||||
{
|
||||
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && $options['readConcern']->isDefault()) {
|
||||
unset($options['readConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->options = $options;
|
||||
$this->options = array_intersect_key($options, ['maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]);
|
||||
|
||||
$this->count = $this->createCount();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,68 +90,19 @@ class EstimatedDocumentCount implements Executable, Explainable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
throw UnsupportedException::readConcernNotSupported();
|
||||
}
|
||||
|
||||
$cursor = $server->executeReadCommand($this->databaseName, new Command($this->createCommandDocument()), $this->createOptions());
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
// Older server versions may return a float
|
||||
if ( ! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) {
|
||||
throw new UnexpectedValueException('count command did not return a numeric "n" value');
|
||||
}
|
||||
|
||||
return (integer) $result->n;
|
||||
return $this->count->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->createCommandDocument();
|
||||
return $this->count->getCommandDocument($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the count command document.
|
||||
*
|
||||
* @return array
|
||||
* @return Count
|
||||
*/
|
||||
private function createCommandDocument()
|
||||
private function createCount()
|
||||
{
|
||||
$cmd = ['count' => $this->collectionName];
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['readConcern'])) {
|
||||
$options['readConcern'] = $this->options['readConcern'];
|
||||
}
|
||||
|
||||
if (isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
return new Count($this->databaseName, $this->collectionName, [], $this->options);
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,12 @@ use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the explain command.
|
||||
@ -38,11 +41,19 @@ class Explain implements Executable
|
||||
const VERBOSITY_EXEC_STATS = 'executionStats';
|
||||
const VERBOSITY_QUERY = 'queryPlanner';
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForDistinct = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForFindAndModify = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var Explainable */
|
||||
private $explainable;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -59,19 +70,19 @@ class Explain implements Executable
|
||||
*
|
||||
* * verbosity (string): The mode in which the explain command will be run.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $databaseName Database name
|
||||
* @param Explainable $explainable Operation to explain
|
||||
* @param array $options Command options
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, Explainable $explainable, array $options = [])
|
||||
{
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -89,11 +100,11 @@ class Explain implements Executable
|
||||
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if ($this->explainable instanceof Distinct && ! \MongoDB\server_supports_feature($server, self::$wireVersionForDistinct)) {
|
||||
if ($this->explainable instanceof Distinct && ! server_supports_feature($server, self::$wireVersionForDistinct)) {
|
||||
throw UnsupportedException::explainNotSupported();
|
||||
}
|
||||
|
||||
if ($this->isFindAndModify($this->explainable) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModify)) {
|
||||
if ($this->isFindAndModify($this->explainable) && ! server_supports_feature($server, self::$wireVersionForFindAndModify)) {
|
||||
throw UnsupportedException::explainNotSupported();
|
||||
}
|
||||
|
||||
@ -138,6 +149,7 @@ class Explain implements Executable
|
||||
if ($explainable instanceof FindAndModify || $explainable instanceof FindOneAndDelete || $explainable instanceof FindOneAndReplace || $explainable instanceof FindOneAndUpdate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -27,5 +27,5 @@ use MongoDB\Driver\Server;
|
||||
*/
|
||||
interface Explainable extends Executable
|
||||
{
|
||||
function getCommandDocument(Server $server);
|
||||
public function getCommandDocument(Server $server);
|
||||
}
|
||||
|
45
cache/stores/mongodb/MongoDB/Operation/Find.php
vendored
45
cache/stores/mongodb/MongoDB/Operation/Find.php
vendored
@ -18,15 +18,23 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Query;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\server_supports_feature;
|
||||
use function trigger_error;
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Operation for the find command.
|
||||
*
|
||||
@ -41,12 +49,22 @@ class Find implements Executable, Explainable
|
||||
const TAILABLE = 2;
|
||||
const TAILABLE_AWAIT = 3;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array|object */
|
||||
private $filter;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -147,7 +165,7 @@ class Find implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
@ -168,7 +186,7 @@ class Find implements Executable, Explainable
|
||||
}
|
||||
|
||||
if (isset($options['cursorType'])) {
|
||||
if ( ! is_integer($options['cursorType'])) {
|
||||
if (! is_integer($options['cursorType'])) {
|
||||
throw InvalidArgumentException::invalidType('"cursorType" option', $options['cursorType'], 'integer');
|
||||
}
|
||||
|
||||
@ -224,11 +242,11 @@ class Find implements Executable, Explainable
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['returnKey']) && ! is_bool($options['returnKey'])) {
|
||||
@ -236,7 +254,7 @@ class Find implements Executable, Explainable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['showRecordId']) && ! is_bool($options['showRecordId'])) {
|
||||
@ -288,14 +306,19 @@ class Find implements Executable, Explainable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
throw UnsupportedException::readConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['readConcern'])) {
|
||||
throw UnsupportedException::readConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$cursor = $server->executeQuery($this->databaseName . '.' . $this->collectionName, new Query($this->filter, $this->createQueryOptions()), $this->createExecuteOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
@ -341,7 +364,7 @@ class Find implements Executable, Explainable
|
||||
];
|
||||
|
||||
foreach ($modifierFallback as $modifier) {
|
||||
if ( ! isset($options[$modifier[0]]) && isset($options['modifiers'][$modifier[1]])) {
|
||||
if (! isset($options[$modifier[0]]) && isset($options['modifiers'][$modifier[1]])) {
|
||||
$options[$modifier[0]] = $options['modifiers'][$modifier[1]];
|
||||
}
|
||||
}
|
||||
@ -407,7 +430,7 @@ class Find implements Executable, Explainable
|
||||
|
||||
$modifiers = empty($this->options['modifiers']) ? [] : (array) $this->options['modifiers'];
|
||||
|
||||
if ( ! empty($modifiers)) {
|
||||
if (! empty($modifiers)) {
|
||||
$options['modifiers'] = $modifiers;
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,21 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function MongoDB\create_field_path_type_map;
|
||||
use function MongoDB\is_pipeline;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the findAndModify command.
|
||||
@ -37,13 +45,25 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class FindAndModify implements Executable, Explainable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForArrayFilters = 6;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -137,7 +157,7 @@ class FindAndModify implements Executable, Explainable
|
||||
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['new'])) {
|
||||
if (! is_bool($options['new'])) {
|
||||
throw InvalidArgumentException::invalidType('"new" option', $options['new'], 'boolean');
|
||||
}
|
||||
|
||||
@ -145,12 +165,12 @@ class FindAndModify implements Executable, Explainable
|
||||
throw InvalidArgumentException::invalidType('"query" option', $options['query'], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['remove'])) {
|
||||
if (! is_bool($options['remove'])) {
|
||||
throw InvalidArgumentException::invalidType('"remove" option', $options['remove'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) {
|
||||
@ -166,14 +186,14 @@ class FindAndModify implements Executable, Explainable
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['upsert'])) {
|
||||
if (! is_bool($options['upsert'])) {
|
||||
throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean');
|
||||
}
|
||||
|
||||
if ( ! (isset($options['update']) xor $options['remove'])) {
|
||||
if (! (isset($options['update']) xor $options['remove'])) {
|
||||
throw new InvalidArgumentException('The "remove" option must be true or an "update" document must be specified, but not both');
|
||||
}
|
||||
|
||||
@ -198,34 +218,32 @@ class FindAndModify implements Executable, Explainable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['arrayFilters']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
if (isset($this->options['arrayFilters']) && ! server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
throw UnsupportedException::arrayFiltersNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$cursor = $server->executeWriteCommand($this->databaseName, new Command($this->createCommandDocument($server)), $this->createOptions());
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
if ( ! isset($result->value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! is_object($result->value)) {
|
||||
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']);
|
||||
$cursor->setTypeMap(create_field_path_type_map($this->options['typeMap'], 'value'));
|
||||
}
|
||||
|
||||
return $result->value;
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
return isset($result->value) ? $result->value : null;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
@ -236,6 +254,7 @@ class FindAndModify implements Executable, Explainable
|
||||
/**
|
||||
* Create the findAndModify command document.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return array
|
||||
*/
|
||||
private function createCommandDocument(Server $server)
|
||||
@ -249,12 +268,18 @@ class FindAndModify implements Executable, Explainable
|
||||
$cmd['upsert'] = $this->options['upsert'];
|
||||
}
|
||||
|
||||
foreach (['collation', 'fields', 'query', 'sort', 'update'] as $option) {
|
||||
foreach (['collation', 'fields', 'query', 'sort'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = (object) $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->options['update'])) {
|
||||
$cmd['update'] = is_pipeline($this->options['update'])
|
||||
? $this->options['update']
|
||||
: (object) $this->options['update'];
|
||||
}
|
||||
|
||||
if (isset($this->options['arrayFilters'])) {
|
||||
$cmd['arrayFilters'] = $this->options['arrayFilters'];
|
||||
}
|
||||
@ -263,7 +288,9 @@ class FindAndModify implements Executable, Explainable
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,11 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
|
||||
/**
|
||||
* Operation for finding a single document with the find command.
|
||||
@ -32,6 +33,7 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class FindOne implements Executable, Explainable
|
||||
{
|
||||
/** @var Find */
|
||||
private $find;
|
||||
|
||||
/**
|
||||
@ -126,7 +128,7 @@ class FindOne implements Executable, Explainable
|
||||
$cursor = $this->find->execute($server);
|
||||
$document = current($cursor->toArray());
|
||||
|
||||
return ($document === false) ? null : $document;
|
||||
return $document === false ? null : $document;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
|
@ -17,10 +17,12 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
|
||||
/**
|
||||
* Operation for deleting a document with the findAndModify command.
|
||||
@ -31,6 +33,7 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class FindOneAndDelete implements Executable, Explainable
|
||||
{
|
||||
/** @var FindAndModify */
|
||||
private $findAndModify;
|
||||
|
||||
/**
|
||||
@ -71,7 +74,7 @@ class FindOneAndDelete implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,14 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function MongoDB\is_first_key_operator;
|
||||
|
||||
/**
|
||||
* Operation for replacing a document with the findAndModify command.
|
||||
@ -34,6 +38,7 @@ class FindOneAndReplace implements Executable, Explainable
|
||||
const RETURN_DOCUMENT_BEFORE = 1;
|
||||
const RETURN_DOCUMENT_AFTER = 2;
|
||||
|
||||
/** @var FindAndModify */
|
||||
private $findAndModify;
|
||||
|
||||
/**
|
||||
@ -90,15 +95,15 @@ class FindOneAndReplace implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_array($replacement) && ! is_object($replacement)) {
|
||||
if (! is_array($replacement) && ! is_object($replacement)) {
|
||||
throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object');
|
||||
}
|
||||
|
||||
if (\MongoDB\is_first_key_operator($replacement)) {
|
||||
if (is_first_key_operator($replacement)) {
|
||||
throw new InvalidArgumentException('First key in $replacement argument is an update operator');
|
||||
}
|
||||
|
||||
@ -111,7 +116,7 @@ class FindOneAndReplace implements Executable, Explainable
|
||||
throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_integer($options['returnDocument'])) {
|
||||
if (! is_integer($options['returnDocument'])) {
|
||||
throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer');
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,15 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function MongoDB\is_first_key_operator;
|
||||
use function MongoDB\is_pipeline;
|
||||
|
||||
/**
|
||||
* Operation for updating a document with the findAndModify command.
|
||||
@ -34,6 +39,7 @@ class FindOneAndUpdate implements Executable, Explainable
|
||||
const RETURN_DOCUMENT_BEFORE = 1;
|
||||
const RETURN_DOCUMENT_AFTER = 2;
|
||||
|
||||
/** @var FindAndModify */
|
||||
private $findAndModify;
|
||||
|
||||
/**
|
||||
@ -93,16 +99,16 @@ class FindOneAndUpdate implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_array($update) && ! is_object($update)) {
|
||||
if (! is_array($update) && ! is_object($update)) {
|
||||
throw InvalidArgumentException::invalidType('$update', $update, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! \MongoDB\is_first_key_operator($update)) {
|
||||
throw new InvalidArgumentException('First key in $update argument is not an update operator');
|
||||
if (! is_first_key_operator($update) && ! is_pipeline($update)) {
|
||||
throw new InvalidArgumentException('Expected an update document with operator as first key or a pipeline');
|
||||
}
|
||||
|
||||
$options += [
|
||||
@ -114,7 +120,7 @@ class FindOneAndUpdate implements Executable, Explainable
|
||||
throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_integer($options['returnDocument'])) {
|
||||
if (! is_integer($options['returnDocument'])) {
|
||||
throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer');
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,19 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\InsertManyResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\InsertManyResult;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_object;
|
||||
use function MongoDB\server_supports_feature;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Operation for inserting multiple documents with the insert command.
|
||||
@ -34,11 +40,19 @@ use MongoDB\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class InsertMany implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var object[]|array[] */
|
||||
private $documents;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -81,7 +95,7 @@ class InsertMany implements Executable
|
||||
throw new InvalidArgumentException(sprintf('$documents is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($document) && ! is_object($document)) {
|
||||
if (! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$documents[%d]', $i), $document, 'array or object');
|
||||
}
|
||||
|
||||
@ -94,16 +108,16 @@ class InsertMany implements Executable
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['ordered'])) {
|
||||
if (! is_bool($options['ordered'])) {
|
||||
throw InvalidArgumentException::invalidType('"ordered" option', $options['ordered'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -126,9 +140,16 @@ class InsertMany implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$options = ['ordered' => $this->options['ordered']];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,18 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\InsertOneResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\InsertOneResult;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_object;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for inserting a single document with the insert command.
|
||||
@ -34,11 +39,19 @@ use MongoDB\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class InsertOne implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array|object */
|
||||
private $document;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -66,7 +79,7 @@ class InsertOne implements Executable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $document, array $options = [])
|
||||
{
|
||||
if ( ! is_array($document) && ! is_object($document)) {
|
||||
if (! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
@ -75,11 +88,11 @@ class InsertOne implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -104,7 +117,14 @@ class InsertOne implements Executable
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if (isset($this->options['writeConcern']) && $inTransaction) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
|
@ -18,15 +18,16 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Query;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Model\CachingIterator;
|
||||
use MongoDB\Model\CollectionInfoCommandIterator;
|
||||
use MongoDB\Model\CollectionInfoIterator;
|
||||
use MongoDB\Model\CollectionInfoLegacyIterator;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
|
||||
/**
|
||||
* Operation for the listCollections command.
|
||||
@ -37,7 +38,10 @@ use MongoDB\Model\CollectionInfoLegacyIterator;
|
||||
*/
|
||||
class ListCollections implements Executable
|
||||
{
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -69,7 +73,7 @@ class ListCollections implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
@ -121,7 +125,7 @@ class ListCollections implements Executable
|
||||
{
|
||||
$cmd = ['listCollections' => 1];
|
||||
|
||||
if ( ! empty($this->options['filter'])) {
|
||||
if (! empty($this->options['filter'])) {
|
||||
$cmd['filter'] = (object) $this->options['filter'];
|
||||
}
|
||||
|
||||
@ -129,7 +133,7 @@ class ListCollections implements Executable
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
$cursor = $server->executeCommand($this->databaseName, new Command($cmd), $this->createOptions());
|
||||
$cursor = $server->executeReadCommand($this->databaseName, new Command($cmd), $this->createOptions());
|
||||
$cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
|
||||
|
||||
return new CollectionInfoCommandIterator(new CachingIterator($cursor));
|
||||
|
@ -18,13 +18,17 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Model\DatabaseInfoIterator;
|
||||
use MongoDB\Model\DatabaseInfoLegacyIterator;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
|
||||
/**
|
||||
* Operation for the ListDatabases command.
|
||||
@ -35,6 +39,7 @@ use MongoDB\Model\DatabaseInfoLegacyIterator;
|
||||
*/
|
||||
class ListDatabases implements Executable
|
||||
{
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -67,7 +72,7 @@ class ListDatabases implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
$this->options = $options;
|
||||
@ -86,7 +91,7 @@ class ListDatabases implements Executable
|
||||
{
|
||||
$cmd = ['listDatabases' => 1];
|
||||
|
||||
if ( ! empty($this->options['filter'])) {
|
||||
if (! empty($this->options['filter'])) {
|
||||
$cmd['filter'] = (object) $this->options['filter'];
|
||||
}
|
||||
|
||||
@ -94,11 +99,11 @@ class ListDatabases implements Executable
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
$cursor = $server->executeCommand('admin', new Command($cmd), $this->createOptions());
|
||||
$cursor = $server->executeReadCommand('admin', new Command($cmd), $this->createOptions());
|
||||
$cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
if ( ! isset($result['databases']) || ! is_array($result['databases'])) {
|
||||
if (! isset($result['databases']) || ! is_array($result['databases'])) {
|
||||
throw new UnexpectedValueException('listDatabases command did not return a "databases" array');
|
||||
}
|
||||
|
||||
|
@ -17,16 +17,16 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use EmptyIterator;
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Query;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Model\CachingIterator;
|
||||
use MongoDB\Model\IndexInfoIterator;
|
||||
use MongoDB\Model\IndexInfoIteratorIterator;
|
||||
use EmptyIterator;
|
||||
use function is_integer;
|
||||
|
||||
/**
|
||||
* Operation for the listIndexes command.
|
||||
@ -37,11 +37,19 @@ use EmptyIterator;
|
||||
*/
|
||||
class ListIndexes implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $errorCodeDatabaseNotFound = 60;
|
||||
|
||||
/** @var integer */
|
||||
private static $errorCodeNamespaceNotFound = 26;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -68,7 +76,7 @@ class ListIndexes implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
@ -126,14 +134,14 @@ class ListIndexes implements Executable
|
||||
}
|
||||
|
||||
try {
|
||||
$cursor = $server->executeCommand($this->databaseName, new Command($cmd), $this->createOptions());
|
||||
$cursor = $server->executeReadCommand($this->databaseName, new Command($cmd), $this->createOptions());
|
||||
} catch (DriverRuntimeException $e) {
|
||||
/* The server may return an error if the collection does not exist.
|
||||
* Check for possible error codes (see: SERVER-20463) and return an
|
||||
* empty iterator instead of throwing.
|
||||
*/
|
||||
if ($e->getCode() === self::$errorCodeNamespaceNotFound || $e->getCode() === self::$errorCodeDatabaseNotFound) {
|
||||
return new IndexInfoIteratorIterator(new EmptyIterator);
|
||||
return new IndexInfoIteratorIterator(new EmptyIterator());
|
||||
}
|
||||
|
||||
throw $e;
|
||||
|
@ -17,21 +17,29 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use ArrayIterator;
|
||||
use MongoDB\BSON\JavascriptInterface;
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\TypeMapArrayIterator;
|
||||
use MongoDB\MapReduceResult;
|
||||
use ArrayIterator;
|
||||
use stdClass;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_integer;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\create_field_path_type_map;
|
||||
use function MongoDB\is_mapreduce_output_inline;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the mapReduce command.
|
||||
@ -42,16 +50,34 @@ use stdClass;
|
||||
*/
|
||||
class MapReduce implements Executable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForWriteConcern = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var JavascriptInterface */
|
||||
private $map;
|
||||
|
||||
/** @var JavascriptInterface */
|
||||
private $reduce;
|
||||
|
||||
/** @var array|object|string */
|
||||
private $out;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -144,7 +170,7 @@ class MapReduce implements Executable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = [])
|
||||
{
|
||||
if ( ! is_string($out) && ! is_array($out) && ! is_object($out)) {
|
||||
if (! is_string($out) && ! is_array($out) && ! is_object($out)) {
|
||||
throw InvalidArgumentException::invalidType('$out', $out, 'string or array or object');
|
||||
}
|
||||
|
||||
@ -157,7 +183,7 @@ class MapReduce implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['finalize']) && ! $options['finalize'] instanceof JavascriptInterface) {
|
||||
throw InvalidArgumentException::invalidType('"finalize" option', $options['finalize'], 'MongoDB\Driver\Javascript');
|
||||
throw InvalidArgumentException::invalidType('"finalize" option', $options['finalize'], JavascriptInterface::class);
|
||||
}
|
||||
|
||||
if (isset($options['jsMode']) && ! is_bool($options['jsMode'])) {
|
||||
@ -177,11 +203,11 @@ class MapReduce implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern');
|
||||
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
|
||||
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
|
||||
}
|
||||
|
||||
if (isset($options['scope']) && ! is_array($options['scope']) && ! is_object($options['scope'])) {
|
||||
@ -189,7 +215,7 @@ class MapReduce implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) {
|
||||
@ -205,7 +231,7 @@ class MapReduce implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && $options['readConcern']->isDefault()) {
|
||||
@ -236,26 +262,46 @@ class MapReduce implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
throw UnsupportedException::readConcernNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$hasOutputCollection = ! \MongoDB\is_mapreduce_output_inline($this->out);
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction) {
|
||||
if (isset($this->options['readConcern'])) {
|
||||
throw UnsupportedException::readConcernNotSupportedInTransaction();
|
||||
}
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
$hasOutputCollection = ! is_mapreduce_output_inline($this->out);
|
||||
|
||||
$command = $this->createCommand($server);
|
||||
$options = $this->createOptions($hasOutputCollection);
|
||||
|
||||
/* If the mapReduce operation results in a write, use
|
||||
* executeReadWriteCommand to ensure we're handling the writeConcern
|
||||
* option.
|
||||
* In other cases, we use executeCommand as this will prevent the
|
||||
* mapReduce operation from being retried when retryReads is enabled.
|
||||
* See https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.rst#unsupported-read-operations. */
|
||||
$cursor = $hasOutputCollection
|
||||
? $server->executeReadWriteCommand($this->databaseName, $command, $options)
|
||||
: $server->executeReadCommand($this->databaseName, $command, $options);
|
||||
: $server->executeCommand($this->databaseName, $command, $options);
|
||||
|
||||
if (isset($this->options['typeMap']) && ! $hasOutputCollection) {
|
||||
$cursor->setTypeMap(create_field_path_type_map($this->options['typeMap'], 'results.$'));
|
||||
}
|
||||
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
@ -291,7 +337,9 @@ class MapReduce implements Executable
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
@ -312,11 +360,7 @@ class MapReduce implements Executable
|
||||
if (isset($result->results) && is_array($result->results)) {
|
||||
$results = $result->results;
|
||||
|
||||
return function() use ($results) {
|
||||
if (isset($this->options['typeMap'])) {
|
||||
return new TypeMapArrayIterator($results, $this->options['typeMap']);
|
||||
}
|
||||
|
||||
return function () use ($results) {
|
||||
return new ArrayIterator($results);
|
||||
};
|
||||
}
|
||||
@ -328,7 +372,7 @@ class MapReduce implements Executable
|
||||
? new Find($this->databaseName, $result->result, [], $options)
|
||||
: new Find($result->result->db, $result->result->collection, [], $options);
|
||||
|
||||
return function() use ($find, $server) {
|
||||
return function () use ($find, $server) {
|
||||
return $find->execute($server);
|
||||
};
|
||||
}
|
||||
@ -352,7 +396,7 @@ class MapReduce implements Executable
|
||||
$options['readConcern'] = $this->options['readConcern'];
|
||||
}
|
||||
|
||||
if ( ! $hasOutputCollection && isset($this->options['readPreference'])) {
|
||||
if (! $hasOutputCollection && isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
|
@ -18,11 +18,15 @@
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the collMod command.
|
||||
@ -33,9 +37,16 @@ use MongoDB\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class ModifyCollection implements Executable
|
||||
{
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array */
|
||||
private $collectionOptions;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -55,10 +66,10 @@ class ModifyCollection implements Executable
|
||||
* This is not supported for server versions < 3.2 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection or view to modify
|
||||
* @param string $collectionOptions Collection or view options to assign
|
||||
* @param array $options Command options
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection or view to modify
|
||||
* @param array $collectionOptions Collection or view options to assign
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $collectionOptions, array $options = [])
|
||||
@ -68,7 +79,7 @@ class ModifyCollection implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
@ -76,7 +87,7 @@ class ModifyCollection implements Executable
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -99,7 +110,7 @@ class ModifyCollection implements Executable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
|
@ -17,11 +17,15 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\UpdateResult;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function MongoDB\is_first_key_operator;
|
||||
use function MongoDB\is_pipeline;
|
||||
|
||||
/**
|
||||
* Operation for replacing a single document with the update command.
|
||||
@ -32,6 +36,7 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class ReplaceOne implements Executable
|
||||
{
|
||||
/** @var Update */
|
||||
private $update;
|
||||
|
||||
/**
|
||||
@ -68,14 +73,18 @@ class ReplaceOne implements Executable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = [])
|
||||
{
|
||||
if ( ! is_array($replacement) && ! is_object($replacement)) {
|
||||
if (! is_array($replacement) && ! is_object($replacement)) {
|
||||
throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object');
|
||||
}
|
||||
|
||||
if (\MongoDB\is_first_key_operator($replacement)) {
|
||||
if (is_first_key_operator($replacement)) {
|
||||
throw new InvalidArgumentException('First key in $replacement argument is an update operator');
|
||||
}
|
||||
|
||||
if (is_pipeline($replacement)) {
|
||||
throw new InvalidArgumentException('$replacement argument is a pipeline');
|
||||
}
|
||||
|
||||
$this->update = new Update(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
|
@ -17,14 +17,20 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\UpdateResult;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_object;
|
||||
use function MongoDB\is_first_key_operator;
|
||||
use function MongoDB\is_pipeline;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for the update command.
|
||||
@ -37,14 +43,28 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class Update implements Executable, Explainable
|
||||
{
|
||||
/** @var integer */
|
||||
private static $wireVersionForArrayFilters = 6;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var string */
|
||||
private $collectionName;
|
||||
|
||||
/** @var array|object */
|
||||
private $filter;
|
||||
|
||||
/** @var array|object */
|
||||
private $update;
|
||||
|
||||
/** @var array */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
@ -92,11 +112,11 @@ class Update implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
if (! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_array($update) && ! is_object($update)) {
|
||||
if (! is_array($update) && ! is_object($update)) {
|
||||
throw InvalidArgumentException::invalidType('$update', $filter, 'array or object');
|
||||
}
|
||||
|
||||
@ -117,24 +137,24 @@ class Update implements Executable, Explainable
|
||||
throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['multi'])) {
|
||||
if (! is_bool($options['multi'])) {
|
||||
throw InvalidArgumentException::invalidType('"multi" option', $options['multi'], 'boolean');
|
||||
}
|
||||
|
||||
if ($options['multi'] && ! \MongoDB\is_first_key_operator($update)) {
|
||||
if ($options['multi'] && ! is_first_key_operator($update) && ! is_pipeline($update)) {
|
||||
throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['upsert'])) {
|
||||
if (! is_bool($options['upsert'])) {
|
||||
throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
@ -159,17 +179,24 @@ class Update implements Executable, Explainable
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['arrayFilters']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
if (isset($this->options['arrayFilters']) && ! server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
throw UnsupportedException::arrayFiltersNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
|
||||
if ($inTransaction && isset($this->options['writeConcern'])) {
|
||||
throw UnsupportedException::writeConcernNotSupportedInTransaction();
|
||||
}
|
||||
|
||||
$bulkOptions = [];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
@ -189,7 +216,9 @@ class Update implements Executable, Explainable
|
||||
$cmd['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
if (! empty($this->options['bypassDocumentValidation']) &&
|
||||
server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)
|
||||
) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
|
@ -17,11 +17,15 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\UpdateResult;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function MongoDB\is_first_key_operator;
|
||||
use function MongoDB\is_pipeline;
|
||||
|
||||
/**
|
||||
* Operation for updating multiple documents with the update command.
|
||||
@ -32,6 +36,7 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class UpdateMany implements Executable, Explainable
|
||||
{
|
||||
/** @var Update */
|
||||
private $update;
|
||||
|
||||
/**
|
||||
@ -74,12 +79,12 @@ class UpdateMany implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! is_array($update) && ! is_object($update)) {
|
||||
if (! is_array($update) && ! is_object($update)) {
|
||||
throw InvalidArgumentException::invalidType('$update', $update, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! \MongoDB\is_first_key_operator($update)) {
|
||||
throw new InvalidArgumentException('First key in $update argument is not an update operator');
|
||||
if (! is_first_key_operator($update) && ! is_pipeline($update)) {
|
||||
throw new InvalidArgumentException('Expected an update document with operator as first key or a pipeline');
|
||||
}
|
||||
|
||||
$this->update = new Update(
|
||||
|
@ -17,11 +17,15 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\UpdateResult;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function MongoDB\is_first_key_operator;
|
||||
use function MongoDB\is_pipeline;
|
||||
|
||||
/**
|
||||
* Operation for updating a single document with the update command.
|
||||
@ -32,6 +36,7 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class UpdateOne implements Executable, Explainable
|
||||
{
|
||||
/** @var Update */
|
||||
private $update;
|
||||
|
||||
/**
|
||||
@ -74,12 +79,12 @@ class UpdateOne implements Executable, Explainable
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! is_array($update) && ! is_object($update)) {
|
||||
if (! is_array($update) && ! is_object($update)) {
|
||||
throw InvalidArgumentException::invalidType('$update', $update, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! \MongoDB\is_first_key_operator($update)) {
|
||||
throw new InvalidArgumentException('First key in $update argument is not an update operator');
|
||||
if (! is_first_key_operator($update) && ! is_pipeline($update)) {
|
||||
throw new InvalidArgumentException('Expected an update document with operator as first key or a pipeline');
|
||||
}
|
||||
|
||||
$this->update = new Update(
|
||||
|
278
cache/stores/mongodb/MongoDB/Operation/Watch.php
vendored
278
cache/stores/mongodb/MongoDB/Operation/Watch.php
vendored
@ -17,23 +17,31 @@
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use MongoDB\ChangeStream;
|
||||
use MongoDB\BSON\TimestampInterface;
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\ChangeStream;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Exception\RuntimeException;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\Monitoring\CommandFailedEvent;
|
||||
use MongoDB\Driver\Monitoring\CommandStartedEvent;
|
||||
use MongoDB\Driver\Monitoring\CommandSubscriber;
|
||||
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\Exception\RuntimeException;
|
||||
use MongoDB\Driver\Monitoring\CommandFailedEvent;
|
||||
use MongoDB\Driver\Monitoring\CommandSubscriber;
|
||||
use MongoDB\Driver\Monitoring\CommandStartedEvent;
|
||||
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\ChangeStreamIterator;
|
||||
use function array_intersect_key;
|
||||
use function array_unshift;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function MongoDB\Driver\Monitoring\addSubscriber;
|
||||
use function MongoDB\Driver\Monitoring\removeSubscriber;
|
||||
use function MongoDB\select_server;
|
||||
use function MongoDB\server_supports_feature;
|
||||
|
||||
/**
|
||||
* Operation for creating a change stream with the aggregate command.
|
||||
@ -47,19 +55,44 @@ use MongoDB\Exception\UnsupportedException;
|
||||
*/
|
||||
class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
{
|
||||
private static $wireVersionForOperationTime = 7;
|
||||
|
||||
const FULL_DOCUMENT_DEFAULT = 'default';
|
||||
const FULL_DOCUMENT_UPDATE_LOOKUP = 'updateLookup';
|
||||
|
||||
/** @var integer */
|
||||
private static $wireVersionForStartAtOperationTime = 7;
|
||||
|
||||
/** @var Aggregate */
|
||||
private $aggregate;
|
||||
|
||||
/** @var array */
|
||||
private $aggregateOptions;
|
||||
|
||||
/** @var array */
|
||||
private $changeStreamOptions;
|
||||
|
||||
/** @var string|null */
|
||||
private $collectionName;
|
||||
|
||||
/** @var string */
|
||||
private $databaseName;
|
||||
|
||||
/** @var integer|null */
|
||||
private $firstBatchSize;
|
||||
|
||||
/** @var boolean */
|
||||
private $hasResumed = false;
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
/** @var TimestampInterface */
|
||||
private $operationTime;
|
||||
|
||||
/** @var array */
|
||||
private $pipeline;
|
||||
private $resumeCallable;
|
||||
|
||||
/** @var object|null */
|
||||
private $postBatchResumeToken;
|
||||
|
||||
/**
|
||||
* Constructs an aggregate command for creating a change stream.
|
||||
@ -92,21 +125,31 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
* * resumeAfter (document): Specifies the logical starting point for the
|
||||
* new change stream.
|
||||
*
|
||||
* Using this option in conjunction with "startAtOperationTime" will
|
||||
* result in a server error. The options are mutually exclusive.
|
||||
* Using this option in conjunction with "startAfter" and/or
|
||||
* "startAtOperationTime" will result in a server error. The options are
|
||||
* mutually exclusive.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * startAfter (document): Specifies the logical starting point for the
|
||||
* new change stream. Unlike "resumeAfter", this option can be used with
|
||||
* a resume token from an "invalidate" event.
|
||||
*
|
||||
* Using this option in conjunction with "resumeAfter" and/or
|
||||
* "startAtOperationTime" will result in a server error. The options are
|
||||
* mutually exclusive.
|
||||
*
|
||||
* * startAtOperationTime (MongoDB\BSON\TimestampInterface): If specified,
|
||||
* the change stream will only provide changes that occurred at or after
|
||||
* the specified timestamp. Any command run against the server will
|
||||
* return an operation time that can be used here. Alternatively, an
|
||||
* operation time may be obtained from MongoDB\Driver\Server::getInfo().
|
||||
*
|
||||
* Using this option in conjunction with "resumeAfter" will result in a
|
||||
* server error. The options are mutually exclusive.
|
||||
* Using this option in conjunction with "resumeAfter" and/or
|
||||
* "startAfter" will result in a server error. The options are mutually
|
||||
* exclusive.
|
||||
*
|
||||
* This option is not supported for server versions < 4.0.
|
||||
*
|
||||
@ -117,11 +160,11 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
* for the collection name. A cluster-level change stream may be created by
|
||||
* specifying null for both the database and collection name.
|
||||
*
|
||||
* @param Manager $manager Manager instance from the driver
|
||||
* @param string|null $databaseName Database name
|
||||
* @param string|null $collectionName Collection name
|
||||
* @param array $pipeline List of pipeline operations
|
||||
* @param array $options Command options
|
||||
* @param Manager $manager Manager instance from the driver
|
||||
* @param string|null $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(Manager $manager, $databaseName, $collectionName, array $pipeline, array $options = [])
|
||||
@ -143,6 +186,10 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
throw InvalidArgumentException::invalidType('"resumeAfter" option', $options['resumeAfter'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['startAfter']) && ! is_array($options['startAfter']) && ! is_object($options['startAfter'])) {
|
||||
throw InvalidArgumentException::invalidType('"startAfter" option', $options['startAfter'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['startAtOperationTime']) && ! $options['startAtOperationTime'] instanceof TimestampInterface) {
|
||||
throw InvalidArgumentException::invalidType('"startAtOperationTime" option', $options['startAtOperationTime'], TimestampInterface::class);
|
||||
}
|
||||
@ -152,7 +199,7 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
* ("implicit from the user's perspective" per PHPLIB-342). Since this
|
||||
* is filling in for an implicit session, we default "causalConsistency"
|
||||
* to false. */
|
||||
if ( ! isset($options['session'])) {
|
||||
if (! isset($options['session'])) {
|
||||
try {
|
||||
$options['session'] = $manager->startSession(['causalConsistency' => false]);
|
||||
} catch (RuntimeException $e) {
|
||||
@ -162,7 +209,7 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
}
|
||||
|
||||
$this->aggregateOptions = array_intersect_key($options, ['batchSize' => 1, 'collation' => 1, 'maxAwaitTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1, 'typeMap' => 1]);
|
||||
$this->changeStreamOptions = array_intersect_key($options, ['fullDocument' => 1, 'resumeAfter' => 1, 'startAtOperationTime' => 1]);
|
||||
$this->changeStreamOptions = array_intersect_key($options, ['fullDocument' => 1, 'resumeAfter' => 1, 'startAfter' => 1, 'startAtOperationTime' => 1]);
|
||||
|
||||
// Null database name implies a cluster-wide change stream
|
||||
if ($databaseName === null) {
|
||||
@ -170,12 +217,12 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
$this->changeStreamOptions['allChangesForCluster'] = true;
|
||||
}
|
||||
|
||||
$this->manager = $manager;
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = isset($collectionName) ? (string) $collectionName : null;
|
||||
$this->pipeline = $pipeline;
|
||||
|
||||
$this->aggregate = $this->createAggregate();
|
||||
$this->resumeCallable = $this->createResumeCallable($manager);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@ -186,6 +233,12 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
/** @internal */
|
||||
final public function commandStarted(CommandStartedEvent $event)
|
||||
{
|
||||
if ($event->getCommandName() !== 'aggregate') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->firstBatchSize = null;
|
||||
$this->postBatchResumeToken = null;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@ -197,7 +250,18 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
|
||||
$reply = $event->getReply();
|
||||
|
||||
if (isset($reply->operationTime) && $reply->operationTime instanceof TimestampInterface) {
|
||||
if (! isset($reply->cursor->firstBatch) || ! is_array($reply->cursor->firstBatch)) {
|
||||
throw new UnexpectedValueException('aggregate command did not return a "cursor.firstBatch" array');
|
||||
}
|
||||
|
||||
$this->firstBatchSize = count($reply->cursor->firstBatch);
|
||||
|
||||
if (isset($reply->cursor->postBatchResumeToken) && is_object($reply->cursor->postBatchResumeToken)) {
|
||||
$this->postBatchResumeToken = $reply->cursor->postBatchResumeToken;
|
||||
}
|
||||
|
||||
if ($this->shouldCaptureOperationTime($event->getServer()) &&
|
||||
isset($reply->operationTime) && $reply->operationTime instanceof TimestampInterface) {
|
||||
$this->operationTime = $reply->operationTime;
|
||||
}
|
||||
}
|
||||
@ -213,11 +277,16 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return new ChangeStream($this->executeAggregate($server), $this->resumeCallable);
|
||||
return new ChangeStream(
|
||||
$this->createChangeStreamIterator($server),
|
||||
function ($resumeToken, $hasAdvanced) {
|
||||
return $this->resume($resumeToken, $hasAdvanced);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the aggregate command for creating a change stream.
|
||||
* Create the aggregate command for a change stream.
|
||||
*
|
||||
* This method is also used to recreate the aggregate command when resuming.
|
||||
*
|
||||
@ -231,56 +300,139 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
return new Aggregate($this->databaseName, $this->collectionName, $pipeline, $this->aggregateOptions);
|
||||
}
|
||||
|
||||
private function createResumeCallable(Manager $manager)
|
||||
/**
|
||||
* Create a ChangeStreamIterator by executing the aggregate command.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return ChangeStreamIterator
|
||||
*/
|
||||
private function createChangeStreamIterator(Server $server)
|
||||
{
|
||||
return function($resumeToken = null) use ($manager) {
|
||||
/* If a resume token was provided, update the "resumeAfter" option
|
||||
* and ensure that "startAtOperationTime" is no longer set. */
|
||||
if ($resumeToken !== null) {
|
||||
$this->changeStreamOptions['resumeAfter'] = $resumeToken;
|
||||
unset($this->changeStreamOptions['startAtOperationTime']);
|
||||
}
|
||||
|
||||
/* If we captured an operation time from the first aggregate command
|
||||
* and there is no "resumeAfter" option, set "startAtOperationTime"
|
||||
* so that we can resume from the original aggregate's time. */
|
||||
if ($this->operationTime !== null && ! isset($this->changeStreamOptions['resumeAfter'])) {
|
||||
$this->changeStreamOptions['startAtOperationTime'] = $this->operationTime;
|
||||
}
|
||||
|
||||
$this->aggregate = $this->createAggregate();
|
||||
|
||||
/* Select a new server using the read preference, execute this
|
||||
* operation on it, and return the new ChangeStream. */
|
||||
$server = $manager->selectServer($this->aggregateOptions['readPreference']);
|
||||
|
||||
return $this->execute($server);
|
||||
};
|
||||
return new ChangeStreamIterator(
|
||||
$this->executeAggregate($server),
|
||||
$this->firstBatchSize,
|
||||
$this->getInitialResumeToken(),
|
||||
$this->postBatchResumeToken
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the aggregate command and optionally capture its operation time.
|
||||
* Execute the aggregate command.
|
||||
*
|
||||
* The command will be executed using APM so that we can capture data from
|
||||
* its response (e.g. firstBatch size, postBatchResumeToken).
|
||||
*
|
||||
* @param Server $server
|
||||
* @return Cursor
|
||||
*/
|
||||
private function executeAggregate(Server $server)
|
||||
{
|
||||
/* If we've already captured an operation time or the server does not
|
||||
* support returning an operation time (e.g. MongoDB 3.6), execute the
|
||||
* aggregation directly and return its cursor. */
|
||||
if ($this->operationTime !== null || ! \MongoDB\server_supports_feature($server, self::$wireVersionForOperationTime)) {
|
||||
return $this->aggregate->execute($server);
|
||||
}
|
||||
|
||||
/* Otherwise, execute the aggregation using command monitoring so that
|
||||
* we can capture its operation time with commandSucceeded(). */
|
||||
\MongoDB\Driver\Monitoring\addSubscriber($this);
|
||||
addSubscriber($this);
|
||||
|
||||
try {
|
||||
return $this->aggregate->execute($server);
|
||||
} finally {
|
||||
\MongoDB\Driver\Monitoring\removeSubscriber($this);
|
||||
removeSubscriber($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the initial resume token for creating the ChangeStreamIterator.
|
||||
*
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#updating-the-cached-resume-token
|
||||
* @return array|object|null
|
||||
*/
|
||||
private function getInitialResumeToken()
|
||||
{
|
||||
if ($this->firstBatchSize === 0 && isset($this->postBatchResumeToken)) {
|
||||
return $this->postBatchResumeToken;
|
||||
}
|
||||
|
||||
if (isset($this->changeStreamOptions['startAfter'])) {
|
||||
return $this->changeStreamOptions['startAfter'];
|
||||
}
|
||||
|
||||
if (isset($this->changeStreamOptions['resumeAfter'])) {
|
||||
return $this->changeStreamOptions['resumeAfter'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes a change stream.
|
||||
*
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#resume-process
|
||||
* @param array|object|null $resumeToken
|
||||
* @param bool $hasAdvanced
|
||||
* @return ChangeStreamIterator
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function resume($resumeToken = null, $hasAdvanced = false)
|
||||
{
|
||||
if (isset($resumeToken) && ! is_array($resumeToken) && ! is_object($resumeToken)) {
|
||||
throw InvalidArgumentException::invalidType('$resumeToken', $resumeToken, 'array or object');
|
||||
}
|
||||
|
||||
$this->hasResumed = true;
|
||||
|
||||
/* Select a new server using the original read preference. While watch
|
||||
* is not usable within transactions, we still check if there is a
|
||||
* pinned session. This is to avoid an ambiguous error message about
|
||||
* running a command on the wrong server. */
|
||||
$server = select_server($this->manager, $this->aggregateOptions);
|
||||
|
||||
$resumeOption = isset($this->changeStreamOptions['startAfter']) && ! $hasAdvanced ? 'startAfter' : 'resumeAfter';
|
||||
|
||||
unset($this->changeStreamOptions['resumeAfter']);
|
||||
unset($this->changeStreamOptions['startAfter']);
|
||||
unset($this->changeStreamOptions['startAtOperationTime']);
|
||||
|
||||
if ($resumeToken !== null) {
|
||||
$this->changeStreamOptions[$resumeOption] = $resumeToken;
|
||||
}
|
||||
|
||||
if ($resumeToken === null && $this->operationTime !== null) {
|
||||
$this->changeStreamOptions['startAtOperationTime'] = $this->operationTime;
|
||||
}
|
||||
|
||||
// Recreate the aggregate command and return a new ChangeStreamIterator
|
||||
$this->aggregate = $this->createAggregate();
|
||||
|
||||
return $this->createChangeStreamIterator($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to capture operation time from an aggregate response.
|
||||
*
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#startatoperationtime
|
||||
* @param Server $server
|
||||
* @return boolean
|
||||
*/
|
||||
private function shouldCaptureOperationTime(Server $server)
|
||||
{
|
||||
if ($this->hasResumed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->changeStreamOptions['resumeAfter']) ||
|
||||
isset($this->changeStreamOptions['startAfter']) ||
|
||||
isset($this->changeStreamOptions['startAtOperationTime'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->firstBatchSize > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->postBatchResumeToken !== null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! server_supports_feature($server, self::$wireVersionForStartAtOperationTime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
127
cache/stores/mongodb/MongoDB/Operation/WithTransaction.php
vendored
Normal file
127
cache/stores/mongodb/MongoDB/Operation/WithTransaction.php
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace MongoDB\Operation;
|
||||
|
||||
use Exception;
|
||||
use MongoDB\Driver\Exception\RuntimeException;
|
||||
use MongoDB\Driver\Session;
|
||||
use function call_user_func;
|
||||
use function time;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class WithTransaction
|
||||
{
|
||||
/** @var callable */
|
||||
private $callback;
|
||||
|
||||
/** @var array */
|
||||
private $transactionOptions;
|
||||
|
||||
/**
|
||||
* @see Session::startTransaction for supported transaction options
|
||||
*
|
||||
* @param callable $callback A callback that will be invoked within the transaction
|
||||
* @param array $transactionOptions Additional options that are passed to Session::startTransaction
|
||||
*/
|
||||
public function __construct(callable $callback, array $transactionOptions = [])
|
||||
{
|
||||
$this->callback = $callback;
|
||||
$this->transactionOptions = $transactionOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation in the given session
|
||||
*
|
||||
* This helper takes care of retrying the commit operation or the entire
|
||||
* transaction if an error occurs.
|
||||
*
|
||||
* If the commit fails because of an UnknownTransactionCommitResult error, the
|
||||
* commit is retried without re-invoking the callback.
|
||||
* If the commit fails because of a TransientTransactionError, the entire
|
||||
* transaction will be retried. In this case, the callback will be invoked
|
||||
* again. It is important that the logic inside the callback is idempotent.
|
||||
*
|
||||
* In case of failures, the commit or transaction are retried until 120 seconds
|
||||
* from the initial call have elapsed. After that, no retries will happen and
|
||||
* the helper will throw the last exception received from the driver.
|
||||
*
|
||||
* @see Client::startSession
|
||||
*
|
||||
* @param Session $session A session object as retrieved by Client::startSession
|
||||
* @return void
|
||||
* @throws RuntimeException for driver errors while committing the transaction
|
||||
* @throws Exception for any other errors, including those thrown in the callback
|
||||
*/
|
||||
public function execute(Session $session)
|
||||
{
|
||||
$startTime = time();
|
||||
|
||||
while (true) {
|
||||
$session->startTransaction($this->transactionOptions);
|
||||
|
||||
try {
|
||||
call_user_func($this->callback, $session);
|
||||
} catch (Exception $e) {
|
||||
if ($session->isInTransaction()) {
|
||||
$session->abortTransaction();
|
||||
}
|
||||
|
||||
if ($e instanceof RuntimeException &&
|
||||
$e->hasErrorLabel('TransientTransactionError') &&
|
||||
! $this->isTransactionTimeLimitExceeded($startTime)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (! $session->isInTransaction()) {
|
||||
// Assume callback intentionally ended the transaction
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
$session->commitTransaction();
|
||||
} catch (RuntimeException $e) {
|
||||
if ($e->getCode() !== 50 /* MaxTimeMSExpired */ &&
|
||||
$e->hasErrorLabel('UnknownTransactionCommitResult') &&
|
||||
! $this->isTransactionTimeLimitExceeded($startTime)
|
||||
) {
|
||||
// Retry committing the transaction
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($e->hasErrorLabel('TransientTransactionError') &&
|
||||
! $this->isTransactionTimeLimitExceeded($startTime)
|
||||
) {
|
||||
// Restart the transaction, invoking the callback again
|
||||
continue 2;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// Commit was successful
|
||||
break;
|
||||
}
|
||||
|
||||
// Transaction was successful
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the time limit for retrying transactions in the convenient transaction API has passed
|
||||
*
|
||||
* @param int $startTime The time the transaction was started
|
||||
* @return bool
|
||||
*/
|
||||
private function isTransactionTimeLimitExceeded($startTime)
|
||||
{
|
||||
return time() - $startTime >= 120;
|
||||
}
|
||||
}
|
@ -25,14 +25,12 @@ use MongoDB\Exception\BadMethodCallException;
|
||||
*/
|
||||
class UpdateResult
|
||||
{
|
||||
/** @var WriteResult */
|
||||
private $writeResult;
|
||||
|
||||
/** @var boolean */
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
*/
|
||||
public function __construct(WriteResult $writeResult)
|
||||
{
|
||||
$this->writeResult = $writeResult;
|
||||
|
249
cache/stores/mongodb/MongoDB/functions.php
vendored
249
cache/stores/mongodb/MongoDB/functions.php
vendored
@ -17,13 +17,28 @@
|
||||
|
||||
namespace MongoDB;
|
||||
|
||||
use Exception;
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use stdClass;
|
||||
use MongoDB\Exception\RuntimeException;
|
||||
use MongoDB\Operation\WithTransaction;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use function end;
|
||||
use function get_object_vars;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function key;
|
||||
use function MongoDB\BSON\fromPHP;
|
||||
use function MongoDB\BSON\toPHP;
|
||||
use function reset;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Applies a type map to a document.
|
||||
@ -40,11 +55,11 @@ use ReflectionClass;
|
||||
*/
|
||||
function apply_type_map_to_document($document, array $typeMap)
|
||||
{
|
||||
if ( ! is_array($document) && ! is_object($document)) {
|
||||
if (! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
return \MongoDB\BSON\toPHP(\MongoDB\BSON\fromPHP($document), $typeMap);
|
||||
return toPHP(fromPHP($document), $typeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +81,7 @@ function generate_index_name($document)
|
||||
$document = get_object_vars($document);
|
||||
}
|
||||
|
||||
if ( ! is_array($document)) {
|
||||
if (! is_array($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
@ -99,18 +114,75 @@ function is_first_key_operator($document)
|
||||
$document = get_object_vars($document);
|
||||
}
|
||||
|
||||
if ( ! is_array($document)) {
|
||||
if (! is_array($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
reset($document);
|
||||
$firstKey = (string) key($document);
|
||||
|
||||
return (isset($firstKey[0]) && $firstKey[0] === '$');
|
||||
return isset($firstKey[0]) && $firstKey[0] === '$';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the aggregation pipeline ends with an $out operator.
|
||||
* Returns whether an update specification is a valid aggregation pipeline.
|
||||
*
|
||||
* @internal
|
||||
* @param mixed $pipeline
|
||||
* @return boolean
|
||||
*/
|
||||
function is_pipeline($pipeline)
|
||||
{
|
||||
if (! is_array($pipeline)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($pipeline === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$expectedKey = 0;
|
||||
|
||||
foreach ($pipeline as $key => $stage) {
|
||||
if (! is_array($stage) && ! is_object($stage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($expectedKey !== $key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$expectedKey++;
|
||||
$stage = (array) $stage;
|
||||
reset($stage);
|
||||
$key = key($stage);
|
||||
|
||||
if (! isset($key[0]) || $key[0] !== '$') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we are currently in a transaction.
|
||||
*
|
||||
* @internal
|
||||
* @param array $options Command options
|
||||
* @return boolean
|
||||
*/
|
||||
function is_in_transaction(array $options)
|
||||
{
|
||||
if (isset($options['session']) && $options['session'] instanceof Session && $options['session']->isInTransaction()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the aggregation pipeline ends with an $out or $merge operator.
|
||||
*
|
||||
* This is used for determining whether the aggregation pipeline must be
|
||||
* executed against a primary server.
|
||||
@ -119,7 +191,7 @@ function is_first_key_operator($document)
|
||||
* @param array $pipeline List of pipeline operations
|
||||
* @return boolean
|
||||
*/
|
||||
function is_last_pipeline_operator_out(array $pipeline)
|
||||
function is_last_pipeline_operator_write(array $pipeline)
|
||||
{
|
||||
$lastOp = end($pipeline);
|
||||
|
||||
@ -129,7 +201,7 @@ function is_last_pipeline_operator_out(array $pipeline)
|
||||
|
||||
$lastOp = (array) $lastOp;
|
||||
|
||||
return key($lastOp) === '$out';
|
||||
return in_array(key($lastOp), ['$out', '$merge'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +217,7 @@ function is_last_pipeline_operator_out(array $pipeline)
|
||||
*/
|
||||
function is_mapreduce_output_inline($out)
|
||||
{
|
||||
if ( ! is_array($out) && ! is_object($out)) {
|
||||
if (! is_array($out) && ! is_object($out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -157,7 +229,7 @@ function is_mapreduce_output_inline($out)
|
||||
$out = get_object_vars($out);
|
||||
}
|
||||
|
||||
if ( ! is_array($out)) {
|
||||
if (! is_array($out)) {
|
||||
throw InvalidArgumentException::invalidType('$out', $out, 'array or object');
|
||||
}
|
||||
|
||||
@ -180,18 +252,20 @@ function server_supports_feature(Server $server, $feature)
|
||||
$maxWireVersion = isset($info['maxWireVersion']) ? (integer) $info['maxWireVersion'] : 0;
|
||||
$minWireVersion = isset($info['minWireVersion']) ? (integer) $info['minWireVersion'] : 0;
|
||||
|
||||
return ($minWireVersion <= $feature && $maxWireVersion >= $feature);
|
||||
return $minWireVersion <= $feature && $maxWireVersion >= $feature;
|
||||
}
|
||||
|
||||
function is_string_array($input) {
|
||||
if (!is_array($input)){
|
||||
function is_string_array($input)
|
||||
{
|
||||
if (! is_array($input)) {
|
||||
return false;
|
||||
}
|
||||
foreach($input as $item) {
|
||||
if (!is_string($item)) {
|
||||
foreach ($input as $item) {
|
||||
if (! is_string($item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -204,22 +278,155 @@ function is_string_array($input) {
|
||||
* @see https://bugs.php.net/bug.php?id=49664
|
||||
* @param mixed $element Value to be copied
|
||||
* @return mixed
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
function recursive_copy($element) {
|
||||
function recursive_copy($element)
|
||||
{
|
||||
if (is_array($element)) {
|
||||
foreach ($element as $key => $value) {
|
||||
$element[$key] = recursive_copy($value);
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
if ( ! is_object($element)) {
|
||||
if (! is_object($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
if ( ! (new ReflectionClass($element))->isCloneable()) {
|
||||
if (! (new ReflectionClass($element))->isCloneable()) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
return clone $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a type map to apply to a field type
|
||||
*
|
||||
* This is used in the Aggregate, Distinct, and FindAndModify operations to
|
||||
* apply the root-level type map to the document that will be returned. It also
|
||||
* replaces the root type with object for consistency within these operations
|
||||
*
|
||||
* An existing type map for the given field path will not be overwritten
|
||||
*
|
||||
* @internal
|
||||
* @param array $typeMap The existing typeMap
|
||||
* @param string $fieldPath The field path to apply the root type to
|
||||
* @return array
|
||||
*/
|
||||
function create_field_path_type_map(array $typeMap, $fieldPath)
|
||||
{
|
||||
// If some field paths already exist, we prefix them with the field path we are assuming as the new root
|
||||
if (isset($typeMap['fieldPaths']) && is_array($typeMap['fieldPaths'])) {
|
||||
$fieldPaths = $typeMap['fieldPaths'];
|
||||
|
||||
$typeMap['fieldPaths'] = [];
|
||||
foreach ($fieldPaths as $existingFieldPath => $type) {
|
||||
$typeMap['fieldPaths'][$fieldPath . '.' . $existingFieldPath] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
// If a root typemap was set, apply this to the field object
|
||||
if (isset($typeMap['root'])) {
|
||||
$typeMap['fieldPaths'][$fieldPath] = $typeMap['root'];
|
||||
}
|
||||
|
||||
/* Special case if we want to convert an array, in which case we need to
|
||||
* ensure that the field containing the array is exposed as an array,
|
||||
* instead of the type given in the type map's array key. */
|
||||
if (substr($fieldPath, -2, 2) === '.$') {
|
||||
$typeMap['fieldPaths'][substr($fieldPath, 0, -2)] = 'array';
|
||||
}
|
||||
|
||||
$typeMap['root'] = 'object';
|
||||
|
||||
return $typeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback within a transaction in the given session
|
||||
*
|
||||
* This helper takes care of retrying the commit operation or the entire
|
||||
* transaction if an error occurs.
|
||||
*
|
||||
* If the commit fails because of an UnknownTransactionCommitResult error, the
|
||||
* commit is retried without re-invoking the callback.
|
||||
* If the commit fails because of a TransientTransactionError, the entire
|
||||
* transaction will be retried. In this case, the callback will be invoked
|
||||
* again. It is important that the logic inside the callback is idempotent.
|
||||
*
|
||||
* In case of failures, the commit or transaction are retried until 120 seconds
|
||||
* from the initial call have elapsed. After that, no retries will happen and
|
||||
* the helper will throw the last exception received from the driver.
|
||||
*
|
||||
* @see Client::startSession
|
||||
* @see Session::startTransaction for supported transaction options
|
||||
*
|
||||
* @param Session $session A session object as retrieved by Client::startSession
|
||||
* @param callable $callback A callback that will be invoked within the transaction
|
||||
* @param array $transactionOptions Additional options that are passed to Session::startTransaction
|
||||
* @return void
|
||||
* @throws RuntimeException for driver errors while committing the transaction
|
||||
* @throws Exception for any other errors, including those thrown in the callback
|
||||
*/
|
||||
function with_transaction(Session $session, callable $callback, array $transactionOptions = [])
|
||||
{
|
||||
$operation = new WithTransaction($callback, $transactionOptions);
|
||||
$operation->execute($session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session option if it is set and valid.
|
||||
*
|
||||
* @internal
|
||||
* @param array $options
|
||||
* @return Session|null
|
||||
*/
|
||||
function extract_session_from_options(array $options)
|
||||
{
|
||||
if (! isset($options['session']) || ! $options['session'] instanceof Session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $options['session'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the readPreference option if it is set and valid.
|
||||
*
|
||||
* @internal
|
||||
* @param array $options
|
||||
* @return ReadPreference|null
|
||||
*/
|
||||
function extract_read_preference_from_options(array $options)
|
||||
{
|
||||
if (! isset($options['readPreference']) || ! $options['readPreference'] instanceof ReadPreference) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $options['readPreference'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs server selection, respecting the readPreference and session options
|
||||
* (if given)
|
||||
*
|
||||
* @internal
|
||||
* @return Server
|
||||
*/
|
||||
function select_server(Manager $manager, array $options)
|
||||
{
|
||||
$session = extract_session_from_options($options);
|
||||
if ($session instanceof Session && $session->getServer() !== null) {
|
||||
return $session->getServer();
|
||||
}
|
||||
|
||||
$readPreference = extract_read_preference_from_options($options);
|
||||
if (! $readPreference instanceof ReadPreference) {
|
||||
// TODO: PHPLIB-476: Read transaction read preference once PHPC-1439 is implemented
|
||||
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
|
||||
}
|
||||
|
||||
return $manager->selectServer($readPreference);
|
||||
}
|
||||
|
8
cache/stores/mongodb/readme_moodle.txt
vendored
8
cache/stores/mongodb/readme_moodle.txt
vendored
@ -1,6 +1,6 @@
|
||||
MongoDB PHP
|
||||
-----------
|
||||
Download from https://github.com/mongodb/mongo-php-library
|
||||
Download from https://github.com/mongodb/mongo-php-library/releases
|
||||
|
||||
Import procedure:
|
||||
|
||||
@ -8,8 +8,4 @@ Import procedure:
|
||||
- Copy the license file from the project root.
|
||||
- Update thirdpartylibs.xml with the latest version.
|
||||
|
||||
2019/03/14
|
||||
----------
|
||||
Last commit on download: aac8e54009196f6544e50baf9b63dcf0eab3bbdf
|
||||
|
||||
This version (1.4.2) requires PHP mongodb extension >= 1.5
|
||||
This version (1.5.1) requires PHP mongodb extension >= 1.6.0
|
||||
|
2
cache/stores/mongodb/thirdpartylibs.xml
vendored
2
cache/stores/mongodb/thirdpartylibs.xml
vendored
@ -4,7 +4,7 @@
|
||||
<location>MongoDB</location>
|
||||
<name>MongoDB PHP Library</name>
|
||||
<license>Apache</license>
|
||||
<version>1.4.2</version>
|
||||
<version>1.5.1</version>
|
||||
<licenseversion>2.0</licenseversion>
|
||||
</library>
|
||||
</libraries>
|
Loading…
x
Reference in New Issue
Block a user