Merge branch 'MDL-54592-master' of git://github.com/vmdef/moodle
This commit is contained in:
@@ -6,6 +6,7 @@ vendor/
|
||||
admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
|
||||
admin/tool/usertours/amd/src/tour.js
|
||||
auth/cas/CAS/
|
||||
cache/stores/mongodb/MongoDB/
|
||||
enrol/lti/ims-blti/
|
||||
filter/algebra/AlgParser.pm
|
||||
filter/tex/mimetex.*
|
||||
|
||||
@@ -9,6 +9,7 @@ vendor/
|
||||
admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
|
||||
admin/tool/usertours/amd/src/tour.js
|
||||
auth/cas/CAS/
|
||||
cache/stores/mongodb/MongoDB/
|
||||
enrol/lti/ims-blti/
|
||||
filter/algebra/AlgParser.pm
|
||||
filter/tex/mimetex.*
|
||||
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
use MongoDB\Driver\WriteResult;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Result class for a bulk write operation.
|
||||
*/
|
||||
class BulkWriteResult
|
||||
{
|
||||
private $writeResult;
|
||||
private $insertedIds;
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
* @param mixed[] $insertedIds
|
||||
*/
|
||||
public function __construct(WriteResult $writeResult, array $insertedIds)
|
||||
{
|
||||
$this->writeResult = $writeResult;
|
||||
$this->insertedIds = $insertedIds;
|
||||
$this->isAcknowledged = $writeResult->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were deleted.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see BulkWriteResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getDeletedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getDeletedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were inserted.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see BulkWriteResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getInsertedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getInsertedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the inserted documents' IDs.
|
||||
*
|
||||
* The index of each ID in the map corresponds to each document's position
|
||||
* in the bulk operation. If a document had an ID prior to inserting (i.e.
|
||||
* the driver did not generate an ID), the index will contain its "_id"
|
||||
* field value. Any driver-generated ID will be a MongoDB\BSON\ObjectId
|
||||
* instance.
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getInsertedIds()
|
||||
{
|
||||
return $this->insertedIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were matched by the filter.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see BulkWriteResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getMatchedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getMatchedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were modified.
|
||||
*
|
||||
* This value is undefined (i.e. null) if the write executed as a legacy
|
||||
* operation instead of command.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see BulkWriteResult::isAcknowledged()
|
||||
* @return integer|null
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getModifiedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getModifiedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were upserted.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see BulkWriteResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getUpsertedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getUpsertedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the upserted documents' IDs.
|
||||
*
|
||||
* The index of each ID in the map corresponds to each document's position
|
||||
* in bulk operation. If a document had an ID prior to upserting (i.e. the
|
||||
* server did not need to generate an ID), this will contain its "_id". Any
|
||||
* server-generated ID will be a MongoDB\BSON\ObjectId instance.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see BulkWriteResult::isAcknowledged()
|
||||
* @return mixed[]
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getUpsertedIds()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getUpsertedIds();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this update was acknowledged by the server.
|
||||
*
|
||||
* If the update was not acknowledged, other fields from the WriteResult
|
||||
* (e.g. matchedCount) will be undefined.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAcknowledged()
|
||||
{
|
||||
return $this->isAcknowledged;
|
||||
}
|
||||
}
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 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;
|
||||
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\Driver\Cursor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Iterator for a change stream.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::watch()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/changeStream/
|
||||
*/
|
||||
class ChangeStream implements Iterator
|
||||
{
|
||||
/**
|
||||
* @deprecated 1.4
|
||||
* @todo Remove this in 2.0 (see: PHPLIB-360)
|
||||
*/
|
||||
const CURSOR_NOT_FOUND = 43;
|
||||
|
||||
private static $errorCodeCappedPositionLost = 136;
|
||||
private static $errorCodeInterrupted = 11601;
|
||||
private static $errorCodeCursorKilled = 237;
|
||||
|
||||
private $resumeToken;
|
||||
private $resumeCallable;
|
||||
private $csIt;
|
||||
private $key = 0;
|
||||
private $hasAdvanced = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @internal
|
||||
* @param Cursor $cursor
|
||||
* @param callable $resumeCallable
|
||||
*/
|
||||
public function __construct(Cursor $cursor, callable $resumeCallable)
|
||||
{
|
||||
$this->resumeCallable = $resumeCallable;
|
||||
$this->csIt = new IteratorIterator($cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.current
|
||||
* @return mixed
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->csIt->current();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \MongoDB\Driver\CursorId
|
||||
*/
|
||||
public function getCursorId()
|
||||
{
|
||||
return $this->csIt->getInnerIterator()->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.key
|
||||
* @return mixed
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
if ($this->valid()) {
|
||||
return $this->key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.next
|
||||
* @return void
|
||||
*/
|
||||
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;
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
if ($this->isResumableError($e)) {
|
||||
$this->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.rewind
|
||||
* @return void
|
||||
*/
|
||||
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;
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
if ($this->isResumableError($e)) {
|
||||
$this->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.valid
|
||||
* @return boolean
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an exception is a resumable error.
|
||||
*
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#resumable-error
|
||||
* @param RuntimeException $exception
|
||||
* @return boolean
|
||||
*/
|
||||
private function isResumableError(RuntimeException $exception)
|
||||
{
|
||||
if ($exception instanceof ConnectionException) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! $exception instanceof ServerException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_array($exception->getCode(), [self::$errorCodeCappedPositionLost, self::$errorCodeCursorKilled, self::$errorCodeInterrupted])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new changeStream after a resumable server error.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function resume()
|
||||
{
|
||||
$newChangeStream = call_user_func($this->resumeCallable, $this->resumeToken);
|
||||
$this->csIt = $newChangeStream->csIt;
|
||||
$this->csIt->rewind();
|
||||
}
|
||||
}
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
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\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
use MongoDB\Model\DatabaseInfoIterator;
|
||||
use MongoDB\Operation\DropDatabase;
|
||||
use MongoDB\Operation\ListDatabases;
|
||||
use MongoDB\Operation\Watch;
|
||||
|
||||
class Client
|
||||
{
|
||||
private static $defaultTypeMap = [
|
||||
'array' => 'MongoDB\Model\BSONArray',
|
||||
'document' => 'MongoDB\Model\BSONDocument',
|
||||
'root' => 'MongoDB\Model\BSONDocument',
|
||||
];
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
private static $wireVersionForWritableCommandWriteConcern = 5;
|
||||
|
||||
private $manager;
|
||||
private $readConcern;
|
||||
private $readPreference;
|
||||
private $uri;
|
||||
private $typeMap;
|
||||
private $writeConcern;
|
||||
|
||||
/**
|
||||
* Constructs a new Client instance.
|
||||
*
|
||||
* This is the preferred class for connecting to a MongoDB server or
|
||||
* cluster of servers. It serves as a gateway for accessing individual
|
||||
* databases and collections.
|
||||
*
|
||||
* Supported driver-specific options:
|
||||
*
|
||||
* * typeMap (array): Default type map for cursors and BSON documents.
|
||||
*
|
||||
* Other options are documented in MongoDB\Driver\Manager::__construct().
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/connection-string/
|
||||
* @see http://php.net/manual/en/mongodb-driver-manager.construct.php
|
||||
* @see http://php.net/manual/en/mongodb.persistence.php#mongodb.persistence.typemaps
|
||||
* @param string $uri MongoDB connection string
|
||||
* @param array $uriOptions Additional connection string options
|
||||
* @param array $driverOptions Driver-specific options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverInvalidArgumentException for parameter/option parsing errors in the driver
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function __construct($uri = 'mongodb://127.0.0.1/', array $uriOptions = [], array $driverOptions = [])
|
||||
{
|
||||
$driverOptions += ['typeMap' => self::$defaultTypeMap];
|
||||
|
||||
if (isset($driverOptions['typeMap']) && ! is_array($driverOptions['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" driver option', $driverOptions['typeMap'], 'array');
|
||||
}
|
||||
|
||||
$this->uri = (string) $uri;
|
||||
$this->typeMap = isset($driverOptions['typeMap']) ? $driverOptions['typeMap'] : null;
|
||||
|
||||
unset($driverOptions['typeMap']);
|
||||
|
||||
$this->manager = new Manager($uri, $uriOptions, $driverOptions);
|
||||
$this->readConcern = $this->manager->getReadConcern();
|
||||
$this->readPreference = $this->manager->getReadPreference();
|
||||
$this->writeConcern = $this->manager->getWriteConcern();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return internal properties for debugging purposes.
|
||||
*
|
||||
* @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return [
|
||||
'manager' => $this->manager,
|
||||
'uri' => $this->uri,
|
||||
'typeMap' => $this->typeMap,
|
||||
'writeConcern' => $this->writeConcern,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a database.
|
||||
*
|
||||
* Note: databases whose names contain special characters (e.g. "-") may
|
||||
* be selected with complex syntax (e.g. $client->{"that-database"}) or
|
||||
* {@link selectDatabase()}.
|
||||
*
|
||||
* @see http://php.net/oop5.overloading#object.get
|
||||
* @see http://php.net/types.string#language.types.string.parsing.complex
|
||||
* @param string $databaseName Name of the database to select
|
||||
* @return Database
|
||||
*/
|
||||
public function __get($databaseName)
|
||||
{
|
||||
return $this->selectDatabase($databaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the connection string (i.e. URI).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a database.
|
||||
*
|
||||
* @see DropDatabase::__construct() for supported options
|
||||
* @param string $databaseName Database name
|
||||
* @param array $options Additional options
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if options are unsupported on the selected server
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function dropDatabase($databaseName, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new DropDatabase($databaseName, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Manager.
|
||||
*
|
||||
* @return Manager
|
||||
*/
|
||||
public function getManager()
|
||||
{
|
||||
return $this->manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the read concern for this client.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php
|
||||
* @return ReadConcern
|
||||
*/
|
||||
public function getReadConcern()
|
||||
{
|
||||
return $this->readConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the read preference for this client.
|
||||
*
|
||||
* @return ReadPreference
|
||||
*/
|
||||
public function getReadPreference()
|
||||
{
|
||||
return $this->readPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type map for this client.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTypeMap()
|
||||
{
|
||||
return $this->typeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the write concern for this client.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php
|
||||
* @return WriteConcern
|
||||
*/
|
||||
public function getWriteConcern()
|
||||
{
|
||||
return $this->writeConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* List databases.
|
||||
*
|
||||
* @see ListDatabases::__construct() for supported options
|
||||
* @return DatabaseInfoIterator
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function listDatabases(array $options = [])
|
||||
{
|
||||
$operation = new ListDatabases($options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a collection.
|
||||
*
|
||||
* @see Collection::__construct() for supported options
|
||||
* @param string $databaseName Name of the database containing the collection
|
||||
* @param string $collectionName Name of the collection to select
|
||||
* @param array $options Collection constructor options
|
||||
* @return Collection
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function selectCollection($databaseName, $collectionName, array $options = [])
|
||||
{
|
||||
$options += ['typeMap' => $this->typeMap];
|
||||
|
||||
return new Collection($this->manager, $databaseName, $collectionName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a database.
|
||||
*
|
||||
* @see Database::__construct() for supported options
|
||||
* @param string $databaseName Name of the database to select
|
||||
* @param array $options Database constructor options
|
||||
* @return Database
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function selectDatabase($databaseName, array $options = [])
|
||||
{
|
||||
$options += ['typeMap' => $this->typeMap];
|
||||
|
||||
return new Database($this->manager, $databaseName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function startSession(array $options = [])
|
||||
{
|
||||
return $this->manager->startSession($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a change stream for watching changes to the cluster.
|
||||
*
|
||||
* @see Watch::__construct() for supported options
|
||||
* @param array $pipeline List of pipeline operations
|
||||
* @param array $options Command options
|
||||
* @return ChangeStream
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function watch(array $pipeline = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$operation = new Watch($this->manager, null, null, $pipeline, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
}
|
||||
+1092
File diff suppressed because it is too large
Load Diff
+463
@@ -0,0 +1,463 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
use MongoDB\Collection;
|
||||
use MongoDB\Driver\Cursor;
|
||||
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\Bucket;
|
||||
use MongoDB\Model\CollectionInfoIterator;
|
||||
use MongoDB\Operation\CreateCollection;
|
||||
use MongoDB\Operation\DatabaseCommand;
|
||||
use MongoDB\Operation\DropCollection;
|
||||
use MongoDB\Operation\DropDatabase;
|
||||
use MongoDB\Operation\ListCollections;
|
||||
use MongoDB\Operation\ModifyCollection;
|
||||
use MongoDB\Operation\Watch;
|
||||
|
||||
class Database
|
||||
{
|
||||
private static $defaultTypeMap = [
|
||||
'array' => 'MongoDB\Model\BSONArray',
|
||||
'document' => 'MongoDB\Model\BSONDocument',
|
||||
'root' => 'MongoDB\Model\BSONDocument',
|
||||
];
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
private static $wireVersionForWritableCommandWriteConcern = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $manager;
|
||||
private $readConcern;
|
||||
private $readPreference;
|
||||
private $typeMap;
|
||||
private $writeConcern;
|
||||
|
||||
/**
|
||||
* Constructs new Database instance.
|
||||
*
|
||||
* This class provides methods for database-specific operations and serves
|
||||
* as a gateway for accessing collections.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * readConcern (MongoDB\Driver\ReadConcern): The default read concern to
|
||||
* use for database operations and selected collections. Defaults to the
|
||||
* Manager's read concern.
|
||||
*
|
||||
* * readPreference (MongoDB\Driver\ReadPreference): The default read
|
||||
* preference to use for database operations and selected collections.
|
||||
* Defaults to the Manager's read preference.
|
||||
*
|
||||
* * typeMap (array): Default type map for cursors and BSON documents.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): The default write concern
|
||||
* to use for database operations and selected collections. Defaults to
|
||||
* the Manager's write concern.
|
||||
*
|
||||
* @param Manager $manager Manager instance from the driver
|
||||
* @param string $databaseName Database name
|
||||
* @param array $options Database options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct(Manager $manager, $databaseName, array $options = [])
|
||||
{
|
||||
if (strlen($databaseName) < 1) {
|
||||
throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName);
|
||||
}
|
||||
|
||||
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['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
$this->manager = $manager;
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern();
|
||||
$this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference();
|
||||
$this->typeMap = isset($options['typeMap']) ? $options['typeMap'] : self::$defaultTypeMap;
|
||||
$this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return internal properties for debugging purposes.
|
||||
*
|
||||
* @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return [
|
||||
'databaseName' => $this->databaseName,
|
||||
'manager' => $this->manager,
|
||||
'readConcern' => $this->readConcern,
|
||||
'readPreference' => $this->readPreference,
|
||||
'typeMap' => $this->typeMap,
|
||||
'writeConcern' => $this->writeConcern,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a collection within this database.
|
||||
*
|
||||
* Note: collections whose names contain special characters (e.g. ".") may
|
||||
* be selected with complex syntax (e.g. $database->{"system.profile"}) or
|
||||
* {@link selectCollection()}.
|
||||
*
|
||||
* @see http://php.net/oop5.overloading#object.get
|
||||
* @see http://php.net/types.string#language.types.string.parsing.complex
|
||||
* @param string $collectionName Name of the collection to select
|
||||
* @return Collection
|
||||
*/
|
||||
public function __get($collectionName)
|
||||
{
|
||||
return $this->selectCollection($collectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command on this database.
|
||||
*
|
||||
* @see DatabaseCommand::__construct() for supported options
|
||||
* @param array|object $command Command document
|
||||
* @param array $options Options for command execution
|
||||
* @return Cursor
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function command($command, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$operation = new DatabaseCommand($this->databaseName, $command, $options);
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new collection explicitly.
|
||||
*
|
||||
* @see CreateCollection::__construct() for supported options
|
||||
* @param string $collectionName
|
||||
* @param array $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
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function createCollection($collectionName, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new CreateCollection($this->databaseName, $collectionName, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop this database.
|
||||
*
|
||||
* @see DropDatabase::__construct() for supported options
|
||||
* @param array $options Additional options
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if options are unsupported on the selected server
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function drop(array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new DropDatabase($this->databaseName, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a collection within this database.
|
||||
*
|
||||
* @see DropCollection::__construct() for supported options
|
||||
* @param string $collectionName Collection name
|
||||
* @param array $options Additional options
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if options are unsupported on the selected server
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function dropCollection($collectionName, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new DropCollection($this->databaseName, $collectionName, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDatabaseName()
|
||||
{
|
||||
return $this->databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Manager.
|
||||
*
|
||||
* @return Manager
|
||||
*/
|
||||
public function getManager()
|
||||
{
|
||||
return $this->manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the read concern for this database.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php
|
||||
* @return ReadConcern
|
||||
*/
|
||||
public function getReadConcern()
|
||||
{
|
||||
return $this->readConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the read preference for this database.
|
||||
*
|
||||
* @return ReadPreference
|
||||
*/
|
||||
public function getReadPreference()
|
||||
{
|
||||
return $this->readPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type map for this database.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTypeMap()
|
||||
{
|
||||
return $this->typeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the write concern for this database.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php
|
||||
* @return WriteConcern
|
||||
*/
|
||||
public function getWriteConcern()
|
||||
{
|
||||
return $this->writeConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information for all collections in this database.
|
||||
*
|
||||
* @see ListCollections::__construct() for supported options
|
||||
* @param array $options
|
||||
* @return CollectionInfoIterator
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function listCollections(array $options = [])
|
||||
{
|
||||
$operation = new ListCollections($this->databaseName, $options);
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies a collection or view.
|
||||
*
|
||||
* @see ModifyCollection::__construct() for supported options
|
||||
* @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
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function modifyCollection($collectionName, array $collectionOptions, array $options = [])
|
||||
{
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
|
||||
|
||||
if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
|
||||
$options['writeConcern'] = $this->writeConcern;
|
||||
}
|
||||
|
||||
$operation = new ModifyCollection($this->databaseName, $collectionName, $collectionOptions, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a collection within this database.
|
||||
*
|
||||
* @see Collection::__construct() for supported options
|
||||
* @param string $collectionName Name of the collection to select
|
||||
* @param array $options Collection constructor options
|
||||
* @return Collection
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function selectCollection($collectionName, array $options = [])
|
||||
{
|
||||
$options += [
|
||||
'readConcern' => $this->readConcern,
|
||||
'readPreference' => $this->readPreference,
|
||||
'typeMap' => $this->typeMap,
|
||||
'writeConcern' => $this->writeConcern,
|
||||
];
|
||||
|
||||
return new Collection($this->manager, $this->databaseName, $collectionName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a GridFS bucket within this database.
|
||||
*
|
||||
* @see Bucket::__construct() for supported options
|
||||
* @param array $options Bucket constructor options
|
||||
* @return Bucket
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function selectGridFSBucket(array $options = [])
|
||||
{
|
||||
$options += [
|
||||
'readConcern' => $this->readConcern,
|
||||
'readPreference' => $this->readPreference,
|
||||
'typeMap' => $this->typeMap,
|
||||
'writeConcern' => $this->writeConcern,
|
||||
];
|
||||
|
||||
return new Bucket($this->manager, $this->databaseName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a change stream for watching changes to the database.
|
||||
*
|
||||
* @see Watch::__construct() for supported options
|
||||
* @param array $pipeline List of pipeline operations
|
||||
* @param array $options Command options
|
||||
* @return ChangeStream
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function watch(array $pipeline = [], array $options = [])
|
||||
{
|
||||
if ( ! isset($options['readPreference'])) {
|
||||
$options['readPreference'] = $this->readPreference;
|
||||
}
|
||||
|
||||
$server = $this->manager->selectServer($options['readPreference']);
|
||||
|
||||
if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
|
||||
$options['readConcern'] = $this->readConcern;
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = $this->typeMap;
|
||||
}
|
||||
|
||||
$operation = new Watch($this->manager, $this->databaseName, null, $pipeline, $options);
|
||||
|
||||
return $operation->execute($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a clone of this database with different options.
|
||||
*
|
||||
* @see Database::__construct() for supported options
|
||||
* @param array $options Database constructor options
|
||||
* @return Database
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function withOptions(array $options = [])
|
||||
{
|
||||
$options += [
|
||||
'readConcern' => $this->readConcern,
|
||||
'readPreference' => $this->readPreference,
|
||||
'typeMap' => $this->typeMap,
|
||||
'writeConcern' => $this->writeConcern,
|
||||
];
|
||||
|
||||
return new Database($this->manager, $this->databaseName, $options);
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
use MongoDB\Driver\WriteResult;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Result class for a delete operation.
|
||||
*/
|
||||
class DeleteResult
|
||||
{
|
||||
private $writeResult;
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
*/
|
||||
public function __construct(WriteResult $writeResult)
|
||||
{
|
||||
$this->writeResult = $writeResult;
|
||||
$this->isAcknowledged = $writeResult->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were deleted.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see DeleteResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getDeletedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getDeletedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this delete was acknowledged by the server.
|
||||
*
|
||||
* If the delete was not acknowledged, other fields from the WriteResult
|
||||
* (e.g. deletedCount) will be undefined.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAcknowledged()
|
||||
{
|
||||
return $this->isAcknowledged;
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Exception;
|
||||
|
||||
class BadMethodCallException extends \BadMethodCallException implements Exception
|
||||
{
|
||||
/**
|
||||
* Thrown when a mutable method is invoked on an immutable object.
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @return self
|
||||
*/
|
||||
public static function classIsImmutable($class)
|
||||
{
|
||||
return new static(sprintf('%s is immutable', $class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when accessing a result field on an unacknowledged write result.
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @return self
|
||||
*/
|
||||
public static function unacknowledgedWriteResultAccess($method)
|
||||
{
|
||||
return new static(sprintf('%s should not be called for an unacknowledged write result', $method));
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Exception;
|
||||
|
||||
interface Exception extends \MongoDB\Driver\Exception\Exception
|
||||
{
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Exception;
|
||||
|
||||
class InvalidArgumentException extends \MongoDB\Driver\Exception\InvalidArgumentException implements Exception
|
||||
{
|
||||
/**
|
||||
* Thrown when an argument or option has an invalid type.
|
||||
*
|
||||
* @param string $name Name of the argument or option
|
||||
* @param mixed $value Actual value (used to derive the type)
|
||||
* @param string $expectedType Expected type
|
||||
* @return self
|
||||
*/
|
||||
public static function invalidType($name, $value, $expectedType)
|
||||
{
|
||||
return new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, is_object($value) ? get_class($value) : gettype($value)));
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Exception;
|
||||
|
||||
class ResumeTokenException extends \Exception
|
||||
{
|
||||
/**
|
||||
* Thrown when a resume token has an invalid type.
|
||||
*
|
||||
* @param mixed $value Actual value (used to derive the type)
|
||||
* @return self
|
||||
*/
|
||||
public static function invalidType($value)
|
||||
{
|
||||
return new static(sprintf('Expected resume token to have type "array or object" but found "%s"', gettype($value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a resume token is not found in a change document.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function notFound()
|
||||
{
|
||||
return new static('Resume token not found in change document');
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Exception;
|
||||
|
||||
class RuntimeException extends \MongoDB\Driver\Exception\RuntimeException implements Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Exception;
|
||||
|
||||
class UnexpectedValueException extends \MongoDB\Driver\Exception\UnexpectedValueException implements Exception
|
||||
{
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Exception;
|
||||
|
||||
class UnsupportedException extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* Thrown when array filters are not supported by a server.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function arrayFiltersNotSupported()
|
||||
{
|
||||
return new static('Array filters are not supported by the server executing this operation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when collations are not supported by a server.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function collationNotSupported()
|
||||
{
|
||||
return new static('Collations are not supported by the server executing this operation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when explain is not supported by a server.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function explainNotSupported()
|
||||
{
|
||||
return new static('Explain is not supported by the server executing this operation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a command's readConcern option is not supported by a server.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function readConcernNotSupported()
|
||||
{
|
||||
return new static('Read concern is not supported by the server executing this command');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a command's writeConcern option is not supported by a server.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function writeConcernNotSupported()
|
||||
{
|
||||
return new static('Write concern is not supported by the server executing this command');
|
||||
}
|
||||
}
|
||||
+677
@@ -0,0 +1,677 @@
|
||||
<?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\GridFS;
|
||||
|
||||
use MongoDB\Collection;
|
||||
use MongoDB\Driver\Cursor;
|
||||
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\GridFS\Exception\CorruptFileException;
|
||||
use MongoDB\GridFS\Exception\FileNotFoundException;
|
||||
use MongoDB\Operation\Find;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Bucket provides a public API for interacting with the GridFS files and chunks
|
||||
* collections.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Bucket
|
||||
{
|
||||
private static $defaultBucketName = 'fs';
|
||||
private static $defaultChunkSizeBytes = 261120;
|
||||
private static $defaultTypeMap = [
|
||||
'array' => 'MongoDB\Model\BSONArray',
|
||||
'document' => 'MongoDB\Model\BSONDocument',
|
||||
'root' => 'MongoDB\Model\BSONDocument',
|
||||
];
|
||||
private static $streamWrapperProtocol = 'gridfs';
|
||||
|
||||
private $collectionWrapper;
|
||||
private $databaseName;
|
||||
private $manager;
|
||||
private $bucketName;
|
||||
private $disableMD5;
|
||||
private $chunkSizeBytes;
|
||||
private $readConcern;
|
||||
private $readPreference;
|
||||
private $typeMap;
|
||||
private $writeConcern;
|
||||
|
||||
/**
|
||||
* Constructs a GridFS bucket.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * bucketName (string): The bucket name, which will be used as a prefix
|
||||
* for the files and chunks collections. Defaults to "fs".
|
||||
*
|
||||
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to
|
||||
* 261120 (i.e. 255 KiB).
|
||||
*
|
||||
* * disableMD5 (boolean): When true, no MD5 sum will be generated for
|
||||
* each stored file. Defaults to "false".
|
||||
*
|
||||
* * readConcern (MongoDB\Driver\ReadConcern): Read concern.
|
||||
*
|
||||
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
|
||||
*
|
||||
* * typeMap (array): Default type map for cursors and BSON documents.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param Manager $manager Manager instance from the driver
|
||||
* @param string $databaseName Database name
|
||||
* @param array $options Bucket options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct(Manager $manager, $databaseName, array $options = [])
|
||||
{
|
||||
$options += [
|
||||
'bucketName' => self::$defaultBucketName,
|
||||
'chunkSizeBytes' => self::$defaultChunkSizeBytes,
|
||||
'disableMD5' => false,
|
||||
];
|
||||
|
||||
if (isset($options['bucketName']) && ! is_string($options['bucketName'])) {
|
||||
throw InvalidArgumentException::invalidType('"bucketName" option', $options['bucketName'], 'string');
|
||||
}
|
||||
|
||||
if (isset($options['chunkSizeBytes']) && ! is_integer($options['chunkSizeBytes'])) {
|
||||
throw InvalidArgumentException::invalidType('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['chunkSizeBytes']) && $options['chunkSizeBytes'] < 1) {
|
||||
throw new InvalidArgumentException(sprintf('Expected "chunkSizeBytes" option to be >= 1, %d given', $options['chunkSizeBytes']));
|
||||
}
|
||||
|
||||
if (isset($options['disableMD5']) && ! is_bool($options['disableMD5'])) {
|
||||
throw InvalidArgumentException::invalidType('"disableMD5" option', $options['disableMD5'], 'boolean');
|
||||
}
|
||||
|
||||
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['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
$this->manager = $manager;
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->bucketName = $options['bucketName'];
|
||||
$this->chunkSizeBytes = $options['chunkSizeBytes'];
|
||||
$this->disableMD5 = $options['disableMD5'];
|
||||
$this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern();
|
||||
$this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference();
|
||||
$this->typeMap = isset($options['typeMap']) ? $options['typeMap'] : self::$defaultTypeMap;
|
||||
$this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern();
|
||||
|
||||
$collectionOptions = array_intersect_key($options, ['readConcern' => 1, 'readPreference' => 1, 'typeMap' => 1, 'writeConcern' => 1]);
|
||||
|
||||
$this->collectionWrapper = new CollectionWrapper($manager, $databaseName, $options['bucketName'], $collectionOptions);
|
||||
$this->registerStreamWrapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return internal properties for debugging purposes.
|
||||
*
|
||||
* @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return [
|
||||
'bucketName' => $this->bucketName,
|
||||
'databaseName' => $this->databaseName,
|
||||
'manager' => $this->manager,
|
||||
'chunkSizeBytes' => $this->chunkSizeBytes,
|
||||
'readConcern' => $this->readConcern,
|
||||
'readPreference' => $this->readPreference,
|
||||
'typeMap' => $this->typeMap,
|
||||
'writeConcern' => $this->writeConcern,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file from the GridFS bucket.
|
||||
*
|
||||
* If the files collection document is not found, this method will still
|
||||
* attempt to delete orphaned chunks.
|
||||
*
|
||||
* @param mixed $id File ID
|
||||
* @throws FileNotFoundException if no file could be selected
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$file = $this->collectionWrapper->findFileById($id);
|
||||
$this->collectionWrapper->deleteFileAndChunksById($id);
|
||||
|
||||
if ($file === null) {
|
||||
throw FileNotFoundException::byId($id, $this->getFilesNamespace());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents of a GridFS file to a writable stream.
|
||||
*
|
||||
* @param mixed $id File ID
|
||||
* @param resource $destination Writable Stream
|
||||
* @throws FileNotFoundException if no file could be selected
|
||||
* @throws InvalidArgumentException if $destination is not a stream
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function downloadToStream($id, $destination)
|
||||
{
|
||||
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
|
||||
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
|
||||
}
|
||||
|
||||
stream_copy_to_stream($this->openDownloadStream($id), $destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents of a GridFS file, which is selected by name and
|
||||
* revision, to a writable stream.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * revision (integer): Which revision (i.e. documents with the same
|
||||
* filename and different uploadDate) of the file to retrieve. Defaults
|
||||
* to -1 (i.e. the most recent revision).
|
||||
*
|
||||
* Revision numbers are defined as follows:
|
||||
*
|
||||
* * 0 = the original stored file
|
||||
* * 1 = the first revision
|
||||
* * 2 = the second revision
|
||||
* * etc…
|
||||
* * -2 = the second most recent revision
|
||||
* * -1 = the most recent revision
|
||||
*
|
||||
* @param string $filename Filename
|
||||
* @param resource $destination Writable Stream
|
||||
* @param array $options Download options
|
||||
* @throws FileNotFoundException if no file could be selected
|
||||
* @throws InvalidArgumentException if $destination is not a stream
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function downloadToStreamByName($filename, $destination, array $options = [])
|
||||
{
|
||||
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
|
||||
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
|
||||
}
|
||||
|
||||
stream_copy_to_stream($this->openDownloadStreamByName($filename, $options), $destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the files and chunks collections associated with this GridFS
|
||||
* bucket.
|
||||
*
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function drop()
|
||||
{
|
||||
$this->collectionWrapper->dropCollections();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds documents from the GridFS bucket's files collection matching the
|
||||
* query.
|
||||
*
|
||||
* @see Find::__construct() for supported options
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Additional options
|
||||
* @return Cursor
|
||||
* @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 find($filter = [], array $options = [])
|
||||
{
|
||||
return $this->collectionWrapper->findFiles($filter, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a single document from the GridFS bucket's files collection
|
||||
* matching the query.
|
||||
*
|
||||
* @see FindOne::__construct() for supported options
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Additional options
|
||||
* @return array|object|null
|
||||
* @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 findOne($filter = [], array $options = [])
|
||||
{
|
||||
return $this->collectionWrapper->findOneFile($filter, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bucket name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBucketName()
|
||||
{
|
||||
return $this->bucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the chunks collection.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getChunksCollection()
|
||||
{
|
||||
return $this->collectionWrapper->getChunksCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the chunk size in bytes.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getChunkSizeBytes()
|
||||
{
|
||||
return $this->chunkSizeBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDatabaseName()
|
||||
{
|
||||
return $this->databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file document of the GridFS file associated with a stream.
|
||||
*
|
||||
* @param resource $stream GridFS stream
|
||||
* @return array|object
|
||||
* @throws InvalidArgumentException if $stream is not a GridFS stream
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function getFileDocumentForStream($stream)
|
||||
{
|
||||
$file = $this->getRawFileDocumentForStream($stream);
|
||||
|
||||
// Filter the raw document through the specified type map
|
||||
return \MongoDB\apply_type_map_to_document($file, $this->typeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file document's ID of the GridFS file associated with a stream.
|
||||
*
|
||||
* @param resource $stream GridFS stream
|
||||
* @return mixed
|
||||
* @throws CorruptFileException if the file "_id" field does not exist
|
||||
* @throws InvalidArgumentException if $stream is not a GridFS stream
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function getFileIdForStream($stream)
|
||||
{
|
||||
$file = $this->getRawFileDocumentForStream($stream);
|
||||
|
||||
/* Filter the raw document through the specified type map, but override
|
||||
* the root type so we can reliably access the ID.
|
||||
*/
|
||||
$typeMap = ['root' => 'stdClass'] + $this->typeMap;
|
||||
$file = \MongoDB\apply_type_map_to_document($file, $typeMap);
|
||||
|
||||
if ( ! isset($file->_id) && ! property_exists($file, '_id')) {
|
||||
throw new CorruptFileException('file._id does not exist');
|
||||
}
|
||||
|
||||
return $file->_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the files collection.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getFilesCollection()
|
||||
{
|
||||
return $this->collectionWrapper->getFilesCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the read concern for this GridFS bucket.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php
|
||||
* @return ReadConcern
|
||||
*/
|
||||
public function getReadConcern()
|
||||
{
|
||||
return $this->readConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the read preference for this GridFS bucket.
|
||||
*
|
||||
* @return ReadPreference
|
||||
*/
|
||||
public function getReadPreference()
|
||||
{
|
||||
return $this->readPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type map for this GridFS bucket.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTypeMap()
|
||||
{
|
||||
return $this->typeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the write concern for this GridFS bucket.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php
|
||||
* @return WriteConcern
|
||||
*/
|
||||
public function getWriteConcern()
|
||||
{
|
||||
return $this->writeConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a readable stream for reading a GridFS file.
|
||||
*
|
||||
* @param mixed $id File ID
|
||||
* @return resource
|
||||
* @throws FileNotFoundException if no file could be selected
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function openDownloadStream($id)
|
||||
{
|
||||
$file = $this->collectionWrapper->findFileById($id);
|
||||
|
||||
if ($file === null) {
|
||||
throw FileNotFoundException::byId($id, $this->getFilesNamespace());
|
||||
}
|
||||
|
||||
return $this->openDownloadStreamByFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a readable stream stream to read a GridFS file, which is selected
|
||||
* by name and revision.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * revision (integer): Which revision (i.e. documents with the same
|
||||
* filename and different uploadDate) of the file to retrieve. Defaults
|
||||
* to -1 (i.e. the most recent revision).
|
||||
*
|
||||
* Revision numbers are defined as follows:
|
||||
*
|
||||
* * 0 = the original stored file
|
||||
* * 1 = the first revision
|
||||
* * 2 = the second revision
|
||||
* * etc…
|
||||
* * -2 = the second most recent revision
|
||||
* * -1 = the most recent revision
|
||||
*
|
||||
* @param string $filename Filename
|
||||
* @param array $options Download options
|
||||
* @return resource
|
||||
* @throws FileNotFoundException if no file could be selected
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function openDownloadStreamByName($filename, array $options = [])
|
||||
{
|
||||
$options += ['revision' => -1];
|
||||
|
||||
$file = $this->collectionWrapper->findFileByFilenameAndRevision($filename, $options['revision']);
|
||||
|
||||
if ($file === null) {
|
||||
throw FileNotFoundException::byFilenameAndRevision($filename, $options['revision'], $this->getFilesNamespace());
|
||||
}
|
||||
|
||||
return $this->openDownloadStreamByFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a writable stream for writing a GridFS file.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * _id (mixed): File document identifier. Defaults to a new ObjectId.
|
||||
*
|
||||
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to the
|
||||
* bucket's chunk size.
|
||||
*
|
||||
* * disableMD5 (boolean): When true, no MD5 sum will be generated for
|
||||
* the stored file. Defaults to "false".
|
||||
*
|
||||
* * metadata (document): User data for the "metadata" field of the files
|
||||
* collection document.
|
||||
*
|
||||
* @param string $filename Filename
|
||||
* @param array $options Upload options
|
||||
* @return resource
|
||||
*/
|
||||
public function openUploadStream($filename, array $options = [])
|
||||
{
|
||||
$options += ['chunkSizeBytes' => $this->chunkSizeBytes];
|
||||
|
||||
$path = $this->createPathForUpload();
|
||||
$context = stream_context_create([
|
||||
self::$streamWrapperProtocol => [
|
||||
'collectionWrapper' => $this->collectionWrapper,
|
||||
'filename' => $filename,
|
||||
'options' => $options,
|
||||
],
|
||||
]);
|
||||
|
||||
return fopen($path, 'w', false, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the GridFS file with the specified ID.
|
||||
*
|
||||
* @param mixed $id File ID
|
||||
* @param string $newFilename New filename
|
||||
* @throws FileNotFoundException if no file could be selected
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function rename($id, $newFilename)
|
||||
{
|
||||
$updateResult = $this->collectionWrapper->updateFilenameForId($id, $newFilename);
|
||||
|
||||
if ($updateResult->getModifiedCount() === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the update resulted in no modification, it's possible that the
|
||||
* file did not exist, in which case we must raise an error. Checking
|
||||
* the write result's matched count will be most efficient, but fall
|
||||
* back to a findOne operation if necessary (i.e. legacy writes).
|
||||
*/
|
||||
$found = $updateResult->getMatchedCount() !== null
|
||||
? $updateResult->getMatchedCount() === 1
|
||||
: $this->collectionWrapper->findFileById($id) !== null;
|
||||
|
||||
if ( ! $found) {
|
||||
throw FileNotFoundException::byId($id, $this->getFilesNamespace());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents of a readable stream to a GridFS file.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * _id (mixed): File document identifier. Defaults to a new ObjectId.
|
||||
*
|
||||
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to the
|
||||
* bucket's chunk size.
|
||||
*
|
||||
* * disableMD5 (boolean): When true, no MD5 sum will be generated for
|
||||
* the stored file. Defaults to "false".
|
||||
*
|
||||
* * metadata (document): User data for the "metadata" field of the files
|
||||
* collection document.
|
||||
*
|
||||
* @param string $filename Filename
|
||||
* @param resource $source Readable stream
|
||||
* @param array $options Stream options
|
||||
* @return mixed ID of the newly created GridFS file
|
||||
* @throws InvalidArgumentException if $source is not a GridFS stream
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function uploadFromStream($filename, $source, array $options = [])
|
||||
{
|
||||
if ( ! is_resource($source) || get_resource_type($source) != "stream") {
|
||||
throw InvalidArgumentException::invalidType('$source', $source, 'resource');
|
||||
}
|
||||
|
||||
$destination = $this->openUploadStream($filename, $options);
|
||||
stream_copy_to_stream($source, $destination);
|
||||
|
||||
return $this->getFileIdForStream($destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path for an existing GridFS file.
|
||||
*
|
||||
* @param stdClass $file GridFS file document
|
||||
* @return string
|
||||
*/
|
||||
private function createPathForFile(stdClass $file)
|
||||
{
|
||||
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]));
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'%s://%s/%s.files/%s',
|
||||
self::$streamWrapperProtocol,
|
||||
urlencode($this->databaseName),
|
||||
urlencode($this->bucketName),
|
||||
urlencode($id)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path for a new GridFS file, which does not yet have an ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createPathForUpload()
|
||||
{
|
||||
return sprintf(
|
||||
'%s://%s/%s.files',
|
||||
self::$streamWrapperProtocol,
|
||||
urlencode($this->databaseName),
|
||||
urlencode($this->bucketName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the files collection.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getFilesNamespace()
|
||||
{
|
||||
return sprintf('%s.%s.files', $this->databaseName, $this->bucketName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file document of the GridFS file associated with a stream.
|
||||
*
|
||||
* This returns the raw document from the StreamWrapper, which does not
|
||||
* respect the Bucket's type map.
|
||||
*
|
||||
* @param resource $stream GridFS stream
|
||||
* @return stdClass
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function getRawFileDocumentForStream($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');
|
||||
}
|
||||
|
||||
return $metadata['wrapper_data']->getFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a readable stream for the GridFS file.
|
||||
*
|
||||
* @param stdClass $file GridFS file document
|
||||
* @return resource
|
||||
*/
|
||||
private function openDownloadStreamByFile(stdClass $file)
|
||||
{
|
||||
$path = $this->createPathForFile($file);
|
||||
$context = stream_context_create([
|
||||
self::$streamWrapperProtocol => [
|
||||
'collectionWrapper' => $this->collectionWrapper,
|
||||
'file' => $file,
|
||||
],
|
||||
]);
|
||||
|
||||
return fopen($path, 'r', false, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the GridFS stream wrapper if it is not already registered.
|
||||
*/
|
||||
private function registerStreamWrapper()
|
||||
{
|
||||
if (in_array(self::$streamWrapperProtocol, stream_get_wrappers())) {
|
||||
return;
|
||||
}
|
||||
|
||||
StreamWrapper::register(self::$streamWrapperProtocol);
|
||||
}
|
||||
}
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
<?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\GridFS;
|
||||
|
||||
use MongoDB\Collection;
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* CollectionWrapper abstracts the GridFS files and chunks collections.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CollectionWrapper
|
||||
{
|
||||
private $bucketName;
|
||||
private $chunksCollection;
|
||||
private $databaseName;
|
||||
private $checkedIndexes = false;
|
||||
private $filesCollection;
|
||||
|
||||
/**
|
||||
* Constructs a GridFS collection wrapper.
|
||||
*
|
||||
* @see Collection::__construct() for supported options
|
||||
* @param Manager $manager Manager instance from the driver
|
||||
* @param string $databaseName Database name
|
||||
* @param string $bucketName Bucket name
|
||||
* @param array $collectionOptions Collection options
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(Manager $manager, $databaseName, $bucketName, array $collectionOptions = [])
|
||||
{
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->bucketName = (string) $bucketName;
|
||||
|
||||
$this->filesCollection = new Collection($manager, $databaseName, sprintf('%s.files', $bucketName), $collectionOptions);
|
||||
$this->chunksCollection = new Collection($manager, $databaseName, sprintf('%s.chunks', $bucketName), $collectionOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all GridFS chunks for a given file ID.
|
||||
*
|
||||
* @param mixed $id
|
||||
*/
|
||||
public function deleteChunksByFilesId($id)
|
||||
{
|
||||
$this->chunksCollection->deleteMany(['files_id' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a GridFS file and related chunks by ID.
|
||||
*
|
||||
* @param mixed $id
|
||||
*/
|
||||
public function deleteFileAndChunksById($id)
|
||||
{
|
||||
$this->filesCollection->deleteOne(['_id' => $id]);
|
||||
$this->chunksCollection->deleteMany(['files_id' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the GridFS files and chunks collections.
|
||||
*/
|
||||
public function dropCollections()
|
||||
{
|
||||
$this->filesCollection->drop(['typeMap' => []]);
|
||||
$this->chunksCollection->drop(['typeMap' => []]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds GridFS chunk documents for a given file ID and optional offset.
|
||||
*
|
||||
* @param mixed $id File ID
|
||||
* @param integer $fromChunk Starting chunk (inclusive)
|
||||
* @return Cursor
|
||||
*/
|
||||
public function findChunksByFileId($id, $fromChunk = 0)
|
||||
{
|
||||
return $this->chunksCollection->find(
|
||||
[
|
||||
'files_id' => $id,
|
||||
'n' => ['$gte' => $fromChunk],
|
||||
],
|
||||
[
|
||||
'sort' => ['n' => 1],
|
||||
'typeMap' => ['root' => 'stdClass'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a GridFS file document for a given filename and revision.
|
||||
*
|
||||
* Revision numbers are defined as follows:
|
||||
*
|
||||
* * 0 = the original stored file
|
||||
* * 1 = the first revision
|
||||
* * 2 = the second revision
|
||||
* * etc…
|
||||
* * -2 = the second most recent revision
|
||||
* * -1 = the most recent revision
|
||||
*
|
||||
* @see Bucket::downloadToStreamByName()
|
||||
* @see Bucket::openDownloadStreamByName()
|
||||
* @param string $filename
|
||||
* @param integer $revision
|
||||
* @return stdClass|null
|
||||
*/
|
||||
public function findFileByFilenameAndRevision($filename, $revision)
|
||||
{
|
||||
$filename = (string) $filename;
|
||||
$revision = (integer) $revision;
|
||||
|
||||
if ($revision < 0) {
|
||||
$skip = abs($revision) - 1;
|
||||
$sortOrder = -1;
|
||||
} else {
|
||||
$skip = $revision;
|
||||
$sortOrder = 1;
|
||||
}
|
||||
|
||||
return $this->filesCollection->findOne(
|
||||
['filename' => $filename],
|
||||
[
|
||||
'skip' => $skip,
|
||||
'sort' => ['uploadDate' => $sortOrder],
|
||||
'typeMap' => ['root' => 'stdClass'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a GridFS file document for a given ID.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @return stdClass|null
|
||||
*/
|
||||
public function findFileById($id)
|
||||
{
|
||||
return $this->filesCollection->findOne(
|
||||
['_id' => $id],
|
||||
['typeMap' => ['root' => 'stdClass']]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds documents from the GridFS bucket's files collection.
|
||||
*
|
||||
* @see Find::__construct() for supported options
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Additional options
|
||||
* @return Cursor
|
||||
*/
|
||||
public function findFiles($filter, array $options = [])
|
||||
{
|
||||
return $this->filesCollection->find($filter, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a single document from the GridFS bucket's files collection.
|
||||
*
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Additional options
|
||||
* @return array|object|null
|
||||
*/
|
||||
public function findOneFile($filter, array $options = [])
|
||||
{
|
||||
return $this->filesCollection->findOne($filter, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bucket name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBucketName()
|
||||
{
|
||||
return $this->bucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the chunks collection.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getChunksCollection()
|
||||
{
|
||||
return $this->chunksCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDatabaseName()
|
||||
{
|
||||
return $this->databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the files collection.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getFilesCollection()
|
||||
{
|
||||
return $this->filesCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a document into the chunks collection.
|
||||
*
|
||||
* @param array|object $chunk Chunk document
|
||||
*/
|
||||
public function insertChunk($chunk)
|
||||
{
|
||||
if ( ! $this->checkedIndexes) {
|
||||
$this->ensureIndexes();
|
||||
}
|
||||
|
||||
$this->chunksCollection->insertOne($chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a document into the files collection.
|
||||
*
|
||||
* The file document should be inserted after all chunks have been inserted.
|
||||
*
|
||||
* @param array|object $file File document
|
||||
*/
|
||||
public function insertFile($file)
|
||||
{
|
||||
if ( ! $this->checkedIndexes) {
|
||||
$this->ensureIndexes();
|
||||
}
|
||||
|
||||
$this->filesCollection->insertOne($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the filename field in the file document for a given ID.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param string $filename
|
||||
* @return UpdateResult
|
||||
*/
|
||||
public function updateFilenameForId($id, $filename)
|
||||
{
|
||||
return $this->filesCollection->updateOne(
|
||||
['_id' => $id],
|
||||
['$set' => ['filename' => (string) $filename]]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an index on the chunks collection if it does not already exist.
|
||||
*/
|
||||
private function ensureChunksIndex()
|
||||
{
|
||||
foreach ($this->chunksCollection->listIndexes() as $index) {
|
||||
if ($index->isUnique() && $index->getKey() === ['files_id' => 1, 'n' => 1]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->chunksCollection->createIndex(['files_id' => 1, 'n' => 1], ['unique' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an index on the files collection if it does not already exist.
|
||||
*/
|
||||
private function ensureFilesIndex()
|
||||
{
|
||||
foreach ($this->filesCollection->listIndexes() as $index) {
|
||||
if ($index->getKey() === ['filename' => 1, 'uploadDate' => 1]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->filesCollection->createIndex(['filename' => 1, 'uploadDate' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure indexes on the files and chunks collections exist.
|
||||
*
|
||||
* This method is called once before the first write operation on a GridFS
|
||||
* bucket. Indexes are only be created if the files collection is empty.
|
||||
*/
|
||||
private function ensureIndexes()
|
||||
{
|
||||
if ($this->checkedIndexes) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->checkedIndexes = true;
|
||||
|
||||
if ( ! $this->isFilesCollectionEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->ensureFilesIndex();
|
||||
$this->ensureChunksIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the files collection is empty.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function isFilesCollectionEmpty()
|
||||
{
|
||||
return null === $this->filesCollection->findOne([], [
|
||||
'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
|
||||
'projection' => ['_id' => 1],
|
||||
'typeMap' => [],
|
||||
]);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
<?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\GridFS\Exception;
|
||||
|
||||
use MongoDB\Exception\RuntimeException;
|
||||
|
||||
class CorruptFileException extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* Thrown when a chunk is not found for an expected index.
|
||||
*
|
||||
* @param integer $expectedIndex Expected index number
|
||||
* @return self
|
||||
*/
|
||||
public static function missingChunk($expectedIndex)
|
||||
{
|
||||
return new static(sprintf('Chunk not found for index "%d"', $expectedIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a chunk has an unexpected index number.
|
||||
*
|
||||
* @param integer $index Actual index number (i.e. "n" field)
|
||||
* @param integer $expectedIndex Expected index number
|
||||
* @return self
|
||||
*/
|
||||
public static function unexpectedIndex($index, $expectedIndex)
|
||||
{
|
||||
return new static(sprintf('Expected chunk to have index "%d" but found "%d"', $expectedIndex, $index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a chunk has an unexpected data size.
|
||||
*
|
||||
* @param integer $size Actual size (i.e. "data" field length)
|
||||
* @param integer $expectedSize Expected size
|
||||
* @return self
|
||||
*/
|
||||
public static function unexpectedSize($size, $expectedSize)
|
||||
{
|
||||
return new static(sprintf('Expected chunk to have size "%d" but found "%d"', $expectedSize, $size));
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<?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\GridFS\Exception;
|
||||
|
||||
use MongoDB\Exception\RuntimeException;
|
||||
|
||||
class FileNotFoundException extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* Thrown when a file cannot be found by its filename and revision.
|
||||
*
|
||||
* @param string $filename Filename
|
||||
* @param integer $revision Revision
|
||||
* @param string $namespace Namespace for the files collection
|
||||
* @return self
|
||||
*/
|
||||
public static function byFilenameAndRevision($filename, $revision, $namespace)
|
||||
{
|
||||
return new static(sprintf('File with name "%s" and revision "%d" not found in "%s"', $filename, $revision, $namespace));
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a file cannot be found by its ID.
|
||||
*
|
||||
* @param mixed $id File ID
|
||||
* @param string $namespace Namespace for the files collection
|
||||
* @return self
|
||||
*/
|
||||
public static function byId($id, $namespace)
|
||||
{
|
||||
$json = \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP(['_id' => $id]));
|
||||
|
||||
return new static(sprintf('File "%s" not found in "%s"', $json, $namespace));
|
||||
}
|
||||
}
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
<?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\GridFS;
|
||||
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\GridFS\Exception\CorruptFileException;
|
||||
use IteratorIterator;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* ReadableStream abstracts the process of reading a GridFS file.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ReadableStream
|
||||
{
|
||||
private $buffer;
|
||||
private $bufferOffset = 0;
|
||||
private $chunkSize;
|
||||
private $chunkOffset = 0;
|
||||
private $chunksIterator;
|
||||
private $collectionWrapper;
|
||||
private $expectedLastChunkSize = 0;
|
||||
private $file;
|
||||
private $length;
|
||||
private $numChunks = 0;
|
||||
|
||||
/**
|
||||
* Constructs a readable GridFS stream.
|
||||
*
|
||||
* @param CollectionWrapper $collectionWrapper GridFS collection wrapper
|
||||
* @param stdClass $file GridFS file document
|
||||
* @throws CorruptFileException
|
||||
*/
|
||||
public function __construct(CollectionWrapper $collectionWrapper, stdClass $file)
|
||||
{
|
||||
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) {
|
||||
throw new CorruptFileException('file.length is not an integer > 0');
|
||||
}
|
||||
|
||||
if ( ! isset($file->_id) && ! property_exists($file, '_id')) {
|
||||
throw new CorruptFileException('file._id does not exist');
|
||||
}
|
||||
|
||||
$this->file = $file;
|
||||
$this->chunkSize = (integer) $file->chunkSize;
|
||||
$this->length = (integer) $file->length;
|
||||
|
||||
$this->collectionWrapper = $collectionWrapper;
|
||||
|
||||
if ($this->length > 0) {
|
||||
$this->numChunks = (integer) ceil($this->length / $this->chunkSize);
|
||||
$this->expectedLastChunkSize = ($this->length - (($this->numChunks - 1) * $this->chunkSize));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return internal properties for debugging purposes.
|
||||
*
|
||||
* @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return [
|
||||
'bucketName' => $this->collectionWrapper->getBucketName(),
|
||||
'databaseName' => $this->collectionWrapper->getDatabaseName(),
|
||||
'file' => $this->file,
|
||||
];
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the stream's file document.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the stream's size in bytes.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the current read position is at the end of the stream.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEOF()
|
||||
{
|
||||
if ($this->chunkOffset === $this->numChunks - 1) {
|
||||
return $this->bufferOffset >= $this->expectedLastChunkSize;
|
||||
}
|
||||
|
||||
return $this->chunkOffset >= $this->numChunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read bytes from the stream.
|
||||
*
|
||||
* Note: this method may return a string smaller than the requested length
|
||||
* if data is not available to be read.
|
||||
*
|
||||
* @param integer $length Number of bytes to read
|
||||
* @return string
|
||||
* @throws InvalidArgumentException if $length is negative
|
||||
*/
|
||||
public function readBytes($length)
|
||||
{
|
||||
if ($length < 0) {
|
||||
throw new InvalidArgumentException(sprintf('$length must be >= 0; given: %d', $length));
|
||||
}
|
||||
|
||||
if ($this->chunksIterator === null) {
|
||||
$this->initChunksIterator();
|
||||
}
|
||||
|
||||
if ($this->buffer === null && ! $this->initBufferFromCurrentChunk()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$data = '';
|
||||
|
||||
while (strlen($data) < $length) {
|
||||
if ($this->bufferOffset >= strlen($this->buffer) && ! $this->initBufferFromNextChunk()) {
|
||||
break;
|
||||
}
|
||||
|
||||
$initialDataLength = strlen($data);
|
||||
$data .= substr($this->buffer, $this->bufferOffset, $length - $initialDataLength);
|
||||
$this->bufferOffset += strlen($data) - $initialDataLength;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks the chunk and buffer offsets for the next read operation.
|
||||
*
|
||||
* @param integer $offset
|
||||
* @throws InvalidArgumentException if $offset is out of range
|
||||
*/
|
||||
public function seek($offset)
|
||||
{
|
||||
if ($offset < 0 || $offset > $this->file->length) {
|
||||
throw new InvalidArgumentException(sprintf('$offset must be >= 0 and <= %d; given: %d', $this->file->length, $offset));
|
||||
}
|
||||
|
||||
/* Compute the offsets for the chunk and buffer (i.e. chunk data) from
|
||||
* which we will expect to read after seeking. If the chunk offset
|
||||
* changed, we'll also need to reset the buffer.
|
||||
*/
|
||||
$lastChunkOffset = $this->chunkOffset;
|
||||
$this->chunkOffset = (integer) floor($offset / $this->chunkSize);
|
||||
$this->bufferOffset = $offset % $this->chunkSize;
|
||||
|
||||
if ($lastChunkOffset === $this->chunkOffset) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->chunksIterator === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the buffer since the current chunk will be changed
|
||||
$this->buffer = null;
|
||||
|
||||
/* If we are seeking to a previous chunk, we need to reinitialize the
|
||||
* chunk iterator.
|
||||
*/
|
||||
if ($lastChunkOffset > $this->chunkOffset) {
|
||||
$this->chunksIterator = null;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we are seeking to a subsequent chunk, we do not need to
|
||||
* reinitalize the chunk iterator. Instead, we can simply move forward
|
||||
* to $this->chunkOffset.
|
||||
*/
|
||||
$numChunks = $this->chunkOffset - $lastChunkOffset;
|
||||
for ($i = 0; $i < $numChunks; $i++) {
|
||||
$this->chunksIterator->next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current position of the stream.
|
||||
*
|
||||
* This is the offset within the stream where the next byte would be read.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function tell()
|
||||
{
|
||||
return ($this->chunkOffset * $this->chunkSize) + $this->bufferOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the buffer to the current chunk's data.
|
||||
*
|
||||
* @return boolean Whether there was a current chunk to read
|
||||
* @throws CorruptFileException if an expected chunk could not be read successfully
|
||||
*/
|
||||
private function initBufferFromCurrentChunk()
|
||||
{
|
||||
if ($this->chunkOffset === 0 && $this->numChunks === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->chunksIterator->valid()) {
|
||||
throw CorruptFileException::missingChunk($this->chunkOffset);
|
||||
}
|
||||
|
||||
$currentChunk = $this->chunksIterator->current();
|
||||
|
||||
if ($currentChunk->n !== $this->chunkOffset) {
|
||||
throw CorruptFileException::unexpectedIndex($currentChunk->n, $this->chunkOffset);
|
||||
}
|
||||
|
||||
$this->buffer = $currentChunk->data->getData();
|
||||
|
||||
$actualChunkSize = strlen($this->buffer);
|
||||
|
||||
$expectedChunkSize = ($this->chunkOffset === $this->numChunks - 1)
|
||||
? $this->expectedLastChunkSize
|
||||
: $this->chunkSize;
|
||||
|
||||
if ($actualChunkSize !== $expectedChunkSize) {
|
||||
throw CorruptFileException::unexpectedSize($actualChunkSize, $expectedChunkSize);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance to the next chunk and initialize the buffer to its data.
|
||||
*
|
||||
* @return boolean Whether there was a next chunk to read
|
||||
* @throws CorruptFileException if an expected chunk could not be read successfully
|
||||
*/
|
||||
private function initBufferFromNextChunk()
|
||||
{
|
||||
if ($this->chunkOffset === $this->numChunks - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->bufferOffset = 0;
|
||||
$this->chunkOffset++;
|
||||
$this->chunksIterator->next();
|
||||
|
||||
return $this->initBufferFromCurrentChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the chunk iterator starting from the current offset.
|
||||
*/
|
||||
private function initChunksIterator()
|
||||
{
|
||||
$cursor = $this->collectionWrapper->findChunksByFileId($this->file->_id, $this->chunkOffset);
|
||||
|
||||
$this->chunksIterator = new IteratorIterator($cursor);
|
||||
$this->chunksIterator->rewind();
|
||||
}
|
||||
}
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
<?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\GridFS;
|
||||
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
use Exception;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Stream wrapper for reading and writing a GridFS file.
|
||||
*
|
||||
* @internal
|
||||
* @see Bucket::openUploadStream()
|
||||
* @see Bucket::openDownloadStream()
|
||||
*/
|
||||
class StreamWrapper
|
||||
{
|
||||
/**
|
||||
* @var resource|null Stream context (set by PHP)
|
||||
*/
|
||||
public $context;
|
||||
|
||||
private $mode;
|
||||
private $protocol;
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* Return the stream's file document.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->stream->getFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the GridFS stream wrapper.
|
||||
*
|
||||
* @param string $protocol Protocol to use for stream_wrapper_register()
|
||||
*/
|
||||
public static function register($protocol = 'gridfs')
|
||||
{
|
||||
if (in_array($protocol, stream_get_wrappers())) {
|
||||
stream_wrapper_unregister($protocol);
|
||||
}
|
||||
|
||||
stream_wrapper_register($protocol, get_called_class(), \STREAM_IS_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-close.php
|
||||
*/
|
||||
public function stream_close()
|
||||
{
|
||||
$this->stream->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the file pointer is at the end of the stream.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-eof.php
|
||||
* @return boolean
|
||||
*/
|
||||
public function stream_eof()
|
||||
{
|
||||
if ( ! $this->stream instanceof ReadableStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->stream->isEOF();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the stream.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-open.php
|
||||
* @param string $path Path to the file resource
|
||||
* @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
|
||||
*/
|
||||
public function stream_open($path, $mode, $options, &$openedPath)
|
||||
{
|
||||
$this->initProtocol($path);
|
||||
$this->mode = $mode;
|
||||
|
||||
if ($mode === 'r') {
|
||||
return $this->initReadableStream();
|
||||
}
|
||||
|
||||
if ($mode === 'w') {
|
||||
return $this->initWritableStream();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read bytes from the stream.
|
||||
*
|
||||
* Note: this method may return a string smaller than the requested length
|
||||
* if data is not available to be read.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-read.php
|
||||
* @param integer $length Number of bytes to read
|
||||
* @return string
|
||||
*/
|
||||
public function stream_read($length)
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current position of the stream.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-seek.php
|
||||
* @param integer $offset Stream offset to seek to
|
||||
* @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)
|
||||
{
|
||||
$size = $this->stream->getSize();
|
||||
|
||||
if ($whence === \SEEK_CUR) {
|
||||
$offset += $this->stream->tell();
|
||||
}
|
||||
|
||||
if ($whence === \SEEK_END) {
|
||||
$offset += $size;
|
||||
}
|
||||
|
||||
// WritableStreams are always positioned at the end of the stream
|
||||
if ($this->stream instanceof WritableStream) {
|
||||
return $offset === $size;
|
||||
}
|
||||
|
||||
if ($offset < 0 || $offset > $size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->stream->seek($offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return information about the stream.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-stat.php
|
||||
* @return array
|
||||
*/
|
||||
public function stream_stat()
|
||||
{
|
||||
$stat = $this->getStatTemplate();
|
||||
|
||||
$stat[2] = $stat['mode'] = $this->stream instanceof ReadableStream
|
||||
? 0100444 // S_IFREG & S_IRUSR & S_IRGRP & S_IROTH
|
||||
: 0100222; // S_IFREG & S_IWUSR & S_IWGRP & S_IWOTH
|
||||
$stat[7] = $stat['size'] = $this->stream->getSize();
|
||||
|
||||
$file = $this->stream->getFile();
|
||||
|
||||
if (isset($file->uploadDate) && $file->uploadDate instanceof UTCDateTime) {
|
||||
$timestamp = $file->uploadDate->toDateTime()->getTimestamp();
|
||||
$stat[9] = $stat['mtime'] = $timestamp;
|
||||
$stat[10] = $stat['ctime'] = $timestamp;
|
||||
}
|
||||
|
||||
if (isset($file->chunkSize) && is_integer($file->chunkSize)) {
|
||||
$stat[11] = $stat['blksize'] = $file->chunkSize;
|
||||
}
|
||||
|
||||
return $stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current position of the stream.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-tell.php
|
||||
* @return integer The current position of the stream
|
||||
*/
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->stream->tell();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write bytes to the stream.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-write.php
|
||||
* @param string $data Data to write
|
||||
* @return integer The number of bytes written
|
||||
*/
|
||||
public function stream_write($data)
|
||||
{
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stat template with default values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getStatTemplate()
|
||||
{
|
||||
return [
|
||||
0 => 0, 'dev' => 0,
|
||||
1 => 0, 'ino' => 0,
|
||||
2 => 0, 'mode' => 0,
|
||||
3 => 0, 'nlink' => 0,
|
||||
4 => 0, 'uid' => 0,
|
||||
5 => 0, 'gid' => 0,
|
||||
6 => -1, 'rdev' => -1,
|
||||
7 => 0, 'size' => 0,
|
||||
8 => 0, 'atime' => 0,
|
||||
9 => 0, 'mtime' => 0,
|
||||
10 => 0, 'ctime' => 0,
|
||||
11 => -1, 'blksize' => -1,
|
||||
12 => -1, 'blocks' => -1,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the protocol from the given path.
|
||||
*
|
||||
* @see StreamWrapper::stream_open()
|
||||
* @param string $path
|
||||
*/
|
||||
private function initProtocol($path)
|
||||
{
|
||||
$parts = explode('://', $path, 2);
|
||||
$this->protocol = $parts[0] ?: 'gridfs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the internal stream for reading.
|
||||
*
|
||||
* @see StreamWrapper::stream_open()
|
||||
* @return boolean
|
||||
*/
|
||||
private function initReadableStream()
|
||||
{
|
||||
$context = stream_context_get_options($this->context);
|
||||
|
||||
$this->stream = new ReadableStream(
|
||||
$context[$this->protocol]['collectionWrapper'],
|
||||
$context[$this->protocol]['file']
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the internal stream for writing.
|
||||
*
|
||||
* @see StreamWrapper::stream_open()
|
||||
* @return boolean
|
||||
*/
|
||||
private function initWritableStream()
|
||||
{
|
||||
$context = stream_context_get_options($this->context);
|
||||
|
||||
$this->stream = new WritableStream(
|
||||
$context[$this->protocol]['collectionWrapper'],
|
||||
$context[$this->protocol]['filename'],
|
||||
$context[$this->protocol]['options']
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
<?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\GridFS;
|
||||
|
||||
use MongoDB\BSON\Binary;
|
||||
use MongoDB\BSON\ObjectId;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* WritableStream abstracts the process of writing a GridFS file.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class WritableStream
|
||||
{
|
||||
private static $defaultChunkSizeBytes = 261120;
|
||||
|
||||
private $buffer = '';
|
||||
private $chunkOffset = 0;
|
||||
private $chunkSize;
|
||||
private $disableMD5;
|
||||
private $collectionWrapper;
|
||||
private $file;
|
||||
private $hashCtx;
|
||||
private $isClosed = false;
|
||||
private $length = 0;
|
||||
|
||||
/**
|
||||
* Constructs a writable GridFS stream.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * _id (mixed): File document identifier. Defaults to a new ObjectId.
|
||||
*
|
||||
* * aliases (array of strings): DEPRECATED An array of aliases.
|
||||
* Applications wishing to store aliases should add an aliases field to
|
||||
* the metadata document instead.
|
||||
*
|
||||
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to
|
||||
* 261120 (i.e. 255 KiB).
|
||||
*
|
||||
* * disableMD5 (boolean): When true, no MD5 sum will be generated.
|
||||
* Defaults to "false".
|
||||
*
|
||||
* * contentType (string): DEPRECATED content type to be stored with the
|
||||
* file. This information should now be added to the metadata.
|
||||
*
|
||||
* * metadata (document): User data for the "metadata" field of the files
|
||||
* collection document.
|
||||
*
|
||||
* @param CollectionWrapper $collectionWrapper GridFS collection wrapper
|
||||
* @param string $filename Filename
|
||||
* @param array $options Upload options
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(CollectionWrapper $collectionWrapper, $filename, array $options = [])
|
||||
{
|
||||
$options += [
|
||||
'_id' => new ObjectId,
|
||||
'chunkSizeBytes' => self::$defaultChunkSizeBytes,
|
||||
'disableMD5' => false,
|
||||
];
|
||||
|
||||
if (isset($options['aliases']) && ! \MongoDB\is_string_array($options['aliases'])) {
|
||||
throw InvalidArgumentException::invalidType('"aliases" option', $options['aliases'], 'array of strings');
|
||||
}
|
||||
|
||||
if (isset($options['chunkSizeBytes']) && ! is_integer($options['chunkSizeBytes'])) {
|
||||
throw InvalidArgumentException::invalidType('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['chunkSizeBytes']) && $options['chunkSizeBytes'] < 1) {
|
||||
throw new InvalidArgumentException(sprintf('Expected "chunkSizeBytes" option to be >= 1, %d given', $options['chunkSizeBytes']));
|
||||
}
|
||||
|
||||
if (isset($options['disableMD5']) && ! is_bool($options['disableMD5'])) {
|
||||
throw InvalidArgumentException::invalidType('"disableMD5" option', $options['disableMD5'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['contentType']) && ! is_string($options['contentType'])) {
|
||||
throw InvalidArgumentException::invalidType('"contentType" option', $options['contentType'], 'string');
|
||||
}
|
||||
|
||||
if (isset($options['metadata']) && ! is_array($options['metadata']) && ! is_object($options['metadata'])) {
|
||||
throw InvalidArgumentException::invalidType('"metadata" option', $options['metadata'], 'array or object');
|
||||
}
|
||||
|
||||
$this->chunkSize = $options['chunkSizeBytes'];
|
||||
$this->collectionWrapper = $collectionWrapper;
|
||||
$this->disableMD5 = $options['disableMD5'];
|
||||
|
||||
if ( ! $this->disableMD5) {
|
||||
$this->hashCtx = hash_init('md5');
|
||||
}
|
||||
|
||||
$this->file = [
|
||||
'_id' => $options['_id'],
|
||||
'chunkSize' => $this->chunkSize,
|
||||
'filename' => (string) $filename,
|
||||
] + array_intersect_key($options, ['aliases' => 1, 'contentType' => 1, 'metadata' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return internal properties for debugging purposes.
|
||||
*
|
||||
* @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return [
|
||||
'bucketName' => $this->collectionWrapper->getBucketName(),
|
||||
'databaseName' => $this->collectionWrapper->getDatabaseName(),
|
||||
'file' => $this->file,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes an active stream and flushes all buffered data to GridFS.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if ($this->isClosed) {
|
||||
// TODO: Should this be an error condition? e.g. BadMethodCallException
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen($this->buffer) > 0) {
|
||||
$this->insertChunkFromBuffer();
|
||||
}
|
||||
|
||||
$this->fileCollectionInsert();
|
||||
$this->isClosed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the stream's file document.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return (object) $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the stream's size in bytes.
|
||||
*
|
||||
* Note: this value will increase as more data is written to the stream.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->length + strlen($this->buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current position of the stream.
|
||||
*
|
||||
* This is the offset within the stream where the next byte would be
|
||||
* written. Since seeking is not supported and writes are appended, this is
|
||||
* always the end of the stream.
|
||||
*
|
||||
* @see WritableStream::getSize()
|
||||
* @return integer
|
||||
*/
|
||||
public function tell()
|
||||
{
|
||||
return $this->getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts binary data into GridFS via chunks.
|
||||
*
|
||||
* Data will be buffered internally until chunkSizeBytes are accumulated, at
|
||||
* which point a chunk document will be inserted and the buffer reset.
|
||||
*
|
||||
* @param string $data Binary data to write
|
||||
* @return integer
|
||||
*/
|
||||
public function writeBytes($data)
|
||||
{
|
||||
if ($this->isClosed) {
|
||||
// TODO: Should this be an error condition? e.g. BadMethodCallException
|
||||
return;
|
||||
}
|
||||
|
||||
$bytesRead = 0;
|
||||
|
||||
while ($bytesRead != strlen($data)) {
|
||||
$initialBufferLength = strlen($this->buffer);
|
||||
$this->buffer .= substr($data, $bytesRead, $this->chunkSize - $initialBufferLength);
|
||||
$bytesRead += strlen($this->buffer) - $initialBufferLength;
|
||||
|
||||
if (strlen($this->buffer) == $this->chunkSize) {
|
||||
$this->insertChunkFromBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
return $bytesRead;
|
||||
}
|
||||
|
||||
private function abort()
|
||||
{
|
||||
try {
|
||||
$this->collectionWrapper->deleteChunksByFilesId($this->file['_id']);
|
||||
} catch (DriverRuntimeException $e) {
|
||||
// We are already handling an error if abort() is called, so suppress this
|
||||
}
|
||||
|
||||
$this->isClosed = true;
|
||||
}
|
||||
|
||||
private function fileCollectionInsert()
|
||||
{
|
||||
$this->file['length'] = $this->length;
|
||||
$this->file['uploadDate'] = new UTCDateTime;
|
||||
|
||||
if ( ! $this->disableMD5) {
|
||||
$this->file['md5'] = hash_final($this->hashCtx);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->collectionWrapper->insertFile($this->file);
|
||||
} catch (DriverRuntimeException $e) {
|
||||
$this->abort();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $this->file['_id'];
|
||||
}
|
||||
|
||||
private function insertChunkFromBuffer()
|
||||
{
|
||||
if (strlen($this->buffer) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->buffer;
|
||||
$this->buffer = '';
|
||||
|
||||
$chunk = [
|
||||
'files_id' => $this->file['_id'],
|
||||
'n' => $this->chunkOffset,
|
||||
'data' => new Binary($data, Binary::TYPE_GENERIC),
|
||||
];
|
||||
|
||||
if ( ! $this->disableMD5) {
|
||||
hash_update($this->hashCtx, $data);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->collectionWrapper->insertChunk($chunk);
|
||||
} catch (DriverRuntimeException $e) {
|
||||
$this->abort();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->length += strlen($data);
|
||||
$this->chunkOffset++;
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
use MongoDB\Driver\WriteResult;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Result class for a multi-document insert operation.
|
||||
*/
|
||||
class InsertManyResult
|
||||
{
|
||||
private $writeResult;
|
||||
private $insertedIds;
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
* @param mixed[] $insertedIds
|
||||
*/
|
||||
public function __construct(WriteResult $writeResult, array $insertedIds)
|
||||
{
|
||||
$this->writeResult = $writeResult;
|
||||
$this->insertedIds = $insertedIds;
|
||||
$this->isAcknowledged = $writeResult->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were inserted.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see InsertManyResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getInsertedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getInsertedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the inserted documents' IDs.
|
||||
*
|
||||
* The index of each ID in the map corresponds to each document's position
|
||||
* in the bulk operation. If a document had an ID prior to inserting (i.e.
|
||||
* the driver did not generate an ID), the index will contain its "_id"
|
||||
* field value. Any driver-generated ID will be a MongoDB\BSON\ObjectId
|
||||
* instance.
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getInsertedIds()
|
||||
{
|
||||
return $this->insertedIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this insert result was acknowledged by the server.
|
||||
*
|
||||
* If the insert was not acknowledged, other fields from the WriteResult
|
||||
* (e.g. insertedCount) will be undefined.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAcknowledged()
|
||||
{
|
||||
return $this->writeResult->isAcknowledged();
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
use MongoDB\Driver\WriteResult;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Result class for a single-document insert operation.
|
||||
*/
|
||||
class InsertOneResult
|
||||
{
|
||||
private $writeResult;
|
||||
private $insertedId;
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
* @param mixed $insertedId
|
||||
*/
|
||||
public function __construct(WriteResult $writeResult, $insertedId)
|
||||
{
|
||||
$this->writeResult = $writeResult;
|
||||
$this->insertedId = $insertedId;
|
||||
$this->isAcknowledged = $writeResult->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were inserted.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see InsertOneResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getInsertedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getInsertedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the inserted document's ID.
|
||||
*
|
||||
* If the document had an ID prior to inserting (i.e. the driver did not
|
||||
* need to generate an ID), this will contain its "_id". Any
|
||||
* driver-generated ID will be a MongoDB\BSON\ObjectId instance.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInsertedId()
|
||||
{
|
||||
return $this->insertedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this insert was acknowledged by the server.
|
||||
*
|
||||
* If the insert was not acknowledged, other fields from the WriteResult
|
||||
* (e.g. insertedCount) will be undefined.
|
||||
*
|
||||
* If the insert was not acknowledged, other fields from the WriteResult
|
||||
* (e.g. insertedCount) will be undefined and their getter methods should
|
||||
* not be invoked.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAcknowledged()
|
||||
{
|
||||
return $this->writeResult->isAcknowledged();
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 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;
|
||||
|
||||
use IteratorAggregate;
|
||||
use stdClass;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Result class for mapReduce command results.
|
||||
*
|
||||
* This class allows for iteration of mapReduce results irrespective of the
|
||||
* output method (e.g. inline, collection) via the IteratorAggregate interface.
|
||||
* It also provides access to command statistics.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::mapReduce()
|
||||
* @see https://docs.mongodb.com/manual/reference/command/mapReduce/
|
||||
*/
|
||||
class MapReduceResult implements IteratorAggregate
|
||||
{
|
||||
private $getIterator;
|
||||
private $executionTimeMS;
|
||||
private $counts;
|
||||
private $timing;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @internal
|
||||
* @param callable $getIterator Callback that returns a Traversable for mapReduce results
|
||||
* @param stdClass $result Result document from the mapReduce command
|
||||
*/
|
||||
public function __construct(callable $getIterator, stdClass $result)
|
||||
{
|
||||
$this->getIterator = $getIterator;
|
||||
$this->executionTimeMS = (integer) $result->timeMillis;
|
||||
$this->counts = (array) $result->counts;
|
||||
$this->timing = isset($result->timing) ? (array) $result->timing : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns various count statistics from the mapReduce command.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCounts()
|
||||
{
|
||||
return $this->counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the command execution time in milliseconds.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getExecutionTimeMS()
|
||||
{
|
||||
return $this->executionTimeMS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapReduce results as a Traversable.
|
||||
*
|
||||
* @see http://php.net/iteratoraggregate.getiterator
|
||||
* @return Traversable
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return call_user_func($this->getIterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns various timing statistics from the mapReduce command.
|
||||
*
|
||||
* Note: timing statistics are only available if the mapReduce command's
|
||||
* "verbose" option was true; otherwise, an empty array will be returned.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTiming()
|
||||
{
|
||||
return $this->timing;
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2016-present 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 MongoDB\BSON\Serializable;
|
||||
use MongoDB\BSON\Unserializable;
|
||||
use ArrayObject;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Model class for a BSON array.
|
||||
*
|
||||
* The internal data will be filtered through array_values() during BSON
|
||||
* serialization to ensure that it becomes a BSON array.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class BSONArray extends ArrayObject implements JsonSerializable, Serializable, Unserializable
|
||||
{
|
||||
/**
|
||||
* Clone this BSONArray.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
foreach ($this as $key => $value) {
|
||||
$this[$key] = \MongoDB\recursive_copy($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for var_export().
|
||||
*
|
||||
* @see http://php.net/oop5.magic#object.set-state
|
||||
* @see http://php.net/var-export
|
||||
* @param array $properties
|
||||
* @return self
|
||||
*/
|
||||
public static function __set_state(array $properties)
|
||||
{
|
||||
$array = new static;
|
||||
$array->exchangeArray($properties);
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the array to BSON.
|
||||
*
|
||||
* The array data will be numerically reindexed to ensure that it is stored
|
||||
* as a BSON array.
|
||||
*
|
||||
* @see http://php.net/mongodb-bson-serializable.bsonserialize
|
||||
* @return array
|
||||
*/
|
||||
public function bsonSerialize()
|
||||
{
|
||||
return array_values($this->getArrayCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize the document to BSON.
|
||||
*
|
||||
* @see http://php.net/mongodb-bson-unserializable.bsonunserialize
|
||||
* @param array $data Array data
|
||||
*/
|
||||
public function bsonUnserialize(array $data)
|
||||
{
|
||||
self::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the array to JSON.
|
||||
*
|
||||
* The array data will be numerically reindexed to ensure that it is stored
|
||||
* as a JSON array.
|
||||
*
|
||||
* @see http://php.net/jsonserializable.jsonserialize
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array_values($this->getArrayCopy());
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2016-present 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 MongoDB\BSON\Serializable;
|
||||
use MongoDB\BSON\Unserializable;
|
||||
use ArrayObject;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Model class for a BSON document.
|
||||
*
|
||||
* The internal data will be cast to an object during BSON serialization to
|
||||
* ensure that it becomes a BSON document.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class BSONDocument extends ArrayObject implements JsonSerializable, Serializable, Unserializable
|
||||
{
|
||||
/**
|
||||
* Deep clone this BSONDocument.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
foreach ($this as $key => $value) {
|
||||
$this[$key] = \MongoDB\recursive_copy($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* This overrides the parent constructor to allow property access of entries
|
||||
* by default.
|
||||
*
|
||||
* @see http://php.net/arrayobject.construct
|
||||
*/
|
||||
public function __construct($input = [], $flags = ArrayObject::ARRAY_AS_PROPS, $iterator_class = 'ArrayIterator')
|
||||
{
|
||||
parent::__construct($input, $flags, $iterator_class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for var_export().
|
||||
*
|
||||
* @see http://php.net/oop5.magic#object.set-state
|
||||
* @see http://php.net/var-export
|
||||
* @param array $properties
|
||||
* @return self
|
||||
*/
|
||||
public static function __set_state(array $properties)
|
||||
{
|
||||
$document = new static;
|
||||
$document->exchangeArray($properties);
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the document to BSON.
|
||||
*
|
||||
* @see http://php.net/mongodb-bson-serializable.bsonserialize
|
||||
* @return object
|
||||
*/
|
||||
public function bsonSerialize()
|
||||
{
|
||||
return (object) $this->getArrayCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize the document to BSON.
|
||||
*
|
||||
* @see http://php.net/mongodb-bson-unserializable.bsonunserialize
|
||||
* @param array $data Array data
|
||||
*/
|
||||
public function bsonUnserialize(array $data)
|
||||
{
|
||||
parent::__construct($data, ArrayObject::ARRAY_AS_PROPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the array to JSON.
|
||||
*
|
||||
* @see http://php.net/jsonserializable.jsonserialize
|
||||
* @return object
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return (object) $this->getArrayCopy();
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2018 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 MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Model\BSONDocument;
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* Iterator for BSON documents.
|
||||
*/
|
||||
class BSONIterator implements Iterator
|
||||
{
|
||||
private static $bsonSize = 4;
|
||||
|
||||
private $buffer;
|
||||
private $bufferLength;
|
||||
private $current;
|
||||
private $key = 0;
|
||||
private $position = 0;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a BSON Iterator.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization.
|
||||
*
|
||||
* @internal
|
||||
* @see http://php.net/manual/en/function.mongodb.bson-tophp.php
|
||||
* @param string $data Concatenated, valid, BSON-encoded documents
|
||||
* @param array $options Iterator options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($data, array $options = [])
|
||||
{
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if ( ! isset($options['typeMap'])) {
|
||||
$options['typeMap'] = [];
|
||||
}
|
||||
|
||||
$this->buffer = $data;
|
||||
$this->bufferLength = strlen($data);
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.current
|
||||
* @return mixed
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.key
|
||||
* @return mixed
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.next
|
||||
* @return void
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->key++;
|
||||
$this->current = null;
|
||||
$this->advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.rewind
|
||||
* @return void
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->key = 0;
|
||||
$this->position = 0;
|
||||
$this->current = null;
|
||||
$this->advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.valid
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->current !== null;
|
||||
}
|
||||
|
||||
private function advance()
|
||||
{
|
||||
if ($this->position === $this->bufferLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (($this->bufferLength - $this->position) < self::$bsonSize) {
|
||||
throw new UnexpectedValueException(sprintf('Expected at least %d bytes; %d remaining', self::$bsonSize, $this->bufferLength - $this->position));
|
||||
}
|
||||
|
||||
list(,$documentLength) = unpack('V', substr($this->buffer, $this->position, self::$bsonSize));
|
||||
|
||||
if (($this->bufferLength - $this->position) < $documentLength) {
|
||||
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->position += $documentLength;
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 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 Countable;
|
||||
use Generator;
|
||||
use Iterator;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Iterator for wrapping a Traversable and caching its results.
|
||||
*
|
||||
* By caching results, this iterators allows a Traversable to be counted and
|
||||
* rewound multiple times, even if the wrapped object does not natively support
|
||||
* those operations (e.g. MongoDB\Driver\Cursor).
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CachingIterator implements Countable, Iterator
|
||||
{
|
||||
private $items = [];
|
||||
private $iterator;
|
||||
private $iteratorAdvanced = false;
|
||||
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
|
||||
* behavior of the SPL iterators and allows users to omit an explicit call
|
||||
* to rewind() before using the other methods.
|
||||
*
|
||||
* @param Traversable $traversable
|
||||
*/
|
||||
public function __construct(Traversable $traversable)
|
||||
{
|
||||
$this->iterator = $this->wrapTraversable($traversable);
|
||||
$this->storeCurrentItem();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/countable.count
|
||||
* @return integer
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
$this->exhaustIterator();
|
||||
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.current
|
||||
* @return mixed
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return current($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.key
|
||||
* @return mixed
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return key($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.next
|
||||
* @return void
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
if ( ! $this->iteratorExhausted) {
|
||||
$this->iterator->next();
|
||||
$this->storeCurrentItem();
|
||||
}
|
||||
|
||||
next($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.rewind
|
||||
* @return void
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
/* If the iterator has advanced, exhaust it now so that future iteration
|
||||
* can rely on the cache.
|
||||
*/
|
||||
if ($this->iteratorAdvanced) {
|
||||
$this->exhaustIterator();
|
||||
}
|
||||
|
||||
reset($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://php.net/iterator.valid
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->key() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the inner iterator is fully consumed and cached.
|
||||
*/
|
||||
private function exhaustIterator()
|
||||
{
|
||||
while ( ! $this->iteratorExhausted) {
|
||||
$this->next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the current item in the cache.
|
||||
*/
|
||||
private function storeCurrentItem()
|
||||
{
|
||||
$key = $this->iterator->key();
|
||||
|
||||
if ($key === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->items[$key] = $this->iterator->current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Traversable with a Generator.
|
||||
*
|
||||
* @param Traversable $traversable
|
||||
* @return Generator
|
||||
*/
|
||||
private function wrapTraversable(Traversable $traversable)
|
||||
{
|
||||
foreach ($traversable as $key => $value) {
|
||||
yield $key => $value;
|
||||
$this->iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
$this->iteratorExhausted = true;
|
||||
}
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 MongoDB\Exception\BadMethodCallException;
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* Collection information model class.
|
||||
*
|
||||
* This class models the collection information returned by the listCollections
|
||||
* command or, for legacy servers, queries on the "system.namespaces"
|
||||
* collection. It provides methods to access options for the collection.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Database::listCollections()
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/enumerate-collections.rst
|
||||
*/
|
||||
class CollectionInfo implements ArrayAccess
|
||||
{
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $info Collection info
|
||||
*/
|
||||
public function __construct(array $info)
|
||||
{
|
||||
$this->info = $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the collection info as an array.
|
||||
*
|
||||
* @see http://php.net/oop5.magic#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of documents to keep in the capped collection.
|
||||
*
|
||||
* @return integer|null
|
||||
*/
|
||||
public function getCappedMax()
|
||||
{
|
||||
return isset($this->info['options']['max']) ? (integer) $this->info['options']['max'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum size (in bytes) of the capped collection.
|
||||
*
|
||||
* @return integer|null
|
||||
*/
|
||||
public function getCappedSize()
|
||||
{
|
||||
return isset($this->info['options']['size']) ? (integer) $this->info['options']['size'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the collection name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return (string) $this->info['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the collection options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return isset($this->info['options']) ? (array) $this->info['options'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the collection is a capped collection.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isCapped()
|
||||
{
|
||||
return ! empty($this->info['options']['capped']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a field exists in the collection information.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetexists
|
||||
* @param mixed $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return array_key_exists($key, $this->info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field's value from the collection information.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetget
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return $this->info[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetunset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 IteratorIterator;
|
||||
|
||||
/**
|
||||
* CollectionInfoIterator for listCollections command results.
|
||||
*
|
||||
* This iterator may be used to wrap a Cursor returned by the listCollections
|
||||
* command.
|
||||
*
|
||||
* @internal
|
||||
* @see \MongoDB\Database::listCollections()
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/enumerate-collections.rst
|
||||
* @see http://docs.mongodb.org/manual/reference/command/listCollections/
|
||||
*/
|
||||
class CollectionInfoCommandIterator extends IteratorIterator implements CollectionInfoIterator
|
||||
{
|
||||
/**
|
||||
* Return the current element as a CollectionInfo instance.
|
||||
*
|
||||
* @see CollectionInfoIterator::current()
|
||||
* @see http://php.net/iterator.current
|
||||
* @return CollectionInfo
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return new CollectionInfo(parent::current());
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 Iterator;
|
||||
|
||||
/**
|
||||
* CollectionInfoIterator interface.
|
||||
*
|
||||
* This iterator is used for enumerating collections in a database.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Database::listCollections()
|
||||
*/
|
||||
interface CollectionInfoIterator extends Iterator
|
||||
{
|
||||
/**
|
||||
* Return the current element as a CollectionInfo instance.
|
||||
*
|
||||
* @return CollectionInfo
|
||||
*/
|
||||
public function current();
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 MongoDB\Exception\BadMethodCallException;
|
||||
use ArrayAccess;
|
||||
/**
|
||||
* Database information model class.
|
||||
*
|
||||
* This class models the database information returned by the listDatabases
|
||||
* command. It provides methods to access common database properties.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Client::listDatabases()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/listDatabases/
|
||||
*/
|
||||
class DatabaseInfo implements ArrayAccess
|
||||
{
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $info Database info
|
||||
*/
|
||||
public function __construct(array $info)
|
||||
{
|
||||
$this->info = $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the collection info as an array.
|
||||
*
|
||||
* @see http://php.net/oop5.magic#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return (string) $this->info['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the databases size on disk (in bytes).
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getSizeOnDisk()
|
||||
{
|
||||
return (integer) $this->info['sizeOnDisk'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the database is empty.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return (boolean) $this->info['empty'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a field exists in the database information.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetexists
|
||||
* @param mixed $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return array_key_exists($key, $this->info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field's value from the database information.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetget
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return $this->info[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetunset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 Iterator;
|
||||
|
||||
/**
|
||||
* DatabaseInfoIterator interface.
|
||||
*
|
||||
* This iterator is used for enumerating databases on a server.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Client::listDatabases()
|
||||
*/
|
||||
interface DatabaseInfoIterator extends Iterator
|
||||
{
|
||||
/**
|
||||
* Return the current element as a DatabaseInfo instance.
|
||||
*
|
||||
* @return DatabaseInfo
|
||||
*/
|
||||
public function current();
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
/**
|
||||
* DatabaseInfoIterator for inline listDatabases command results.
|
||||
*
|
||||
* This iterator may be used to wrap the array returned within the listDatabases
|
||||
* command's single-document result.
|
||||
*
|
||||
* @internal
|
||||
* @see \MongoDB\Client::listDatabases()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/listDatabases/
|
||||
*/
|
||||
class DatabaseInfoLegacyIterator implements DatabaseInfoIterator
|
||||
{
|
||||
private $databases;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $databases
|
||||
*/
|
||||
public function __construct(array $databases)
|
||||
{
|
||||
$this->databases = $databases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current element as a DatabaseInfo instance.
|
||||
*
|
||||
* @see DatabaseInfoIterator::current()
|
||||
* @see http://php.net/iterator.current
|
||||
* @return DatabaseInfo
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return new DatabaseInfo(current($this->databases));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key of the current element.
|
||||
*
|
||||
* @see http://php.net/iterator.key
|
||||
* @return integer
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return key($this->databases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move forward to next element.
|
||||
*
|
||||
* @see http://php.net/iterator.next
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
next($this->databases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind the Iterator to the first element.
|
||||
*
|
||||
* @see http://php.net/iterator.rewind
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
reset($this->databases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current position is valid.
|
||||
*
|
||||
* @see http://php.net/iterator.valid
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return key($this->databases) !== null;
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 MongoDB\Exception\BadMethodCallException;
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* Index information model class.
|
||||
*
|
||||
* This class models the index information returned by the listIndexes command
|
||||
* or, for legacy servers, queries on the "system.indexes" collection. It
|
||||
* provides methods to access common index options, and allows access to other
|
||||
* options through the ArrayAccess interface (write methods are not supported).
|
||||
* For information on keys and index options, see the referenced
|
||||
* db.collection.createIndex() documentation.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::listIndexes()
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst
|
||||
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
|
||||
*/
|
||||
class IndexInfo implements ArrayAccess
|
||||
{
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $info Index info
|
||||
*/
|
||||
public function __construct(array $info)
|
||||
{
|
||||
$this->info = $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the collection info as an array.
|
||||
*
|
||||
* @see http://php.net/oop5.magic#language.oop5.magic.debuginfo
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name to allow casting IndexInfo to string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index key.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return (array) $this->info['key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return (string) $this->info['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index namespace (e.g. "db.collection").
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return (string) $this->info['ns'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index version.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return (integer) $this->info['v'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not this index is of type 2dsphere.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is2dSphere()
|
||||
{
|
||||
return array_search('2dsphere', $this->getKey(), true) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not this index is of type geoHaystack.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isGeoHaystack()
|
||||
{
|
||||
return array_search('geoHaystack', $this->getKey(), true) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this is a sparse index.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/core/index-sparse/
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSparse()
|
||||
{
|
||||
return ! empty($this->info['sparse']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not this index is of type text.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isText()
|
||||
{
|
||||
return array_search('text', $this->getKey(), true) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this is a TTL index.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/core/index-ttl/
|
||||
* @return boolean
|
||||
*/
|
||||
public function isTtl()
|
||||
{
|
||||
return array_key_exists('expireAfterSeconds', $this->info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this is a unique index.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/core/index-unique/
|
||||
* @return boolean
|
||||
*/
|
||||
public function isUnique()
|
||||
{
|
||||
return ! empty($this->info['unique']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a field exists in the index information.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetexists
|
||||
* @param mixed $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return array_key_exists($key, $this->info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field's value from the index information.
|
||||
*
|
||||
* This method satisfies the Enumerating Indexes specification's requirement
|
||||
* that index fields be made accessible under their original names. It may
|
||||
* also be used to access fields that do not have a helper method.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetget
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst#getting-full-index-information
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return $this->info[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @see http://php.net/arrayaccess.offsetunset
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw BadMethodCallException::classIsImmutable(__CLASS__);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 Iterator;
|
||||
|
||||
/**
|
||||
* IndexInfoIterator interface.
|
||||
*
|
||||
* This iterator is used for enumerating indexes in a collection.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::listIndexes()
|
||||
*/
|
||||
interface IndexInfoIterator extends Iterator
|
||||
{
|
||||
/**
|
||||
* Return the current element as a IndexInfo instance.
|
||||
*
|
||||
* @return IndexInfo
|
||||
*/
|
||||
public function current();
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 IteratorIterator;
|
||||
|
||||
/**
|
||||
* IndexInfoIterator for both listIndexes command and legacy query results.
|
||||
*
|
||||
* This common iterator may be used to wrap a Cursor returned by both the
|
||||
* listIndexes command and, for legacy servers, queries on the "system.indexes"
|
||||
* collection.
|
||||
*
|
||||
* @internal
|
||||
* @see \MongoDB\Collection::listIndexes()
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst
|
||||
* @see http://docs.mongodb.org/manual/reference/command/listIndexes/
|
||||
* @see http://docs.mongodb.org/manual/reference/system-collections/
|
||||
*/
|
||||
class IndexInfoIteratorIterator extends IteratorIterator implements IndexInfoIterator
|
||||
{
|
||||
/**
|
||||
* Return the current element as an IndexInfo instance.
|
||||
*
|
||||
* @see IndexInfoIterator::current()
|
||||
* @see http://php.net/iterator.current
|
||||
* @return IndexInfo
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return new IndexInfo(parent::current());
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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 MongoDB\BSON\Serializable;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Index input model class.
|
||||
*
|
||||
* This class is used to validate user input for index creation.
|
||||
*
|
||||
* @internal
|
||||
* @see \MongoDB\Collection::createIndexes()
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst
|
||||
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
|
||||
*/
|
||||
class IndexInput implements Serializable
|
||||
{
|
||||
private $index;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $index Index specification
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(array $index)
|
||||
{
|
||||
if ( ! isset($index['key'])) {
|
||||
throw new InvalidArgumentException('Required "key" document is missing from index specification');
|
||||
}
|
||||
|
||||
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)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('order value for "%s" field within "key" option', $fieldName), $order, 'numeric or string');
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset($index['ns'])) {
|
||||
throw new InvalidArgumentException('Required "ns" option is missing from index specification');
|
||||
}
|
||||
|
||||
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 ( ! is_string($index['name'])) {
|
||||
throw InvalidArgumentException::invalidType('"name" option', $index['name'], 'string');
|
||||
}
|
||||
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name.
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->index['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the index information to BSON for index creation.
|
||||
*
|
||||
* @see \MongoDB\Collection::createIndexes()
|
||||
* @see http://php.net/mongodb-bson-serializable.bsonserialize
|
||||
* @return array
|
||||
*/
|
||||
public function bsonSerialize()
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
<?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__);
|
||||
}
|
||||
}
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the aggregate command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::aggregate()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
|
||||
*/
|
||||
class Aggregate implements Executable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $pipeline;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs an aggregate command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * allowDiskUse (boolean): Enables writing to temporary files. When set
|
||||
* to true, aggregation stages can write data to the _tmp sub-directory
|
||||
* in the dbPath directory. The default is false.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * comment (string): An arbitrary string to help trace the operation
|
||||
* through the database profiler, currentOp, and logs.
|
||||
*
|
||||
* * explain (boolean): Specifies whether or not to return the information
|
||||
* on the processing of the pipeline.
|
||||
*
|
||||
* * hint (string|document): The index to use. Specify either the index
|
||||
* name as a string or the index key pattern as a document. If specified,
|
||||
* then the query system will only consider plans using the hinted index.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be
|
||||
* applied to the returned Cursor (it is not sent to the server).
|
||||
*
|
||||
* * useCursor (boolean): Indicates whether the command will request that
|
||||
* the server provide results using a cursor. The default is true.
|
||||
*
|
||||
* This option allows users to turn off cursors if necessary to aid in
|
||||
* mongod/mongos upgrades.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern. This only
|
||||
* applies when the $out stage is specified.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* Note: Collection-agnostic commands (e.g. $currentOp) may be executed by
|
||||
* specifying null for the collection name.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string|null $collectionName Collection name
|
||||
* @param array $pipeline List of pipeline operations
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $pipeline, array $options = [])
|
||||
{
|
||||
$expectedIndex = 0;
|
||||
|
||||
foreach ($pipeline as $i => $operation) {
|
||||
if ($i !== $expectedIndex) {
|
||||
throw new InvalidArgumentException(sprintf('$pipeline is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($operation) && ! is_object($operation)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$pipeline[%d]', $i), $operation, 'array or object');
|
||||
}
|
||||
|
||||
$expectedIndex += 1;
|
||||
}
|
||||
|
||||
$options += [
|
||||
'allowDiskUse' => false,
|
||||
'useCursor' => true,
|
||||
];
|
||||
|
||||
if ( ! is_bool($options['allowDiskUse'])) {
|
||||
throw InvalidArgumentException::invalidType('"allowDiskUse" option', $options['allowDiskUse'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['batchSize']) && ! is_integer($options['batchSize'])) {
|
||||
throw InvalidArgumentException::invalidType('"batchSize" option', $options['batchSize'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
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['comment']) && ! is_string($options['comment'])) {
|
||||
throw InvalidArgumentException::invalidType('"comment" option', $options['comment'], 'string');
|
||||
}
|
||||
|
||||
if (isset($options['explain']) && ! is_bool($options['explain'])) {
|
||||
throw InvalidArgumentException::invalidType('"explain" option', $options['explain'], 'boolean');
|
||||
}
|
||||
|
||||
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['maxAwaitTimeMS']) && ! is_integer($options['maxAwaitTimeMS'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxAwaitTimeMS" option', $options['maxAwaitTimeMS'], '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['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['batchSize']) && ! $options['useCursor']) {
|
||||
throw new InvalidArgumentException('"batchSize" option should not be used if "useCursor" is false');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && $options['readConcern']->isDefault()) {
|
||||
unset($options['readConcern']);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
if ( ! empty($options['explain'])) {
|
||||
$options['useCursor'] = false;
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = isset($collectionName) ? (string) $collectionName : null;
|
||||
$this->pipeline = $pipeline;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return Traversable
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if collation, read concern, or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$hasExplain = ! empty($this->options['explain']);
|
||||
$hasOutStage = \MongoDB\is_last_pipeline_operator_out($this->pipeline);
|
||||
|
||||
$command = $this->createCommand($server);
|
||||
$options = $this->createOptions($hasOutStage, $hasExplain);
|
||||
|
||||
$cursor = ($hasOutStage && ! $hasExplain)
|
||||
? $server->executeReadWriteCommand($this->databaseName, $command, $options)
|
||||
: $server->executeReadCommand($this->databaseName, $command, $options);
|
||||
|
||||
if ($this->options['useCursor'] || $hasExplain) {
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
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'])) {
|
||||
return new TypeMapArrayIterator($result->result, $this->options['typeMap']);
|
||||
}
|
||||
|
||||
return new ArrayIterator($result->result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the aggregate command.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return Command
|
||||
*/
|
||||
private function createCommand(Server $server)
|
||||
{
|
||||
$cmd = [
|
||||
'aggregate' => isset($this->collectionName) ? $this->collectionName : 1,
|
||||
'pipeline' => $this->pipeline,
|
||||
];
|
||||
$cmdOptions = [];
|
||||
|
||||
$cmd['allowDiskUse'] = $this->options['allowDiskUse'];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
foreach (['comment', 'explain', 'maxTimeMS'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
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['maxAwaitTimeMS'])) {
|
||||
$cmdOptions['maxAwaitTimeMS'] = $this->options['maxAwaitTimeMS'];
|
||||
}
|
||||
|
||||
if ($this->options['useCursor']) {
|
||||
$cmd['cursor'] = isset($this->options["batchSize"])
|
||||
? ['batchSize' => $this->options["batchSize"]]
|
||||
: new stdClass;
|
||||
}
|
||||
|
||||
return new Command($cmd, $cmdOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @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
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions($hasOutStage, $hasExplain)
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['readConcern'])) {
|
||||
$options['readConcern'] = $this->options['readConcern'];
|
||||
}
|
||||
|
||||
if ( ! $hasOutStage && isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if ($hasOutStage && ! $hasExplain && isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+380
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\BulkWriteResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for executing multiple write operations.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::bulkWrite()
|
||||
*/
|
||||
class BulkWrite implements Executable
|
||||
{
|
||||
const DELETE_MANY = 'deleteMany';
|
||||
const DELETE_ONE = 'deleteOne';
|
||||
const INSERT_ONE = 'insertOne';
|
||||
const REPLACE_ONE = 'replaceOne';
|
||||
const UPDATE_MANY = 'updateMany';
|
||||
const UPDATE_ONE = 'updateOne';
|
||||
|
||||
private static $wireVersionForArrayFilters = 6;
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $operations;
|
||||
private $options;
|
||||
private $isArrayFiltersUsed = false;
|
||||
private $isCollationUsed = false;
|
||||
|
||||
/**
|
||||
* Constructs a bulk write operation.
|
||||
*
|
||||
* Example array structure for all supported operation types:
|
||||
*
|
||||
* [
|
||||
* [ 'deleteMany' => [ $filter, $options ] ],
|
||||
* [ 'deleteOne' => [ $filter, $options ] ],
|
||||
* [ 'insertOne' => [ $document ] ],
|
||||
* [ 'replaceOne' => [ $filter, $replacement, $options ] ],
|
||||
* [ 'updateMany' => [ $filter, $update, $options ] ],
|
||||
* [ 'updateOne' => [ $filter, $update, $options ] ],
|
||||
* ]
|
||||
*
|
||||
* Arguments correspond to the respective Operation classes; however, the
|
||||
* writeConcern option is specified for the top-level bulk write operation
|
||||
* instead of each individual operation.
|
||||
*
|
||||
* Supported options for deleteMany and deleteOne operations:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* Supported options for replaceOne, updateMany, and updateOne operations:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. The default is false.
|
||||
*
|
||||
* Supported options for updateMany and updateOne operations:
|
||||
*
|
||||
* * arrayFilters (document array): A set of filters specifying to which
|
||||
* array elements an update should apply.
|
||||
*
|
||||
* This is not supported for server versions < 3.6 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* Supported options for the bulk write operation:
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation. The default is false.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * ordered (boolean): If true, when an insert fails, return without
|
||||
* performing the remaining writes. If false, when a write fails,
|
||||
* continue with the remaining writes, if any. The default is true.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array[] $operations List of write operations
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $operations, array $options = [])
|
||||
{
|
||||
if (empty($operations)) {
|
||||
throw new InvalidArgumentException('$operations is empty');
|
||||
}
|
||||
|
||||
$expectedIndex = 0;
|
||||
|
||||
foreach ($operations as $i => $operation) {
|
||||
if ($i !== $expectedIndex) {
|
||||
throw new InvalidArgumentException(sprintf('$operations is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($operation)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]', $i), $operation, 'array');
|
||||
}
|
||||
|
||||
if (count($operation) !== 1) {
|
||||
throw new InvalidArgumentException(sprintf('Expected one element in $operation[%d], actually: %d', $i, count($operation)));
|
||||
}
|
||||
|
||||
$type = key($operation);
|
||||
$args = current($operation);
|
||||
|
||||
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])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][0]', $i, $type), $args[0], 'array or object');
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case self::INSERT_ONE:
|
||||
break;
|
||||
|
||||
case self::DELETE_MANY:
|
||||
case self::DELETE_ONE:
|
||||
if ( ! isset($args[1])) {
|
||||
$args[1] = [];
|
||||
}
|
||||
|
||||
if ( ! is_array($args[1])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array');
|
||||
}
|
||||
|
||||
$args[1]['limit'] = ($type === self::DELETE_ONE ? 1 : 0);
|
||||
|
||||
if (isset($args[1]['collation'])) {
|
||||
$this->isCollationUsed = true;
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
$operations[$i][$type][1] = $args[1];
|
||||
|
||||
break;
|
||||
|
||||
case self::REPLACE_ONE:
|
||||
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])) {
|
||||
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 an update operator', $i, $type));
|
||||
}
|
||||
|
||||
if ( ! isset($args[2])) {
|
||||
$args[2] = [];
|
||||
}
|
||||
|
||||
if ( ! is_array($args[2])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]', $i, $type), $args[2], 'array');
|
||||
}
|
||||
|
||||
$args[2]['multi'] = false;
|
||||
$args[2] += ['upsert' => false];
|
||||
|
||||
if (isset($args[2]['collation'])) {
|
||||
$this->isCollationUsed = true;
|
||||
|
||||
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'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["upsert"]', $i, $type), $args[2]['upsert'], 'boolean');
|
||||
}
|
||||
|
||||
$operations[$i][$type][2] = $args[2];
|
||||
|
||||
break;
|
||||
|
||||
case self::UPDATE_MANY:
|
||||
case self::UPDATE_ONE:
|
||||
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])) {
|
||||
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 ( ! isset($args[2])) {
|
||||
$args[2] = [];
|
||||
}
|
||||
|
||||
if ( ! is_array($args[2])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]', $i, $type), $args[2], 'array');
|
||||
}
|
||||
|
||||
$args[2]['multi'] = ($type === self::UPDATE_MANY);
|
||||
$args[2] += ['upsert' => false];
|
||||
|
||||
if (isset($args[2]['arrayFilters'])) {
|
||||
$this->isArrayFiltersUsed = true;
|
||||
|
||||
if ( ! is_array($args[2]['arrayFilters'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["arrayFilters"]', $i, $type), $args[2]['arrayFilters'], 'array');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($args[2]['collation'])) {
|
||||
$this->isCollationUsed = true;
|
||||
|
||||
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'])) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["upsert"]', $i, $type), $args[2]['upsert'], 'boolean');
|
||||
}
|
||||
|
||||
$operations[$i][$type][2] = $args[2];
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Unknown operation type "%s" in $operations[%d]', $type, $i));
|
||||
}
|
||||
|
||||
$expectedIndex += 1;
|
||||
}
|
||||
|
||||
$options += ['ordered' => true];
|
||||
|
||||
if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->operations = $operations;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return BulkWriteResult
|
||||
* @throws UnsupportedException if array filters or collation is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if ($this->isArrayFiltersUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
throw UnsupportedException::arrayFiltersNotSupported();
|
||||
}
|
||||
|
||||
if ($this->isCollationUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
$options = ['ordered' => $this->options['ordered']];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
$bulk = new Bulk($options);
|
||||
$insertedIds = [];
|
||||
|
||||
foreach ($this->operations as $i => $operation) {
|
||||
$type = key($operation);
|
||||
$args = current($operation);
|
||||
|
||||
switch ($type) {
|
||||
case self::DELETE_MANY:
|
||||
case self::DELETE_ONE:
|
||||
$bulk->delete($args[0], $args[1]);
|
||||
break;
|
||||
|
||||
case self::INSERT_ONE:
|
||||
$insertedIds[$i] = $bulk->insert($args[0]);
|
||||
break;
|
||||
|
||||
case self::REPLACE_ONE:
|
||||
case self::UPDATE_MANY:
|
||||
case self::UPDATE_ONE:
|
||||
$bulk->update($args[0], $args[1], $args[2]);
|
||||
}
|
||||
}
|
||||
|
||||
$writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createOptions());
|
||||
|
||||
return new BulkWriteResult($writeResult, $insertedIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the bulk write.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\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\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for the count command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::count()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/count/
|
||||
*/
|
||||
class Count implements Executable, Explainable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $filter;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a count command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * hint (string|document): The index to use. Specify either the index
|
||||
* name as a string or the index key pattern as a document. If specified,
|
||||
* then the query system will only consider plans using the hinted index.
|
||||
*
|
||||
* * limit (integer): The maximum number of documents to count.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * skip (integer): The number of documents to skip before returning the
|
||||
* documents.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter = [], array $options = [])
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return integer
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if collation or read concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->createCommandDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the count command document.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createCommandDocument()
|
||||
{
|
||||
$cmd = ['count' => $this->collectionName];
|
||||
|
||||
if ( ! empty($this->filter)) {
|
||||
$cmd['query'] = (object) $this->filter;
|
||||
}
|
||||
|
||||
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'];
|
||||
}
|
||||
|
||||
foreach (['limit', 'maxTimeMS', 'skip'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\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\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for obtaining an exact count of documents in a collection
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::countDocuments()
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#countdocuments
|
||||
*/
|
||||
class CountDocuments implements Executable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $filter;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs an aggregate command for counting documents
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * hint (string|document): The index to use. Specify either the index
|
||||
* name as a string or the index key pattern as a document. If specified,
|
||||
* then the query system will only consider plans using the hinted index.
|
||||
*
|
||||
* * limit (integer): The maximum number of documents to count.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * skip (integer): The number of documents to skip before returning the
|
||||
* documents.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return integer
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if collation or read concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
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());
|
||||
$allResults = $cursor->toArray();
|
||||
|
||||
/* If there are no documents to count, the aggregation pipeline has no items to group, and
|
||||
* hence the result is an empty array (PHPLIB-376) */
|
||||
if (count($allResults) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$result = current($allResults);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the count command document.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createCommandDocument()
|
||||
{
|
||||
$pipeline = [
|
||||
['$match' => (object) $this->filter]
|
||||
];
|
||||
|
||||
if (isset($this->options['skip'])) {
|
||||
$pipeline[] = ['$skip' => $this->options['skip']];
|
||||
}
|
||||
|
||||
if (isset($this->options['limit'])) {
|
||||
$pipeline[] = ['$limit' => $this->options['limit']];
|
||||
}
|
||||
|
||||
$pipeline[] = ['$group' => ['_id' => null, '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;
|
||||
}
|
||||
}
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the create command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Database::createCollection()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/create/
|
||||
*/
|
||||
class CreateCollection implements Executable
|
||||
{
|
||||
const USE_POWER_OF_2_SIZES = 1;
|
||||
const NO_PADDING = 2;
|
||||
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $options = [];
|
||||
|
||||
/**
|
||||
* Constructs a create command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * autoIndexId (boolean): Specify false to disable the automatic creation
|
||||
* of an index on the _id field. For replica sets, this option cannot be
|
||||
* false. The default is true.
|
||||
*
|
||||
* This option has been deprecated since MongoDB 3.2. As of MongoDB 4.0,
|
||||
* this option cannot be false when creating a replicated collection
|
||||
* (i.e. a collection outside of the local database in any mongod mode).
|
||||
*
|
||||
* * capped (boolean): Specify true to create a capped collection. If set,
|
||||
* the size option must also be specified. The default is false.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * flags (integer): Options for the MMAPv1 storage engine only. Must be a
|
||||
* bitwise combination CreateCollection::USE_POWER_OF_2_SIZES and
|
||||
* CreateCollection::NO_PADDING. The default is
|
||||
* CreateCollection::USE_POWER_OF_2_SIZES.
|
||||
*
|
||||
* * indexOptionDefaults (document): Default configuration for indexes when
|
||||
* creating the collection.
|
||||
*
|
||||
* * max (integer): The maximum number of documents allowed in the capped
|
||||
* collection. The size option takes precedence over this limit.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * size (integer): The maximum number of bytes for a capped collection.
|
||||
*
|
||||
* * storageEngine (document): Storage engine options.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will only be
|
||||
* used for the returned command result document.
|
||||
*
|
||||
* * validationAction (string): Validation action.
|
||||
*
|
||||
* * validationLevel (string): Validation level.
|
||||
*
|
||||
* * validator (document): Validation rules or expressions.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* @see http://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb
|
||||
* @see https://docs.mongodb.org/manual/core/document-validation/
|
||||
* @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['autoIndexId']) && ! is_bool($options['autoIndexId'])) {
|
||||
throw InvalidArgumentException::invalidType('"autoIndexId" option', $options['autoIndexId'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['capped']) && ! is_bool($options['capped'])) {
|
||||
throw InvalidArgumentException::invalidType('"capped" option', $options['capped'], 'boolean');
|
||||
}
|
||||
|
||||
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['flags']) && ! is_integer($options['flags'])) {
|
||||
throw InvalidArgumentException::invalidType('"flags" option', $options['flags'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['indexOptionDefaults']) && ! is_array($options['indexOptionDefaults']) && ! is_object($options['indexOptionDefaults'])) {
|
||||
throw InvalidArgumentException::invalidType('"indexOptionDefaults" option', $options['indexOptionDefaults'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['max']) && ! is_integer($options['max'])) {
|
||||
throw InvalidArgumentException::invalidType('"max" option', $options['max'], 'integer');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['size']) && ! is_integer($options['size'])) {
|
||||
throw InvalidArgumentException::invalidType('"size" option', $options['size'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['storageEngine']) && ! is_array($options['storageEngine']) && ! is_object($options['storageEngine'])) {
|
||||
throw InvalidArgumentException::invalidType('"storageEngine" option', $options['storageEngine'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['validationAction']) && ! is_string($options['validationAction'])) {
|
||||
throw InvalidArgumentException::invalidType('"validationAction" option', $options['validationAction'], 'string');
|
||||
}
|
||||
|
||||
if (isset($options['validationLevel']) && ! is_string($options['validationLevel'])) {
|
||||
throw InvalidArgumentException::invalidType('"validationLevel" option', $options['validationLevel'], 'string');
|
||||
}
|
||||
|
||||
if (isset($options['validator']) && ! is_array($options['validator']) && ! is_object($options['validator'])) {
|
||||
throw InvalidArgumentException::invalidType('"validator" option', $options['validator'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
if (isset($options['autoIndexId'])) {
|
||||
trigger_error('The "autoIndexId" option is deprecated and will be removed in a future release', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if collation or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return current($cursor->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the create command.
|
||||
*
|
||||
* @return Command
|
||||
*/
|
||||
private function createCommand()
|
||||
{
|
||||
$cmd = ['create' => $this->collectionName];
|
||||
|
||||
foreach (['autoIndexId', 'capped', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['collation', 'indexOptionDefaults', 'storageEngine', 'validator'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = (object) $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
return new Command($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the createIndexes command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::createIndex()
|
||||
* @see \MongoDB\Collection::createIndexes()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
|
||||
*/
|
||||
class CreateIndexes implements Executable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $indexes = [];
|
||||
private $isCollationUsed = false;
|
||||
private $options = [];
|
||||
|
||||
/**
|
||||
* Constructs a createIndexes command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array[] $indexes List of index specifications
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $indexes, array $options = [])
|
||||
{
|
||||
if (empty($indexes)) {
|
||||
throw new InvalidArgumentException('$indexes is empty');
|
||||
}
|
||||
|
||||
$expectedIndex = 0;
|
||||
|
||||
foreach ($indexes as $i => $index) {
|
||||
if ($i !== $expectedIndex) {
|
||||
throw new InvalidArgumentException(sprintf('$indexes is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($index)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$index[%d]', $i), $index, 'array');
|
||||
}
|
||||
|
||||
if ( ! isset($index['ns'])) {
|
||||
$index['ns'] = $databaseName . '.' . $collectionName;
|
||||
}
|
||||
|
||||
if (isset($index['collation'])) {
|
||||
$this->isCollationUsed = true;
|
||||
}
|
||||
|
||||
$this->indexes[] = new IndexInput($index);
|
||||
|
||||
$expectedIndex += 1;
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return string[] The names of the created indexes
|
||||
* @throws UnsupportedException if collation or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if ($this->isCollationUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$this->executeCommand($server);
|
||||
|
||||
return array_map(function(IndexInput $index) { return (string) $index; }, $this->indexes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one or more indexes for the collection using the createIndexes
|
||||
* command.
|
||||
*
|
||||
* @param Server $server
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
private function executeCommand(Server $server)
|
||||
{
|
||||
$cmd = [
|
||||
'createIndexes' => $this->collectionName,
|
||||
'indexes' => $this->indexes,
|
||||
];
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
$server->executeWriteCommand($this->databaseName, new Command($cmd), $this->createOptions());
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\ReadPreference;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Operation for executing a database command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Database::command()
|
||||
*/
|
||||
class DatabaseCommand implements Executable
|
||||
{
|
||||
private $databaseName;
|
||||
private $command;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * readPreference (MongoDB\Driver\ReadPreference): The read preference to
|
||||
* use when executing the command. This may be used when issuing the
|
||||
* command to a replica set or mongos node to ensure that the driver sets
|
||||
* the wire protocol accordingly or adds the read preference to the
|
||||
* command document, respectively.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * 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
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $command, array $options = [])
|
||||
{
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->command = ($command instanceof Command) ? $command : new Command($command);
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return Cursor
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
$cursor = $server->executeCommand($this->databaseName, $this->command, $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return $cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\DeleteResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the delete command.
|
||||
*
|
||||
* This class is used internally by the DeleteMany and DeleteOne operation
|
||||
* classes.
|
||||
*
|
||||
* @internal
|
||||
* @see http://docs.mongodb.org/manual/reference/command/delete/
|
||||
*/
|
||||
class Delete implements Executable, Explainable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $filter;
|
||||
private $limit;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a delete command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to delete documents
|
||||
* @param integer $limit The number of matching documents to
|
||||
* delete. Must be 0 or 1, for all or a
|
||||
* single document, respectively.
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $limit, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if ($limit !== 0 && $limit !== 1) {
|
||||
throw new InvalidArgumentException('$limit must be 0 or 1');
|
||||
}
|
||||
|
||||
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['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->filter = $filter;
|
||||
$this->limit = $limit;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return DeleteResult
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
$bulk = new Bulk();
|
||||
$bulk->delete($this->filter, $this->createDeleteOptions());
|
||||
|
||||
$writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions());
|
||||
|
||||
return new DeleteResult($writeResult);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
$cmd = ['delete' => $this->collectionName, 'deletes' => [['q' => $this->filter] + $this->createDeleteOptions()]];
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$cmd['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for the delete command.
|
||||
*
|
||||
* Note that these options are different from the bulk write options, which
|
||||
* are created in createExecuteOptions().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createDeleteOptions()
|
||||
{
|
||||
$deleteOptions = ['limit' => $this->limit];
|
||||
|
||||
if (isset($this->options['collation'])) {
|
||||
$deleteOptions['collation'] = (object) $this->options['collation'];
|
||||
}
|
||||
|
||||
return $deleteOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the bulk write.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php
|
||||
* @return array
|
||||
*/
|
||||
private function createExecuteOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\DeleteResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for deleting multiple document with the delete command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::deleteOne()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/delete/
|
||||
*/
|
||||
class DeleteMany implements Executable, Explainable
|
||||
{
|
||||
private $delete;
|
||||
|
||||
/**
|
||||
* Constructs a delete command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to delete documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
$this->delete = new Delete($databaseName, $collectionName, $filter, 0, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return DeleteResult
|
||||
* @throws UnsupportedException if collation is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->delete->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->delete->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\DeleteResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for deleting a single document with the delete command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::deleteOne()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/delete/
|
||||
*/
|
||||
class DeleteOne implements Executable, Explainable
|
||||
{
|
||||
private $delete;
|
||||
|
||||
/**
|
||||
* Constructs a delete command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to delete documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
$this->delete = new Delete($databaseName, $collectionName, $filter, 1, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return DeleteResult
|
||||
* @throws UnsupportedException if collation is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->delete->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->delete->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\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\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for the distinct command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::distinct()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/distinct/
|
||||
*/
|
||||
class Distinct implements Executable, Explainable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $fieldName;
|
||||
private $filter;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a distinct command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @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
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $fieldName, $filter = [], array $options = [])
|
||||
{
|
||||
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['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->fieldName = (string) $fieldName;
|
||||
$this->filter = $filter;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return mixed[]
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if collation or read concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
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());
|
||||
|
||||
if ( ! isset($result->values) || ! is_array($result->values)) {
|
||||
throw new UnexpectedValueException('distinct command did not return a "values" array');
|
||||
}
|
||||
|
||||
return $result->values;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->createCommandDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the distinct command document.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createCommandDocument()
|
||||
{
|
||||
$cmd = [
|
||||
'distinct' => $this->collectionName,
|
||||
'key' => $this->fieldName,
|
||||
];
|
||||
|
||||
if ( ! empty($this->filter)) {
|
||||
$cmd['query'] = (object) $this->filter;
|
||||
}
|
||||
|
||||
if (isset($this->options['collation'])) {
|
||||
$cmd['collation'] = (object) $this->options['collation'];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the drop command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::drop()
|
||||
* @see \MongoDB\Database::dropCollection()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/drop/
|
||||
*/
|
||||
class DropCollection implements Executable
|
||||
{
|
||||
private static $errorMessageNamespaceNotFound = 'ns not found';
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a drop command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be used
|
||||
* for the returned command result document.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if writeConcern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$command = new Command(['drop' => $this->collectionName]);
|
||||
|
||||
try {
|
||||
$cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions());
|
||||
} catch (DriverRuntimeException $e) {
|
||||
/* The server may return an error if the collection does not exist.
|
||||
* Check for an error message (unfortunately, there isn't a code)
|
||||
* and NOP instead of throwing.
|
||||
*/
|
||||
if ($e->getMessage() === self::$errorMessageNamespaceNotFound) {
|
||||
return (object) ['ok' => 0, 'errmsg' => self::$errorMessageNamespaceNotFound];
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return current($cursor->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the dropDatabase command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Client::dropDatabase()
|
||||
* @see \MongoDB\Database::drop()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/dropDatabase/
|
||||
*/
|
||||
class DropDatabase implements Executable
|
||||
{
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a dropDatabase command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be used
|
||||
* for the returned command result document.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, array $options = [])
|
||||
{
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if writeConcern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$command = new Command(['dropDatabase' => 1]);
|
||||
$cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return current($cursor->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the dropIndexes command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::dropIndexes()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/dropIndexes/
|
||||
*/
|
||||
class DropIndexes implements Executable
|
||||
{
|
||||
private static $wireVersionForWriteConcern = 5;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $indexName;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a dropIndexes command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be used
|
||||
* for the returned command result document.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param string $indexName Index name (use "*" to drop all indexes)
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $indexName, array $options = [])
|
||||
{
|
||||
$indexName = (string) $indexName;
|
||||
|
||||
if ($indexName === '') {
|
||||
throw new InvalidArgumentException('$indexName cannot be empty');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->indexName = $indexName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object Command result document
|
||||
* @throws UnsupportedException if writeConcern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return current($cursor->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the dropIndexes command.
|
||||
*
|
||||
* @return Command
|
||||
*/
|
||||
private function createCommand()
|
||||
{
|
||||
$cmd = [
|
||||
'dropIndexes' => $this->collectionName,
|
||||
'index' => $this->indexName,
|
||||
];
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
return new Command($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\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\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnexpectedValueException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for obtaining an estimated count of documents in a collection
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::estimatedDocumentCount()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/count/
|
||||
*/
|
||||
class EstimatedDocumentCount implements Executable, Explainable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a count command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return integer
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if collation or read concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->createCommandDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the count command document.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createCommandDocument()
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
|
||||
/**
|
||||
* Executable interface for operation classes.
|
||||
*
|
||||
* This interface is reserved for internal use until PHPC-378 is implemented,
|
||||
* since execute() should ultimately be changed to use ServerInterface.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface Executable
|
||||
{
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute(Server $server);
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2018 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\Operation;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the explain command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::explain()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/explain/
|
||||
*/
|
||||
class Explain implements Executable
|
||||
{
|
||||
const VERBOSITY_ALL_PLANS = 'allPlansExecution';
|
||||
const VERBOSITY_EXEC_STATS = 'executionStats';
|
||||
const VERBOSITY_QUERY = 'queryPlanner';
|
||||
|
||||
private static $wireVersionForDistinct = 4;
|
||||
private static $wireVersionForFindAndModify = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $explainable;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs an explain command for explainable operations.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be used
|
||||
* used for the returned command result document.
|
||||
*
|
||||
* * verbosity (string): The mode in which the explain command will be run.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param Explainable $explainable Operation to explain
|
||||
* @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');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['verbosity']) && ! is_string($options['verbosity'])) {
|
||||
throw InvalidArgumentException::invalidType('"verbosity" option', $options['verbosity'], 'string');
|
||||
}
|
||||
|
||||
$this->databaseName = $databaseName;
|
||||
$this->explainable = $explainable;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if ($this->explainable instanceof Distinct && ! \MongoDB\server_supports_feature($server, self::$wireVersionForDistinct)) {
|
||||
throw UnsupportedException::explainNotSupported();
|
||||
}
|
||||
|
||||
if ($this->isFindAndModify($this->explainable) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModify)) {
|
||||
throw UnsupportedException::explainNotSupported();
|
||||
}
|
||||
|
||||
$cmd = ['explain' => $this->explainable->getCommandDocument($server)];
|
||||
|
||||
if (isset($this->options['verbosity'])) {
|
||||
$cmd['verbosity'] = $this->options['verbosity'];
|
||||
}
|
||||
|
||||
$cursor = $server->executeCommand($this->databaseName, new Command($cmd), $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return current($cursor->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
private function isFindAndModify($explainable)
|
||||
{
|
||||
if ($explainable instanceof FindAndModify || $explainable instanceof FindOneAndDelete || $explainable instanceof FindOneAndReplace || $explainable instanceof FindOneAndUpdate) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2018 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\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
|
||||
/**
|
||||
* Explainable interface for explainable operations (count, distinct, find,
|
||||
* findAndModify, delete, and update).
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface Explainable extends Executable
|
||||
{
|
||||
function getCommandDocument(Server $server);
|
||||
}
|
||||
+416
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Cursor;
|
||||
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;
|
||||
/**
|
||||
* Operation for the find command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::find()
|
||||
* @see http://docs.mongodb.org/manual/tutorial/query-documents/
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query-modifier/
|
||||
*/
|
||||
class Find implements Executable, Explainable
|
||||
{
|
||||
const NON_TAILABLE = 1;
|
||||
const TAILABLE = 2;
|
||||
const TAILABLE_AWAIT = 3;
|
||||
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $filter;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a find command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * allowPartialResults (boolean): Get partial results from a mongos if
|
||||
* some shards are inaccessible (instead of throwing an error).
|
||||
*
|
||||
* * batchSize (integer): The number of documents to return per batch.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * comment (string): Attaches a comment to the query. If "$comment" also
|
||||
* exists in the modifiers document, this option will take precedence.
|
||||
*
|
||||
* * cursorType (enum): Indicates the type of cursor to use. Must be either
|
||||
* NON_TAILABLE, TAILABLE, or TAILABLE_AWAIT. The default is
|
||||
* NON_TAILABLE.
|
||||
*
|
||||
* * hint (string|document): The index to use. Specify either the index
|
||||
* name as a string or the index key pattern as a document. If specified,
|
||||
* then the query system will only consider plans using the hinted index.
|
||||
*
|
||||
* * limit (integer): The maximum number of documents to return.
|
||||
*
|
||||
* * max (document): The exclusive upper bound for a specific index.
|
||||
*
|
||||
* * maxAwaitTimeMS (integer): The maxium amount of time for the server to wait
|
||||
* on new documents to satisfy a query, if cursorType is TAILABLE_AWAIT.
|
||||
*
|
||||
* * maxScan (integer): Maximum number of documents or index keys to scan
|
||||
* when executing the query.
|
||||
*
|
||||
* This option has been deprecated since version 1.4.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run. If "$maxTimeMS" also exists in the modifiers document, this
|
||||
* option will take precedence.
|
||||
*
|
||||
* * min (document): The inclusive upper bound for a specific index.
|
||||
*
|
||||
* * modifiers (document): Meta operators that modify the output or
|
||||
* behavior of a query. Use of these operators is deprecated in favor of
|
||||
* named options.
|
||||
*
|
||||
* * noCursorTimeout (boolean): The server normally times out idle cursors
|
||||
* after an inactivity period (10 minutes) to prevent excess memory use.
|
||||
* Set this option to prevent that.
|
||||
*
|
||||
* * oplogReplay (boolean): Internal replication use only. The driver
|
||||
* should not set this.
|
||||
*
|
||||
* * projection (document): Limits the fields to return for the matching
|
||||
* document.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * returnKey (boolean): If true, returns only the index keys in the
|
||||
* resulting documents.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * showRecordId (boolean): Determines whether to return the record
|
||||
* identifier for each document. If true, adds a field $recordId to the
|
||||
* returned documents.
|
||||
*
|
||||
* * skip (integer): The number of documents to skip before returning.
|
||||
*
|
||||
* * snapshot (boolean): Prevents the cursor from returning a document more
|
||||
* than once because of an intervening write operation.
|
||||
*
|
||||
* This options has been deprecated since version 1.4.
|
||||
*
|
||||
* * sort (document): The order in which to return matching documents. If
|
||||
* "$orderby" also exists in the modifiers document, this option will
|
||||
* take precedence.
|
||||
*
|
||||
* * 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 string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['allowPartialResults']) && ! is_bool($options['allowPartialResults'])) {
|
||||
throw InvalidArgumentException::invalidType('"allowPartialResults" option', $options['allowPartialResults'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['batchSize']) && ! is_integer($options['batchSize'])) {
|
||||
throw InvalidArgumentException::invalidType('"batchSize" option', $options['batchSize'], 'integer');
|
||||
}
|
||||
|
||||
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['comment']) && ! is_string($options['comment'])) {
|
||||
throw InvalidArgumentException::invalidType('"comment" option', $options['comment'], 'comment');
|
||||
}
|
||||
|
||||
if (isset($options['cursorType'])) {
|
||||
if ( ! is_integer($options['cursorType'])) {
|
||||
throw InvalidArgumentException::invalidType('"cursorType" option', $options['cursorType'], 'integer');
|
||||
}
|
||||
|
||||
if ($options['cursorType'] !== self::NON_TAILABLE &&
|
||||
$options['cursorType'] !== self::TAILABLE &&
|
||||
$options['cursorType'] !== self::TAILABLE_AWAIT) {
|
||||
throw new InvalidArgumentException('Invalid value for "cursorType" option: ' . $options['cursorType']);
|
||||
}
|
||||
}
|
||||
|
||||
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['max']) && ! is_array($options['max']) && ! is_object($options['max'])) {
|
||||
throw InvalidArgumentException::invalidType('"max" option', $options['max'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['maxAwaitTimeMS']) && ! is_integer($options['maxAwaitTimeMS'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxAwaitTimeMS" option', $options['maxAwaitTimeMS'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['maxScan']) && ! is_integer($options['maxScan'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxScan" option', $options['maxScan'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['min']) && ! is_array($options['min']) && ! is_object($options['min'])) {
|
||||
throw InvalidArgumentException::invalidType('"min" option', $options['min'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['modifiers']) && ! is_array($options['modifiers']) && ! is_object($options['modifiers'])) {
|
||||
throw InvalidArgumentException::invalidType('"modifiers" option', $options['modifiers'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['noCursorTimeout']) && ! is_bool($options['noCursorTimeout'])) {
|
||||
throw InvalidArgumentException::invalidType('"noCursorTimeout" option', $options['noCursorTimeout'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['oplogReplay']) && ! is_bool($options['oplogReplay'])) {
|
||||
throw InvalidArgumentException::invalidType('"oplogReplay" option', $options['oplogReplay'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) {
|
||||
throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object');
|
||||
}
|
||||
|
||||
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['returnKey']) && ! is_bool($options['returnKey'])) {
|
||||
throw InvalidArgumentException::invalidType('"returnKey" option', $options['returnKey'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['showRecordId']) && ! is_bool($options['showRecordId'])) {
|
||||
throw InvalidArgumentException::invalidType('"showRecordId" option', $options['showRecordId'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['skip']) && ! is_integer($options['skip'])) {
|
||||
throw InvalidArgumentException::invalidType('"skip" option', $options['skip'], 'integer');
|
||||
}
|
||||
|
||||
if (isset($options['snapshot']) && ! is_bool($options['snapshot'])) {
|
||||
throw InvalidArgumentException::invalidType('"snapshot" option', $options['snapshot'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) {
|
||||
throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && $options['readConcern']->isDefault()) {
|
||||
unset($options['readConcern']);
|
||||
}
|
||||
|
||||
if (isset($options['snapshot'])) {
|
||||
trigger_error('The "snapshot" option is deprecated and will be removed in a future release', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
if (isset($options['maxScan'])) {
|
||||
trigger_error('The "maxScan" option is deprecated and will be removed in a future release', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->filter = $filter;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return Cursor
|
||||
* @throws UnsupportedException if collation or read concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
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->executeQuery($this->databaseName . '.' . $this->collectionName, new Query($this->filter, $this->createQueryOptions()), $this->createExecuteOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return $cursor;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->createCommandDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a command document for Find
|
||||
*/
|
||||
private function createCommandDocument()
|
||||
{
|
||||
$cmd = ['find' => $this->collectionName, 'filter' => (object) $this->filter];
|
||||
|
||||
$options = $this->createQueryOptions();
|
||||
|
||||
if (empty($options)) {
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
// maxAwaitTimeMS is a Query level option so should not be considered here
|
||||
unset($options['maxAwaitTimeMS']);
|
||||
|
||||
$modifierFallback = [
|
||||
['allowPartialResults', 'partial'],
|
||||
['comment', '$comment'],
|
||||
['hint', '$hint'],
|
||||
['maxScan', '$maxScan'],
|
||||
['max', '$max'],
|
||||
['maxTimeMS', '$maxTimeMS'],
|
||||
['min', '$min'],
|
||||
['returnKey', '$returnKey'],
|
||||
['showRecordId', '$showDiskLoc'],
|
||||
['sort', '$orderby'],
|
||||
['snapshot', '$snapshot'],
|
||||
];
|
||||
|
||||
foreach ($modifierFallback as $modifier) {
|
||||
if ( ! isset($options[$modifier[0]]) && isset($options['modifiers'][$modifier[1]])) {
|
||||
$options[$modifier[0]] = $options['modifiers'][$modifier[1]];
|
||||
}
|
||||
}
|
||||
unset($options['modifiers']);
|
||||
|
||||
return $cmd + $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executequery.php
|
||||
* @return array
|
||||
*/
|
||||
private function createExecuteOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for the find query.
|
||||
*
|
||||
* Note that these are separate from the options for executing the command,
|
||||
* which are created in createExecuteOptions().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createQueryOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['cursorType'])) {
|
||||
if ($this->options['cursorType'] === self::TAILABLE) {
|
||||
$options['tailable'] = true;
|
||||
}
|
||||
if ($this->options['cursorType'] === self::TAILABLE_AWAIT) {
|
||||
$options['tailable'] = true;
|
||||
$options['awaitData'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['allowPartialResults', 'batchSize', 'comment', 'hint', 'limit', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$options[$option] = $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['collation', 'max', 'min'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$options[$option] = (object) $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
$modifiers = empty($this->options['modifiers']) ? [] : (array) $this->options['modifiers'];
|
||||
|
||||
if ( ! empty($modifiers)) {
|
||||
$options['modifiers'] = $modifiers;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the findAndModify command.
|
||||
*
|
||||
* This class is used internally by the FindOneAndDelete, FindOneAndReplace, and
|
||||
* FindOneAndUpdate operation classes.
|
||||
*
|
||||
* @internal
|
||||
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
|
||||
*/
|
||||
class FindAndModify implements Executable, Explainable
|
||||
{
|
||||
private static $wireVersionForArrayFilters = 6;
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
private static $wireVersionForWriteConcern = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a findAndModify command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * arrayFilters (document array): A set of filters specifying to which
|
||||
* array elements an update should apply.
|
||||
*
|
||||
* This is not supported for server versions < 3.6 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * fields (document): Limits the fields to return for the matching
|
||||
* document.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * new (boolean): When true, returns the modified document rather than
|
||||
* the original. This option is ignored for remove operations. The
|
||||
* The default is false.
|
||||
*
|
||||
* * query (document): Query by which to filter documents.
|
||||
*
|
||||
* * remove (boolean): When true, removes the matched document. This option
|
||||
* cannot be true if the update option is set. The default is false.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * sort (document): Determines which document the operation modifies if
|
||||
* the query selects multiple documents.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization.
|
||||
*
|
||||
* * update (document): Update or replacement to apply to the matched
|
||||
* document. This option cannot be set if the remove option is true.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. This option is ignored for remove operations. The
|
||||
* default is false.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* 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 name
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $options)
|
||||
{
|
||||
$options += [
|
||||
'new' => false,
|
||||
'remove' => false,
|
||||
'upsert' => false,
|
||||
];
|
||||
|
||||
if (isset($options['arrayFilters']) && ! is_array($options['arrayFilters'])) {
|
||||
throw InvalidArgumentException::invalidType('"arrayFilters" option', $options['arrayFilters'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
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['fields']) && ! is_array($options['fields']) && ! is_object($options['fields'])) {
|
||||
throw InvalidArgumentException::invalidType('"fields" option', $options['fields'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
|
||||
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['new'])) {
|
||||
throw InvalidArgumentException::invalidType('"new" option', $options['new'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['query']) && ! is_array($options['query']) && ! is_object($options['query'])) {
|
||||
throw InvalidArgumentException::invalidType('"query" option', $options['query'], 'array or object');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) {
|
||||
throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['update']) && ! is_array($options['update']) && ! is_object($options['update'])) {
|
||||
throw InvalidArgumentException::invalidType('"update" option', $options['update'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['upsert'])) {
|
||||
throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object|null
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if array filters, collation, or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['arrayFilters']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
throw UnsupportedException::arrayFiltersNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
|
||||
return $result->value;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->createCommandDocument($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the findAndModify command document.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createCommandDocument(Server $server)
|
||||
{
|
||||
$cmd = ['findAndModify' => $this->collectionName];
|
||||
|
||||
if ($this->options['remove']) {
|
||||
$cmd['remove'] = true;
|
||||
} else {
|
||||
$cmd['new'] = $this->options['new'];
|
||||
$cmd['upsert'] = $this->options['upsert'];
|
||||
}
|
||||
|
||||
foreach (['collation', 'fields', 'query', 'sort', 'update'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = (object) $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->options['arrayFilters'])) {
|
||||
$cmd['arrayFilters'] = $this->options['arrayFilters'];
|
||||
}
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for finding a single document with the find command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::findOne()
|
||||
* @see http://docs.mongodb.org/manual/tutorial/query-documents/
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query-modifier/
|
||||
*/
|
||||
class FindOne implements Executable, Explainable
|
||||
{
|
||||
private $find;
|
||||
|
||||
/**
|
||||
* Constructs a find command for finding a single document.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * comment (string): Attaches a comment to the query. If "$comment" also
|
||||
* exists in the modifiers document, this option will take precedence.
|
||||
*
|
||||
* * hint (string|document): The index to use. Specify either the index
|
||||
* name as a string or the index key pattern as a document. If specified,
|
||||
* then the query system will only consider plans using the hinted index.
|
||||
*
|
||||
* * max (document): The exclusive upper bound for a specific index.
|
||||
*
|
||||
* * maxScan (integer): Maximum number of documents or index keys to scan
|
||||
* when executing the query.
|
||||
*
|
||||
* This option has been deprecated since version 1.4.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run. If "$maxTimeMS" also exists in the modifiers document, this
|
||||
* option will take precedence.
|
||||
*
|
||||
* * min (document): The inclusive upper bound for a specific index.
|
||||
*
|
||||
* * modifiers (document): Meta-operators modifying the output or behavior
|
||||
* of a query.
|
||||
*
|
||||
* * projection (document): Limits the fields to return for the matching
|
||||
* document.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * returnKey (boolean): If true, returns only the index keys in the
|
||||
* resulting documents.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * showRecordId (boolean): Determines whether to return the record
|
||||
* identifier for each document. If true, adds a field $recordId to the
|
||||
* returned documents.
|
||||
*
|
||||
* * skip (integer): The number of documents to skip before returning.
|
||||
*
|
||||
* * sort (document): The order in which to return matching documents. If
|
||||
* "$orderby" also exists in the modifiers document, this option will
|
||||
* take precedence.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
$this->find = new Find(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
$filter,
|
||||
['limit' => 1] + $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object|null
|
||||
* @throws UnsupportedException if collation or read concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
$cursor = $this->find->execute($server);
|
||||
$document = current($cursor->toArray());
|
||||
|
||||
return ($document === false) ? null : $document;
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->find->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for deleting a document with the findAndModify command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::findOneAndDelete()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
|
||||
*/
|
||||
class FindOneAndDelete implements Executable, Explainable
|
||||
{
|
||||
private $findAndModify;
|
||||
|
||||
/**
|
||||
* Constructs a findAndModify command for deleting a document.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * projection (document): Limits the fields to return for the matching
|
||||
* document.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * sort (document): Determines which document the operation modifies if
|
||||
* the query selects multiple documents.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* 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 name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) {
|
||||
throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['projection'])) {
|
||||
$options['fields'] = $options['projection'];
|
||||
}
|
||||
|
||||
unset($options['projection']);
|
||||
|
||||
$this->findAndModify = new FindAndModify(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
['query' => $filter, 'remove' => true] + $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object|null
|
||||
* @throws UnsupportedException if collation or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->findAndModify->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->findAndModify->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for replacing a document with the findAndModify command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::findOneAndReplace()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
|
||||
*/
|
||||
class FindOneAndReplace implements Executable, Explainable
|
||||
{
|
||||
const RETURN_DOCUMENT_BEFORE = 1;
|
||||
const RETURN_DOCUMENT_AFTER = 2;
|
||||
|
||||
private $findAndModify;
|
||||
|
||||
/**
|
||||
* Constructs a findAndModify command for replacing a document.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * projection (document): Limits the fields to return for the matching
|
||||
* document.
|
||||
*
|
||||
* * returnDocument (enum): Whether to return the document before or after
|
||||
* the update is applied. Must be either
|
||||
* FindOneAndReplace::RETURN_DOCUMENT_BEFORE or
|
||||
* FindOneAndReplace::RETURN_DOCUMENT_AFTER. The default is
|
||||
* FindOneAndReplace::RETURN_DOCUMENT_BEFORE.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * sort (document): Determines which document the operation modifies if
|
||||
* the query selects multiple documents.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. The default is false.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* 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 name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array|object $replacement Replacement document
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_array($replacement) && ! is_object($replacement)) {
|
||||
throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object');
|
||||
}
|
||||
|
||||
if (\MongoDB\is_first_key_operator($replacement)) {
|
||||
throw new InvalidArgumentException('First key in $replacement argument is an update operator');
|
||||
}
|
||||
|
||||
$options += [
|
||||
'returnDocument' => self::RETURN_DOCUMENT_BEFORE,
|
||||
'upsert' => false,
|
||||
];
|
||||
|
||||
if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) {
|
||||
throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_integer($options['returnDocument'])) {
|
||||
throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer');
|
||||
}
|
||||
|
||||
if ($options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER &&
|
||||
$options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE) {
|
||||
throw new InvalidArgumentException('Invalid value for "returnDocument" option: ' . $options['returnDocument']);
|
||||
}
|
||||
|
||||
if (isset($options['projection'])) {
|
||||
$options['fields'] = $options['projection'];
|
||||
}
|
||||
|
||||
$options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER;
|
||||
|
||||
unset($options['projection'], $options['returnDocument']);
|
||||
|
||||
$this->findAndModify = new FindAndModify(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
['query' => $filter, 'update' => $replacement] + $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object|null
|
||||
* @throws UnsupportedException if collation or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->findAndModify->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->findAndModify->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for updating a document with the findAndModify command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::findOneAndUpdate()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/findAndModify/
|
||||
*/
|
||||
class FindOneAndUpdate implements Executable, Explainable
|
||||
{
|
||||
const RETURN_DOCUMENT_BEFORE = 1;
|
||||
const RETURN_DOCUMENT_AFTER = 2;
|
||||
|
||||
private $findAndModify;
|
||||
|
||||
/**
|
||||
* Constructs a findAndModify command for updating a document.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * arrayFilters (document array): A set of filters specifying to which
|
||||
* array elements an update should apply.
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * projection (document): Limits the fields to return for the matching
|
||||
* document.
|
||||
*
|
||||
* * returnDocument (enum): Whether to return the document before or after
|
||||
* the update is applied. Must be either
|
||||
* FindOneAndUpdate::RETURN_DOCUMENT_BEFORE or
|
||||
* FindOneAndUpdate::RETURN_DOCUMENT_AFTER. The default is
|
||||
* FindOneAndUpdate::RETURN_DOCUMENT_BEFORE.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * sort (document): Determines which document the operation modifies if
|
||||
* the query selects multiple documents.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. The default is false.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* 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 name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array|object $update Update to apply to the matched document
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
$options += [
|
||||
'returnDocument' => self::RETURN_DOCUMENT_BEFORE,
|
||||
'upsert' => false,
|
||||
];
|
||||
|
||||
if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) {
|
||||
throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_integer($options['returnDocument'])) {
|
||||
throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer');
|
||||
}
|
||||
|
||||
if ($options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER &&
|
||||
$options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE) {
|
||||
throw new InvalidArgumentException('Invalid value for "returnDocument" option: ' . $options['returnDocument']);
|
||||
}
|
||||
|
||||
if (isset($options['projection'])) {
|
||||
$options['fields'] = $options['projection'];
|
||||
}
|
||||
|
||||
$options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER;
|
||||
|
||||
unset($options['projection'], $options['returnDocument']);
|
||||
|
||||
$this->findAndModify = new FindAndModify(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
['query' => $filter, 'update' => $update] + $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object|null
|
||||
* @throws UnsupportedException if collation or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->findAndModify->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->findAndModify->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\InsertManyResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Operation for inserting multiple documents with the insert command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::insertMany()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/insert/
|
||||
*/
|
||||
class InsertMany implements Executable
|
||||
{
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $documents;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs an insert command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * ordered (boolean): If true, when an insert fails, return without
|
||||
* performing the remaining writes. If false, when a write fails,
|
||||
* continue with the remaining writes, if any. The default is true.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array[]|object[] $documents List of documents to insert
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $documents, array $options = [])
|
||||
{
|
||||
if (empty($documents)) {
|
||||
throw new InvalidArgumentException('$documents is empty');
|
||||
}
|
||||
|
||||
$expectedIndex = 0;
|
||||
|
||||
foreach ($documents as $i => $document) {
|
||||
if ($i !== $expectedIndex) {
|
||||
throw new InvalidArgumentException(sprintf('$documents is not a list (unexpected index: "%s")', $i));
|
||||
}
|
||||
|
||||
if ( ! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType(sprintf('$documents[%d]', $i), $document, 'array or object');
|
||||
}
|
||||
|
||||
$expectedIndex += 1;
|
||||
}
|
||||
|
||||
$options += ['ordered' => true];
|
||||
|
||||
if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->documents = $documents;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return InsertManyResult
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
$options = ['ordered' => $this->options['ordered']];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
$bulk = new Bulk($options);
|
||||
$insertedIds = [];
|
||||
|
||||
foreach ($this->documents as $i => $document) {
|
||||
$insertedIds[$i] = $bulk->insert($document);
|
||||
}
|
||||
|
||||
$writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createOptions());
|
||||
|
||||
return new InsertManyResult($writeResult, $insertedIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the bulk write.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\InsertOneResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Operation for inserting a single document with the insert command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::insertOne()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/insert/
|
||||
*/
|
||||
class InsertOne implements Executable
|
||||
{
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $document;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs an insert command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $document Document to insert
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $document, array $options = [])
|
||||
{
|
||||
if ( ! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->document = $document;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return InsertOneResult
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
$bulk = new Bulk($options);
|
||||
$insertedId = $bulk->insert($this->document);
|
||||
|
||||
$writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createOptions());
|
||||
|
||||
return new InsertOneResult($writeResult, $insertedId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the bulk write.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Query;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the listCollections command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Database::listCollections()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/listCollections/
|
||||
*/
|
||||
class ListCollections implements Executable
|
||||
{
|
||||
private $databaseName;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a listCollections command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * filter (document): Query by which to filter collections.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, array $options = [])
|
||||
{
|
||||
if (isset($options['filter']) && ! is_array($options['filter']) && ! is_object($options['filter'])) {
|
||||
throw InvalidArgumentException::invalidType('"filter" option', $options['filter'], 'array or object');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return CollectionInfoIterator
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->executeCommand($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* Note: read preference is intentionally omitted, as the spec requires that
|
||||
* the command be executed on the primary.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information for all collections in this database using the
|
||||
* listCollections command.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return CollectionInfoCommandIterator
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
private function executeCommand(Server $server)
|
||||
{
|
||||
$cmd = ['listCollections' => 1];
|
||||
|
||||
if ( ! empty($this->options['filter'])) {
|
||||
$cmd['filter'] = (object) $this->options['filter'];
|
||||
}
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
$cursor = $server->executeCommand($this->databaseName, new Command($cmd), $this->createOptions());
|
||||
$cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
|
||||
|
||||
return new CollectionInfoCommandIterator(new CachingIterator($cursor));
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the ListDatabases command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Client::listDatabases()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/ListDatabases/
|
||||
*/
|
||||
class ListDatabases implements Executable
|
||||
{
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a listDatabases command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * filter (document): Query by which to filter databases.
|
||||
*
|
||||
* For servers < 3.6, this option is ignored.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
if (isset($options['filter']) && ! is_array($options['filter']) && ! is_object($options['filter'])) {
|
||||
throw InvalidArgumentException::invalidType('"filter" option', $options['filter'], 'array or object');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return DatabaseInfoIterator
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
$cmd = ['listDatabases' => 1];
|
||||
|
||||
if ( ! empty($this->options['filter'])) {
|
||||
$cmd['filter'] = (object) $this->options['filter'];
|
||||
}
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
$cursor = $server->executeCommand('admin', new Command($cmd), $this->createOptions());
|
||||
$cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
if ( ! isset($result['databases']) || ! is_array($result['databases'])) {
|
||||
throw new UnexpectedValueException('listDatabases command did not return a "databases" array');
|
||||
}
|
||||
|
||||
/* Return an Iterator instead of an array in case listDatabases is
|
||||
* eventually changed to return a command cursor, like the collection
|
||||
* and index enumeration commands. This makes the "totalSize" command
|
||||
* field inaccessible, but users can manually invoke the command if they
|
||||
* need that value.
|
||||
*/
|
||||
return new DatabaseInfoLegacyIterator($result['databases']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* Note: read preference is intentionally omitted, as the spec requires that
|
||||
* the command be executed on the primary.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Query;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the listIndexes command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::listIndexes()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/listIndexes/
|
||||
*/
|
||||
class ListIndexes implements Executable
|
||||
{
|
||||
private static $errorCodeDatabaseNotFound = 60;
|
||||
private static $errorCodeNamespaceNotFound = 26;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a listIndexes command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* @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['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return IndexInfoIterator
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->executeCommand($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* Note: read preference is intentionally omitted, as the spec requires that
|
||||
* the command be executed on the primary.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information for all indexes for this collection using the
|
||||
* listIndexes command.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return IndexInfoIteratorIterator
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
private function executeCommand(Server $server)
|
||||
{
|
||||
$cmd = ['listIndexes' => $this->collectionName];
|
||||
|
||||
if (isset($this->options['maxTimeMS'])) {
|
||||
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
|
||||
}
|
||||
|
||||
try {
|
||||
$cursor = $server->executeCommand($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);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
|
||||
|
||||
return new IndexInfoIteratorIterator(new CachingIterator($cursor));
|
||||
}
|
||||
}
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\BSON\JavascriptInterface;
|
||||
use MongoDB\Driver\Command;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the mapReduce command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::mapReduce()
|
||||
* @see https://docs.mongodb.com/manual/reference/command/mapReduce/
|
||||
*/
|
||||
class MapReduce implements Executable
|
||||
{
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
private static $wireVersionForReadConcern = 4;
|
||||
private static $wireVersionForWriteConcern = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $map;
|
||||
private $reduce;
|
||||
private $out;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a mapReduce command.
|
||||
*
|
||||
* Required arguments:
|
||||
*
|
||||
* * map (MongoDB\BSON\Javascript): A JavaScript function that associates
|
||||
* or "maps" a value with a key and emits the key and value pair.
|
||||
*
|
||||
* * reduce (MongoDB\BSON\Javascript): A JavaScript function that "reduces"
|
||||
* to a single object all the values associated with a particular key.
|
||||
*
|
||||
* * out (string|document): Specifies where to output the result of the
|
||||
* map-reduce operation. You can either output to a collection or return
|
||||
* the result inline. On a primary member of a replica set you can output
|
||||
* either to a collection or inline, but on a secondary, only inline
|
||||
* output is possible.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation. This only applies when results
|
||||
* are output to a collection.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * finalize (MongoDB\BSON\JavascriptInterface): Follows the reduce method
|
||||
* and modifies the output.
|
||||
*
|
||||
* * jsMode (boolean): Specifies whether to convert intermediate data into
|
||||
* BSON format between the execution of the map and reduce functions.
|
||||
*
|
||||
* * limit (integer): Specifies a maximum number of documents for the input
|
||||
* into the map function.
|
||||
*
|
||||
* * maxTimeMS (integer): The maximum amount of time to allow the query to
|
||||
* run.
|
||||
*
|
||||
* * query (document): Specifies the selection criteria using query
|
||||
* operators for determining the documents input to the map function.
|
||||
*
|
||||
* * readConcern (MongoDB\Driver\ReadConcern): Read concern. This is not
|
||||
* supported when results are returned inline.
|
||||
*
|
||||
* 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 results are output to a collection.
|
||||
*
|
||||
* * scope (document): Specifies global variables that are accessible in
|
||||
* the map, reduce and finalize functions.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * sort (document): Sorts the input documents. This option is useful for
|
||||
* optimization. For example, specify the sort key to be the same as the
|
||||
* emit key so that there are fewer reduce operations. The sort key must
|
||||
* be in an existing index for this collection.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be
|
||||
* applied to the returned Cursor (it is not sent to the server).
|
||||
*
|
||||
* * verbose (boolean): Specifies whether to include the timing information
|
||||
* in the result information.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern. This only
|
||||
* applies when results are output to a collection.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param JavascriptInterface $map Map function
|
||||
* @param JavascriptInterface $reduce Reduce function
|
||||
* @param string|array|object $out Output specification
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = [])
|
||||
{
|
||||
if ( ! is_string($out) && ! is_array($out) && ! is_object($out)) {
|
||||
throw InvalidArgumentException::invalidType('$out', $out, 'string or array or object');
|
||||
}
|
||||
|
||||
if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
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['finalize']) && ! $options['finalize'] instanceof JavascriptInterface) {
|
||||
throw InvalidArgumentException::invalidType('"finalize" option', $options['finalize'], 'MongoDB\Driver\Javascript');
|
||||
}
|
||||
|
||||
if (isset($options['jsMode']) && ! is_bool($options['jsMode'])) {
|
||||
throw InvalidArgumentException::invalidType('"jsMode" option', $options['jsMode'], 'boolean');
|
||||
}
|
||||
|
||||
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['query']) && ! is_array($options['query']) && ! is_object($options['query'])) {
|
||||
throw InvalidArgumentException::invalidType('"query" option', $options['query'], 'array or object');
|
||||
}
|
||||
|
||||
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['scope']) && ! is_array($options['scope']) && ! is_object($options['scope'])) {
|
||||
throw InvalidArgumentException::invalidType('"scope" option', $options['scope'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) {
|
||||
throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['verbose']) && ! is_bool($options['verbose'])) {
|
||||
throw InvalidArgumentException::invalidType('"verbose" option', $options['verbose'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['readConcern']) && $options['readConcern']->isDefault()) {
|
||||
unset($options['readConcern']);
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->map = $map;
|
||||
$this->reduce = $reduce;
|
||||
$this->out = $out;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return MapReduceResult
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
* @throws UnsupportedException if collation, read concern, or write concern is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$hasOutputCollection = ! \MongoDB\is_mapreduce_output_inline($this->out);
|
||||
|
||||
$command = $this->createCommand($server);
|
||||
$options = $this->createOptions($hasOutputCollection);
|
||||
|
||||
$cursor = $hasOutputCollection
|
||||
? $server->executeReadWriteCommand($this->databaseName, $command, $options)
|
||||
: $server->executeReadCommand($this->databaseName, $command, $options);
|
||||
|
||||
$result = current($cursor->toArray());
|
||||
|
||||
$getIterator = $this->createGetIteratorCallable($result, $server);
|
||||
|
||||
return new MapReduceResult($getIterator, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the mapReduce command.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return Command
|
||||
*/
|
||||
private function createCommand(Server $server)
|
||||
{
|
||||
$cmd = [
|
||||
'mapReduce' => $this->collectionName,
|
||||
'map' => $this->map,
|
||||
'reduce' => $this->reduce,
|
||||
'out' => $this->out,
|
||||
];
|
||||
|
||||
foreach (['finalize', 'jsMode', 'limit', 'maxTimeMS', 'verbose'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['collation', 'query', 'scope', 'sort'] as $option) {
|
||||
if (isset($this->options[$option])) {
|
||||
$cmd[$option] = (object) $this->options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
return new Command($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a callable for MapReduceResult::getIterator().
|
||||
*
|
||||
* @param stdClass $result
|
||||
* @param Server $server
|
||||
* @return callable
|
||||
* @throws UnexpectedValueException if the command response was malformed
|
||||
*/
|
||||
private function createGetIteratorCallable(stdClass $result, Server $server)
|
||||
{
|
||||
// Inline results can be wrapped with an ArrayIterator
|
||||
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 new ArrayIterator($results);
|
||||
};
|
||||
}
|
||||
|
||||
if (isset($result->result) && (is_string($result->result) || is_object($result->result))) {
|
||||
$options = isset($this->options['typeMap']) ? ['typeMap' => $this->options['typeMap']] : [];
|
||||
|
||||
$find = is_string($result->result)
|
||||
? new Find($this->databaseName, $result->result, [], $options)
|
||||
: new Find($result->result->db, $result->result->collection, [], $options);
|
||||
|
||||
return function() use ($find, $server) {
|
||||
return $find->execute($server);
|
||||
};
|
||||
}
|
||||
|
||||
throw new UnexpectedValueException('mapReduce command did not return inline results or an output collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php
|
||||
* @param boolean $hasOutputCollection
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions($hasOutputCollection)
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['readConcern'])) {
|
||||
$options['readConcern'] = $this->options['readConcern'];
|
||||
}
|
||||
|
||||
if ( ! $hasOutputCollection && isset($this->options['readPreference'])) {
|
||||
$options['readPreference'] = $this->options['readPreference'];
|
||||
}
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if ($hasOutputCollection && isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2018 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\Operation;
|
||||
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Session;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Operation for the collMod command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Database::modifyCollection()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/collMod/
|
||||
*/
|
||||
class ModifyCollection implements Executable
|
||||
{
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $collectionOptions;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a collMod command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will only be
|
||||
* used for the returned command result document.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* 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
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, array $collectionOptions, array $options = [])
|
||||
{
|
||||
if (empty($collectionOptions)) {
|
||||
throw new InvalidArgumentException('$collectionOptions is empty');
|
||||
}
|
||||
|
||||
if (isset($options['session']) && ! $options['session'] instanceof Session) {
|
||||
throw InvalidArgumentException::invalidType('"session" option', $options['session'], 'MongoDB\Driver\Session');
|
||||
}
|
||||
|
||||
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
|
||||
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
|
||||
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->collectionOptions = $collectionOptions;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return array|object Command result document
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) {
|
||||
throw UnsupportedException::writeConcernNotSupported();
|
||||
}
|
||||
|
||||
$cursor = $server->executeWriteCommand($this->databaseName, new Command(['collMod' => $this->collectionName] + $this->collectionOptions), $this->createOptions());
|
||||
|
||||
if (isset($this->options['typeMap'])) {
|
||||
$cursor->setTypeMap($this->options['typeMap']);
|
||||
}
|
||||
|
||||
return current($cursor->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the command.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php
|
||||
* @return array
|
||||
*/
|
||||
private function createOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for replacing a single document with the update command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::replaceOne()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/update/
|
||||
*/
|
||||
class ReplaceOne implements Executable
|
||||
{
|
||||
private $update;
|
||||
|
||||
/**
|
||||
* Constructs an update command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. The default is false.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array|object $replacement Replacement document
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = [])
|
||||
{
|
||||
if ( ! is_array($replacement) && ! is_object($replacement)) {
|
||||
throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object');
|
||||
}
|
||||
|
||||
if (\MongoDB\is_first_key_operator($replacement)) {
|
||||
throw new InvalidArgumentException('First key in $replacement argument is an update operator');
|
||||
}
|
||||
|
||||
$this->update = new Update(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
$filter,
|
||||
$replacement,
|
||||
['multi' => false] + $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return UpdateResult
|
||||
* @throws UnsupportedException if collation is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->update->execute($server);
|
||||
}
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\BulkWrite as Bulk;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for the update command.
|
||||
*
|
||||
* This class is used internally by the ReplaceOne, UpdateMany, and UpdateOne
|
||||
* operation classes.
|
||||
*
|
||||
* @internal
|
||||
* @see http://docs.mongodb.org/manual/reference/command/update/
|
||||
*/
|
||||
class Update implements Executable, Explainable
|
||||
{
|
||||
private static $wireVersionForArrayFilters = 6;
|
||||
private static $wireVersionForCollation = 5;
|
||||
private static $wireVersionForDocumentLevelValidation = 4;
|
||||
|
||||
private $databaseName;
|
||||
private $collectionName;
|
||||
private $filter;
|
||||
private $update;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs a update command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * arrayFilters (document array): A set of filters specifying to which
|
||||
* array elements an update should apply.
|
||||
*
|
||||
* This is not supported for server versions < 3.6 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * multi (boolean): When true, updates all documents matching the query.
|
||||
* This option cannot be true if the $update argument is a replacement
|
||||
* document (i.e. contains no update operators). The default is false.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. The default is false.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to delete documents
|
||||
* @param array|object $update Update to apply to the matched
|
||||
* document(s) or a replacement document
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
if ( ! is_array($filter) && ! is_object($filter)) {
|
||||
throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_array($update) && ! is_object($update)) {
|
||||
throw InvalidArgumentException::invalidType('$update', $filter, 'array or object');
|
||||
}
|
||||
|
||||
$options += [
|
||||
'multi' => false,
|
||||
'upsert' => false,
|
||||
];
|
||||
|
||||
if (isset($options['arrayFilters']) && ! is_array($options['arrayFilters'])) {
|
||||
throw InvalidArgumentException::invalidType('"arrayFilters" option', $options['arrayFilters'], 'array');
|
||||
}
|
||||
|
||||
if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
|
||||
throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
|
||||
}
|
||||
|
||||
if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) {
|
||||
throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object');
|
||||
}
|
||||
|
||||
if ( ! is_bool($options['multi'])) {
|
||||
throw InvalidArgumentException::invalidType('"multi" option', $options['multi'], 'boolean');
|
||||
}
|
||||
|
||||
if ($options['multi'] && ! \MongoDB\is_first_key_operator($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');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
|
||||
unset($options['writeConcern']);
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = (string) $collectionName;
|
||||
$this->filter = $filter;
|
||||
$this->update = $update;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return UpdateResult
|
||||
* @throws UnsupportedException if array filters or collation is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
if (isset($this->options['arrayFilters']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForArrayFilters)) {
|
||||
throw UnsupportedException::arrayFiltersNotSupported();
|
||||
}
|
||||
|
||||
if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) {
|
||||
throw UnsupportedException::collationNotSupported();
|
||||
}
|
||||
|
||||
$bulkOptions = [];
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
$bulk = new Bulk($bulkOptions);
|
||||
$bulk->update($this->filter, $this->update, $this->createUpdateOptions());
|
||||
|
||||
$writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions());
|
||||
|
||||
return new UpdateResult($writeResult);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
$cmd = ['update' => $this->collectionName, 'updates' => [['q' => $this->filter, 'u' => $this->update] + $this->createUpdateOptions()]];
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$cmd['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
|
||||
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for executing the bulk write.
|
||||
*
|
||||
* @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php
|
||||
* @return array
|
||||
*/
|
||||
private function createExecuteOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (isset($this->options['session'])) {
|
||||
$options['session'] = $this->options['session'];
|
||||
}
|
||||
|
||||
if (isset($this->options['writeConcern'])) {
|
||||
$options['writeConcern'] = $this->options['writeConcern'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create options for the update command.
|
||||
*
|
||||
* Note that these options are different from the bulk write options, which
|
||||
* are created in createExecuteOptions().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createUpdateOptions()
|
||||
{
|
||||
$updateOptions = [
|
||||
'multi' => $this->options['multi'],
|
||||
'upsert' => $this->options['upsert'],
|
||||
];
|
||||
|
||||
if (isset($this->options['arrayFilters'])) {
|
||||
$updateOptions['arrayFilters'] = $this->options['arrayFilters'];
|
||||
}
|
||||
|
||||
if (isset($this->options['collation'])) {
|
||||
$updateOptions['collation'] = (object) $this->options['collation'];
|
||||
}
|
||||
|
||||
return $updateOptions;
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for updating multiple documents with the update command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::updateMany()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/update/
|
||||
*/
|
||||
class UpdateMany implements Executable, Explainable
|
||||
{
|
||||
private $update;
|
||||
|
||||
/**
|
||||
* Constructs an update command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * arrayFilters (document array): A set of filters specifying to which
|
||||
* array elements an update should apply.
|
||||
*
|
||||
* This is not supported for server versions < 3.6 and will result in an$
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. The default is false.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array|object $update Update to apply to the matched documents
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
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');
|
||||
}
|
||||
|
||||
$this->update = new Update(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
$filter,
|
||||
$update,
|
||||
['multi' => true] + $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return UpdateResult
|
||||
* @throws UnsupportedException if collation is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->update->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->update->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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\Operation;
|
||||
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use MongoDB\Exception\UnsupportedException;
|
||||
|
||||
/**
|
||||
* Operation for updating a single document with the update command.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::updateOne()
|
||||
* @see http://docs.mongodb.org/manual/reference/command/update/
|
||||
*/
|
||||
class UpdateOne implements Executable, Explainable
|
||||
{
|
||||
private $update;
|
||||
|
||||
/**
|
||||
* Constructs an update command.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * arrayFilters (document array): A set of filters specifying to which
|
||||
* array elements an update should apply.
|
||||
*
|
||||
* This is not supported for server versions < 3.6 and will result in an$
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * bypassDocumentValidation (boolean): If true, allows the write to
|
||||
* circumvent document level validation.
|
||||
*
|
||||
* For servers < 3.2, this option is ignored as document level validation
|
||||
* is not available.
|
||||
*
|
||||
* * collation (document): Collation specification.
|
||||
*
|
||||
* This is not supported for server versions < 3.4 and will result in an
|
||||
* exception at execution time if used.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * upsert (boolean): When true, a new document is created if no document
|
||||
* matches the query. The default is false.
|
||||
*
|
||||
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param string $collectionName Collection name
|
||||
* @param array|object $filter Query by which to filter documents
|
||||
* @param array|object $update Update to apply to the matched document
|
||||
* @param array $options Command options
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
|
||||
{
|
||||
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');
|
||||
}
|
||||
|
||||
$this->update = new Update(
|
||||
$databaseName,
|
||||
$collectionName,
|
||||
$filter,
|
||||
$update,
|
||||
['multi' => false] + $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return UpdateResult
|
||||
* @throws UnsupportedException if collation is used and unsupported
|
||||
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return $this->update->execute($server);
|
||||
}
|
||||
|
||||
public function getCommandDocument(Server $server)
|
||||
{
|
||||
return $this->update->getCommandDocument($server);
|
||||
}
|
||||
}
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 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\Operation;
|
||||
|
||||
use MongoDB\ChangeStream;
|
||||
use MongoDB\BSON\TimestampInterface;
|
||||
use MongoDB\Driver\Command;
|
||||
use MongoDB\Driver\Cursor;
|
||||
use MongoDB\Driver\Manager;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Operation for creating a change stream with the aggregate command.
|
||||
*
|
||||
* Note: the implementation of CommandSubscriber is an internal implementation
|
||||
* detail and should not be considered part of the public API.
|
||||
*
|
||||
* @api
|
||||
* @see \MongoDB\Collection::watch()
|
||||
* @see https://docs.mongodb.com/manual/changeStreams/
|
||||
*/
|
||||
class Watch implements Executable, /* @internal */ CommandSubscriber
|
||||
{
|
||||
private static $wireVersionForOperationTime = 7;
|
||||
|
||||
const FULL_DOCUMENT_DEFAULT = 'default';
|
||||
const FULL_DOCUMENT_UPDATE_LOOKUP = 'updateLookup';
|
||||
|
||||
private $aggregate;
|
||||
private $aggregateOptions;
|
||||
private $changeStreamOptions;
|
||||
private $collectionName;
|
||||
private $databaseName;
|
||||
private $operationTime;
|
||||
private $pipeline;
|
||||
private $resumeCallable;
|
||||
|
||||
/**
|
||||
* Constructs an aggregate command for creating a change stream.
|
||||
*
|
||||
* Supported options:
|
||||
*
|
||||
* * batchSize (integer): The number of documents to return per batch.
|
||||
*
|
||||
* * collation (document): Specifies a collation.
|
||||
*
|
||||
* * fullDocument (string): Determines whether the "fullDocument" field
|
||||
* will be populated for update operations. By default, change streams
|
||||
* only return the delta of fields during the update operation (via the
|
||||
* "updateDescription" field). To additionally return the most current
|
||||
* majority-committed version of the updated document, specify
|
||||
* "updateLookup" for this option. Defaults to "default".
|
||||
*
|
||||
* Insert and replace operations always include the "fullDocument" field
|
||||
* and delete operations omit the field as the document no longer exists.
|
||||
*
|
||||
* * maxAwaitTimeMS (integer): The maximum amount of time for the server to
|
||||
* wait on new documents to satisfy a change stream query.
|
||||
*
|
||||
* * readConcern (MongoDB\Driver\ReadConcern): Read concern.
|
||||
*
|
||||
* * readPreference (MongoDB\Driver\ReadPreference): Read preference. This
|
||||
* will be used to select a new server when resuming. Defaults to a
|
||||
* "primary" read preference.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* * session (MongoDB\Driver\Session): Client session.
|
||||
*
|
||||
* Sessions are not supported for server versions < 3.6.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* This option is not supported for server versions < 4.0.
|
||||
*
|
||||
* * typeMap (array): Type map for BSON deserialization. This will be
|
||||
* applied to the returned Cursor (it is not sent to the server).
|
||||
*
|
||||
* Note: A database-level change stream may be created by specifying null
|
||||
* 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
|
||||
* @throws InvalidArgumentException for parameter/option parsing errors
|
||||
*/
|
||||
public function __construct(Manager $manager, $databaseName, $collectionName, array $pipeline, array $options = [])
|
||||
{
|
||||
if (isset($collectionName) && ! isset($databaseName)) {
|
||||
throw new InvalidArgumentException('$collectionName should also be null if $databaseName is null');
|
||||
}
|
||||
|
||||
$options += [
|
||||
'fullDocument' => self::FULL_DOCUMENT_DEFAULT,
|
||||
'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
|
||||
];
|
||||
|
||||
if (isset($options['fullDocument']) && ! is_string($options['fullDocument'])) {
|
||||
throw InvalidArgumentException::invalidType('"fullDocument" option', $options['fullDocument'], 'string');
|
||||
}
|
||||
|
||||
if (isset($options['resumeAfter']) && ! is_array($options['resumeAfter']) && ! is_object($options['resumeAfter'])) {
|
||||
throw InvalidArgumentException::invalidType('"resumeAfter" option', $options['resumeAfter'], 'array or object');
|
||||
}
|
||||
|
||||
if (isset($options['startAtOperationTime']) && ! $options['startAtOperationTime'] instanceof TimestampInterface) {
|
||||
throw InvalidArgumentException::invalidType('"startAtOperationTime" option', $options['startAtOperationTime'], TimestampInterface::class);
|
||||
}
|
||||
|
||||
/* In the absence of an explicit session, create one to ensure that the
|
||||
* initial aggregation and any resume attempts can use the same session
|
||||
* ("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'])) {
|
||||
try {
|
||||
$options['session'] = $manager->startSession(['causalConsistency' => false]);
|
||||
} catch (RuntimeException $e) {
|
||||
/* We can ignore the exception, as libmongoc likely cannot
|
||||
* create its own session and there is no risk of a mismatch. */
|
||||
}
|
||||
}
|
||||
|
||||
$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]);
|
||||
|
||||
// Null database name implies a cluster-wide change stream
|
||||
if ($databaseName === null) {
|
||||
$databaseName = 'admin';
|
||||
$this->changeStreamOptions['allChangesForCluster'] = true;
|
||||
}
|
||||
|
||||
$this->databaseName = (string) $databaseName;
|
||||
$this->collectionName = isset($collectionName) ? (string) $collectionName : null;
|
||||
$this->pipeline = $pipeline;
|
||||
|
||||
$this->aggregate = $this->createAggregate();
|
||||
$this->resumeCallable = $this->createResumeCallable($manager);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
final public function commandFailed(CommandFailedEvent $event)
|
||||
{
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
final public function commandStarted(CommandStartedEvent $event)
|
||||
{
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
final public function commandSucceeded(CommandSucceededEvent $event)
|
||||
{
|
||||
if ($event->getCommandName() !== 'aggregate') {
|
||||
return;
|
||||
}
|
||||
|
||||
$reply = $event->getReply();
|
||||
|
||||
if (isset($reply->operationTime) && $reply->operationTime instanceof TimestampInterface) {
|
||||
$this->operationTime = $reply->operationTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation.
|
||||
*
|
||||
* @see Executable::execute()
|
||||
* @param Server $server
|
||||
* @return ChangeStream
|
||||
* @throws UnsupportedException if collation or read concern is used and unsupported
|
||||
* @throws RuntimeException for other driver errors (e.g. connection errors)
|
||||
*/
|
||||
public function execute(Server $server)
|
||||
{
|
||||
return new ChangeStream($this->executeAggregate($server), $this->resumeCallable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the aggregate command for creating a change stream.
|
||||
*
|
||||
* This method is also used to recreate the aggregate command when resuming.
|
||||
*
|
||||
* @return Aggregate
|
||||
*/
|
||||
private function createAggregate()
|
||||
{
|
||||
$pipeline = $this->pipeline;
|
||||
array_unshift($pipeline, ['$changeStream' => (object) $this->changeStreamOptions]);
|
||||
|
||||
return new Aggregate($this->databaseName, $this->collectionName, $pipeline, $this->aggregateOptions);
|
||||
}
|
||||
|
||||
private function createResumeCallable(Manager $manager)
|
||||
{
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the aggregate command and optionally capture its operation time.
|
||||
*
|
||||
* @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);
|
||||
|
||||
try {
|
||||
return $this->aggregate->execute($server);
|
||||
} finally {
|
||||
\MongoDB\Driver\Monitoring\removeSubscriber($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
use MongoDB\Driver\WriteResult;
|
||||
use MongoDB\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Result class for an update operation.
|
||||
*/
|
||||
class UpdateResult
|
||||
{
|
||||
private $writeResult;
|
||||
private $isAcknowledged;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WriteResult $writeResult
|
||||
*/
|
||||
public function __construct(WriteResult $writeResult)
|
||||
{
|
||||
$this->writeResult = $writeResult;
|
||||
$this->isAcknowledged = $writeResult->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were matched by the filter.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see UpdateResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getMatchedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getMatchedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were modified.
|
||||
*
|
||||
* This value is undefined (i.e. null) if the write executed as a legacy
|
||||
* operation instead of command.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see UpdateResult::isAcknowledged()
|
||||
* @return integer|null
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getModifiedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getModifiedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of documents that were upserted.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see UpdateResult::isAcknowledged()
|
||||
* @return integer
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getUpsertedCount()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
return $this->writeResult->getUpsertedCount();
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID of the document inserted by an upsert operation.
|
||||
*
|
||||
* If the document had an ID prior to upserting (i.e. the server did not
|
||||
* need to generate an ID), this will contain its "_id". Any
|
||||
* server-generated ID will be a MongoDB\BSON\ObjectId instance.
|
||||
*
|
||||
* This value is undefined (i.e. null) if an upsert did not take place.
|
||||
*
|
||||
* This method should only be called if the write was acknowledged.
|
||||
*
|
||||
* @see UpdateResult::isAcknowledged()
|
||||
* @return mixed|null
|
||||
* @throws BadMethodCallException is the write result is unacknowledged
|
||||
*/
|
||||
public function getUpsertedId()
|
||||
{
|
||||
if ($this->isAcknowledged) {
|
||||
foreach ($this->writeResult->getUpsertedIds() as $id) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this update was acknowledged by the server.
|
||||
*
|
||||
* If the update was not acknowledged, other fields from the WriteResult
|
||||
* (e.g. matchedCount) will be undefined and their getter methods should not
|
||||
* be invoked.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAcknowledged()
|
||||
{
|
||||
return $this->isAcknowledged;
|
||||
}
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright 2015-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;
|
||||
|
||||
use MongoDB\BSON\Serializable;
|
||||
use MongoDB\Driver\ReadConcern;
|
||||
use MongoDB\Driver\Server;
|
||||
use MongoDB\Driver\WriteConcern;
|
||||
use MongoDB\Exception\InvalidArgumentException;
|
||||
use stdClass;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Applies a type map to a document.
|
||||
*
|
||||
* This function is used by operations where it is not possible to apply a type
|
||||
* map to the cursor directly because the root document is a command response
|
||||
* (e.g. findAndModify).
|
||||
*
|
||||
* @internal
|
||||
* @param array|object $document Document to which the type map will be applied
|
||||
* @param array $typeMap Type map for BSON deserialization.
|
||||
* @return array|object
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function apply_type_map_to_document($document, array $typeMap)
|
||||
{
|
||||
if ( ! is_array($document) && ! is_object($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
return \MongoDB\BSON\toPHP(\MongoDB\BSON\fromPHP($document), $typeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an index name from a key specification.
|
||||
*
|
||||
* @internal
|
||||
* @param array|object $document Document containing fields mapped to values,
|
||||
* which denote order or an index type
|
||||
* @return string
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function generate_index_name($document)
|
||||
{
|
||||
if ($document instanceof Serializable) {
|
||||
$document = $document->bsonSerialize();
|
||||
}
|
||||
|
||||
if (is_object($document)) {
|
||||
$document = get_object_vars($document);
|
||||
}
|
||||
|
||||
if ( ! is_array($document)) {
|
||||
throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
|
||||
}
|
||||
|
||||
$name = '';
|
||||
|
||||
foreach ($document as $field => $type) {
|
||||
$name .= ($name != '' ? '_' : '') . $field . '_' . $type;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the first key in the document starts with a "$" character.
|
||||
*
|
||||
* This is used for differentiating update and replacement documents.
|
||||
*
|
||||
* @internal
|
||||
* @param array|object $document Update or replacement document
|
||||
* @return boolean
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function is_first_key_operator($document)
|
||||
{
|
||||
if ($document instanceof Serializable) {
|
||||
$document = $document->bsonSerialize();
|
||||
}
|
||||
|
||||
if (is_object($document)) {
|
||||
$document = get_object_vars($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 whether the aggregation pipeline ends with an $out operator.
|
||||
*
|
||||
* This is used for determining whether the aggregation pipeline must be
|
||||
* executed against a primary server.
|
||||
*
|
||||
* @internal
|
||||
* @param array $pipeline List of pipeline operations
|
||||
* @return boolean
|
||||
*/
|
||||
function is_last_pipeline_operator_out(array $pipeline)
|
||||
{
|
||||
$lastOp = end($pipeline);
|
||||
|
||||
if ($lastOp === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lastOp = (array) $lastOp;
|
||||
|
||||
return key($lastOp) === '$out';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the "out" option for a mapReduce operation is "inline".
|
||||
*
|
||||
* This is used to determine if a mapReduce command requires a primary.
|
||||
*
|
||||
* @internal
|
||||
* @see https://docs.mongodb.com/manual/reference/command/mapReduce/#output-inline
|
||||
* @param string|array|object $out Output specification
|
||||
* @return boolean
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function is_mapreduce_output_inline($out)
|
||||
{
|
||||
if ( ! is_array($out) && ! is_object($out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($out instanceof Serializable) {
|
||||
$out = $out->bsonSerialize();
|
||||
}
|
||||
|
||||
if (is_object($out)) {
|
||||
$out = get_object_vars($out);
|
||||
}
|
||||
|
||||
if ( ! is_array($out)) {
|
||||
throw InvalidArgumentException::invalidType('$out', $out, 'array or object');
|
||||
}
|
||||
|
||||
reset($out);
|
||||
|
||||
return key($out) === 'inline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the server supports a particular feature.
|
||||
*
|
||||
* @internal
|
||||
* @param Server $server Server to check
|
||||
* @param integer $feature Feature constant (i.e. wire protocol version)
|
||||
* @return boolean
|
||||
*/
|
||||
function server_supports_feature(Server $server, $feature)
|
||||
{
|
||||
$info = $server->getInfo();
|
||||
$maxWireVersion = isset($info['maxWireVersion']) ? (integer) $info['maxWireVersion'] : 0;
|
||||
$minWireVersion = isset($info['minWireVersion']) ? (integer) $info['minWireVersion'] : 0;
|
||||
|
||||
return ($minWireVersion <= $feature && $maxWireVersion >= $feature);
|
||||
}
|
||||
|
||||
function is_string_array($input) {
|
||||
if (!is_array($input)){
|
||||
return false;
|
||||
}
|
||||
foreach($input as $item) {
|
||||
if (!is_string($item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep copy of a value.
|
||||
*
|
||||
* This function will clone objects and recursively copy values within arrays.
|
||||
*
|
||||
* @internal
|
||||
* @see https://bugs.php.net/bug.php?id=49664
|
||||
* @param mixed $element Value to be copied
|
||||
* @return mixed
|
||||
*/
|
||||
function recursive_copy($element) {
|
||||
if (is_array($element)) {
|
||||
foreach ($element as $key => $value) {
|
||||
$element[$key] = recursive_copy($value);
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
if ( ! is_object($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
if ( ! (new ReflectionClass($element))->isCloneable()) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
return clone $element;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
MongoDB PHP
|
||||
-----------
|
||||
|
||||
Downloaded from https://github.com/mongodb/mongo-php-library
|
||||
|
||||
Last commit on download: aac8e54009196f6544e50baf9b63dcf0eab3bbdf
|
||||
|
||||
This version (1.4) requires PHP mongodb extension >= 1.5
|
||||
|
||||
Import procedure:
|
||||
|
||||
- Copy all the files and folders from the folder mongodb/src in this directory.
|
||||
- Copy the license file from the project root.
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class cachestore_mongodb_addinstance_form extends cachestore_addinstance_form {
|
||||
global $OUTPUT;
|
||||
$form = $this->_form;
|
||||
|
||||
if (!class_exists('MongoClient')) {
|
||||
if (!version_compare(phpversion('mongodb'), '1.5', 'ge')) {
|
||||
$form->addElement('html', $OUTPUT->notification(get_string('pleaseupgrademongo', 'cachestore_mongodb')));
|
||||
}
|
||||
|
||||
|
||||
Vendored
+55
-81
@@ -26,13 +26,15 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once('MongoDB/functions.php');
|
||||
|
||||
/**
|
||||
* The MongoDB Cache store.
|
||||
*
|
||||
* This cache store uses the MongoDB Native Driver.
|
||||
* This cache store uses the MongoDB Native Driver and the MongoDB PHP Library.
|
||||
* For installation instructions have a look at the following two links:
|
||||
* - {@link http://www.php.net/manual/en/mongo.installation.php}
|
||||
* - {@link http://www.mongodb.org/display/DOCS/PHP+Language+Center}
|
||||
* - {@link http://php.net/manual/en/set.mongodb.php}
|
||||
* - {@link https://docs.mongodb.com/ecosystem/drivers/php/}
|
||||
*
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -65,19 +67,19 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
|
||||
/**
|
||||
* The Connection object
|
||||
* @var Mongo
|
||||
* @var MongoDB/Client
|
||||
*/
|
||||
protected $connection = false;
|
||||
|
||||
/**
|
||||
* The Database Object
|
||||
* @var MongoDB
|
||||
* @var MongoDB/Database
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* The Collection object
|
||||
* @var MongoCollection
|
||||
* @var MongoDB/Collection
|
||||
*/
|
||||
protected $collection;
|
||||
|
||||
@@ -105,14 +107,6 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
*/
|
||||
protected $isready = false;
|
||||
|
||||
/**
|
||||
* Set to true if the Mongo extension is < version 1.3.
|
||||
* If this is the case we must use the legacy Mongo class instead of MongoClient.
|
||||
* Mongo is backwards compatible, although obviously deprecated.
|
||||
* @var bool
|
||||
*/
|
||||
protected $legacymongo = false;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the Mongo store.
|
||||
*
|
||||
@@ -148,16 +142,14 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
$this->extendedmode = $configuration['extendedmode'];
|
||||
}
|
||||
|
||||
// Test if the MongoClient class exists, if not we need to switch to legacy classes.
|
||||
$this->legacymongo = (!class_exists('MongoClient'));
|
||||
|
||||
// MongoClient from Mongo 1.3 onwards. Mongo for earlier versions.
|
||||
$class = ($this->legacymongo) ? 'Mongo' : 'MongoClient';
|
||||
try {
|
||||
$this->connection = new $class($this->server, $this->options);
|
||||
$this->connection = new MongoDB\Client($this->server, $this->options);
|
||||
// Required because MongoDB\Client does not try to connect to the server
|
||||
$rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY);
|
||||
$this->connection->getManager()->selectServer($rp);
|
||||
$this->isready = true;
|
||||
} catch (MongoConnectionException $e) {
|
||||
// We only want to catch MongoConnectionExceptions here.
|
||||
} catch (MongoDB\Driver\Exception\RuntimeException $e) {
|
||||
// We only want to catch RuntimeException here.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +158,7 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
* @return bool
|
||||
*/
|
||||
public static function are_requirements_met() {
|
||||
return class_exists('MongoClient') || class_exists('Mongo');
|
||||
return version_compare(phpversion('mongodb'), '1.5', 'ge');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,17 +195,18 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
if ($this->is_initialised()) {
|
||||
throw new coding_exception('This mongodb instance has already been initialised.');
|
||||
}
|
||||
$this->database = $this->connection->selectDB($this->databasename);
|
||||
$this->database = $this->connection->selectDatabase($this->databasename);
|
||||
$this->definitionhash = 'm'.$definition->generate_definition_hash();
|
||||
$this->collection = $this->database->selectCollection($this->definitionhash);
|
||||
|
||||
$options = array('name' => 'idx_key');
|
||||
if ($this->legacymongo) {
|
||||
$options['safe'] = $this->usesafe;
|
||||
} else {
|
||||
$options['w'] = $this->usesafe ? 1 : 0;
|
||||
}
|
||||
$this->collection->ensureIndex(array('key' => 1), $options);
|
||||
|
||||
$w = $this->usesafe ? 1 : 0;
|
||||
$wc = new MongoDB\Driver\WriteConcern($w);
|
||||
|
||||
$options['writeConcern'] = $wc;
|
||||
|
||||
$this->collection->createIndex(array('key' => 1), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +214,7 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
* @return bool
|
||||
*/
|
||||
public function is_initialised() {
|
||||
return ($this->database instanceof MongoDB);
|
||||
return ($this->database instanceof MongoDB\Database);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,24 +312,20 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
}
|
||||
$record['data'] = serialize($data);
|
||||
$options = array('upsert' => true);
|
||||
if ($this->legacymongo) {
|
||||
$options['safe'] = $this->usesafe;
|
||||
} else {
|
||||
$options['w'] = $this->usesafe ? 1 : 0;
|
||||
}
|
||||
|
||||
$w = $this->usesafe ? 1 : 0;
|
||||
$wc = new MongoDB\Driver\WriteConcern($w);
|
||||
|
||||
$options['writeConcern'] = $wc;
|
||||
|
||||
$this->delete($key);
|
||||
$result = $this->collection->insert($record, $options);
|
||||
if ($result === true) {
|
||||
// Safe mode is off.
|
||||
return true;
|
||||
} else if (is_array($result)) {
|
||||
if (empty($result['ok']) || isset($result['err'])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
try {
|
||||
$this->collection->insertOne($record, $options);
|
||||
} catch (MongoDB\Exception\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
// Who knows?
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,27 +362,23 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
$criteria = $key;
|
||||
}
|
||||
$options = array('justOne' => false);
|
||||
if ($this->legacymongo) {
|
||||
$options['safe'] = $this->usesafe;
|
||||
} else {
|
||||
$options['w'] = $this->usesafe ? 1 : 0;
|
||||
}
|
||||
$result = $this->collection->remove($criteria, $options);
|
||||
|
||||
if ($result === true) {
|
||||
// Safe mode.
|
||||
return true;
|
||||
} else if (is_array($result)) {
|
||||
if (empty($result['ok']) || isset($result['err'])) {
|
||||
return false;
|
||||
} else if (empty($result['n'])) {
|
||||
// Nothing was removed.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
$w = $this->usesafe ? 1 : 0;
|
||||
$wc = new MongoDB\Driver\WriteConcern($w);
|
||||
|
||||
$options['writeConcern'] = $wc;
|
||||
|
||||
try {
|
||||
$result = $this->collection->deleteOne($criteria, $options);
|
||||
} catch (\MongoDB\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
// Who knows?
|
||||
return false;
|
||||
|
||||
if (empty($result->getDeletedCount())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,20 +483,10 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
public function instance_deleted() {
|
||||
// We can't use purge here that acts upon a collection.
|
||||
// Instead we must drop the named database.
|
||||
if ($this->connection) {
|
||||
$connection = $this->connection;
|
||||
} else {
|
||||
try {
|
||||
// MongoClient from Mongo 1.3 onwards. Mongo for earlier versions.
|
||||
$class = ($this->legacymongo) ? 'Mongo' : 'MongoClient';
|
||||
$connection = new $class($this->server, $this->options);
|
||||
} catch (MongoConnectionException $e) {
|
||||
// We only want to catch MongoConnectionExceptions here.
|
||||
// If the server cannot be connected to we cannot clean it.
|
||||
return;
|
||||
}
|
||||
if (!$this->is_ready()) {
|
||||
return;
|
||||
}
|
||||
$database = $connection->selectDB($this->databasename);
|
||||
$database = $this->connection->selectDatabase($this->databasename);
|
||||
$database->drop();
|
||||
$connection = null;
|
||||
$database = null;
|
||||
@@ -564,7 +539,6 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
return $store;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates an instance of the cache store that can be used for testing.
|
||||
*
|
||||
@@ -577,7 +551,7 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
|
||||
|
||||
// If the configuration is not defined correctly, return only the configuration know about.
|
||||
if (defined('TEST_CACHESTORE_MONGODB_TESTSERVER')) {
|
||||
$configuration['servers'] = explode("\n", TEST_CACHESTORE_MONGODB_TESTSERVER);
|
||||
$configuration['server'] = TEST_CACHESTORE_MONGODB_TESTSERVER;
|
||||
}
|
||||
|
||||
return $configuration;
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<libraries>
|
||||
<library>
|
||||
<location>MongoDB</location>
|
||||
<name>MongoDB PHP Library</name>
|
||||
<license>Apache</license>
|
||||
<version>1.4</version>
|
||||
<licenseversion>2.0</licenseversion>
|
||||
</library>
|
||||
</libraries>
|
||||
Vendored
+5
@@ -1,6 +1,11 @@
|
||||
This files describes API changes in /cache/stores/* - cache store plugins.
|
||||
Information provided here is intended especially for developers.
|
||||
|
||||
=== 3.7 ===
|
||||
* Upgraded MongoDB cache store to use the new lower level PHP-driver and MongoDB PHP Library.
|
||||
* The mongodb extension has replaced the old mongo extension. The mongodb pecl extension >= 1.5 must be installed to use MongoDB
|
||||
cache store.
|
||||
|
||||
=== 3.6 ===
|
||||
* The `cache::now()` function now takes an optional boolean parameter to indicate that the cache should return a more
|
||||
accurate time, generated by the PHP `microtime` function.
|
||||
|
||||
@@ -86,6 +86,7 @@ class core_component {
|
||||
'Phpml' => 'lib/mlbackend/php/phpml/src/Phpml',
|
||||
'PHPMailer\\PHPMailer' => 'lib/phpmailer/src',
|
||||
'RedeyeVentures\\GeoPattern' => 'lib/geopattern-php/GeoPattern',
|
||||
'MongoDB' => 'cache/stores/mongodb/MongoDB',
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user