| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- <?php
- /*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- if (class_exists('MongoCursor', false)) {
- return;
- }
- use Alcaeus\MongoDbAdapter\AbstractCursor;
- use Alcaeus\MongoDbAdapter\TypeConverter;
- use Alcaeus\MongoDbAdapter\ExceptionConverter;
- use MongoDB\Driver\Cursor;
- use MongoDB\Driver\ReadPreference;
- use MongoDB\Operation\Find;
- /**
- * Result object for database query.
- * @link http://www.php.net/manual/en/class.mongocursor.php
- */
- class MongoCursor extends AbstractCursor implements Iterator
- {
- /**
- * @var bool
- */
- public static $slaveOkay = false;
- /**
- * @var int
- */
- public static $timeout = 30000;
- /**
- * @var array
- */
- protected $optionNames = [
- 'allowPartialResults',
- 'batchSize',
- 'cursorType',
- 'limit',
- 'maxTimeMS',
- 'modifiers',
- 'noCursorTimeout',
- 'projection',
- 'readPreference',
- 'skip',
- 'sort',
- ];
- /**
- * @var array
- */
- protected $projection;
- /**
- * @var array
- */
- protected $query;
- protected $allowPartialResults;
- protected $awaitData;
- protected $flags = 0;
- protected $hint;
- protected $limit;
- protected $maxTimeMS;
- protected $noCursorTimeout;
- protected $options = [];
- protected $skip;
- protected $snapshot;
- protected $sort;
- protected $tailable;
- /**
- * Create a new cursor
- * @link http://www.php.net/manual/en/mongocursor.construct.php
- * @param MongoClient $connection Database connection.
- * @param string $ns Full name of database and collection.
- * @param array $query Database query.
- * @param array $fields Fields to return.
- */
- public function __construct(MongoClient $connection, $ns, array $query = array(), array $fields = array())
- {
- parent::__construct($connection, $ns);
- $this->query = $query;
- $this->projection = $fields;
- }
- /**
- * Adds a top-level key/value pair to a query
- * @link http://www.php.net/manual/en/mongocursor.addoption.php
- * @param string $key Fieldname to add.
- * @param mixed $value Value to add.
- * @throws MongoCursorException
- * @return MongoCursor Returns this cursor
- */
- public function addOption($key, $value)
- {
- $this->errorIfOpened();
- $this->options[$key] = $value;
- return $this;
- }
- /**
- * (PECL mongo >= 1.2.11)<br/>
- * Sets whether this cursor will wait for a while for a tailable cursor to return more data
- * @param bool $wait [optional] <p>If the cursor should wait for more data to become available.</p>
- * @return MongoCursor Returns this cursor.
- */
- public function awaitData($wait = true)
- {
- $this->errorIfOpened();
- $this->awaitData = $wait;
- return $this;
- }
- /**
- * Counts the number of results for this query
- * @link http://www.php.net/manual/en/mongocursor.count.php
- * @param bool $foundOnly Send cursor limit and skip information to the count function, if applicable.
- * @return int The number of documents returned by this cursor's query.
- */
- public function count($foundOnly = false)
- {
- $optionNames = ['hint', 'maxTimeMS'];
- if ($foundOnly) {
- $optionNames = array_merge($optionNames, ['limit', 'skip']);
- }
- $options = $this->getOptions($optionNames) + $this->options;
- try {
- $count = $this->collection->count(TypeConverter::fromLegacy($this->query), $options);
- } catch (\MongoDB\Driver\Exception\ExecutionTimeoutException $e) {
- throw new MongoCursorTimeoutException($e->getMessage(), $e->getCode(), $e);
- } catch (\MongoDB\Driver\Exception\Exception $e) {
- throw ExceptionConverter::toLegacy($e);
- }
- return $count;
- }
- /**
- * Execute the query
- * @link http://www.php.net/manual/en/mongocursor.doquery.php
- * @throws MongoConnectionException if it cannot reach the database.
- * @return void
- */
- protected function doQuery()
- {
- $options = $this->getOptions() + $this->options;
- try {
- $this->cursor = $this->collection->find(TypeConverter::fromLegacy($this->query), $options);
- } catch (\MongoDB\Driver\Exception\ExecutionTimeoutException $e) {
- throw new MongoCursorTimeoutException($e->getMessage(), $e->getCode(), $e);
- } catch (\MongoDB\Driver\Exception\Exception $e) {
- throw ExceptionConverter::toLegacy($e);
- }
- }
- /**
- * Return an explanation of the query, often useful for optimization and debugging
- * @link http://www.php.net/manual/en/mongocursor.explain.php
- * @return array Returns an explanation of the query.
- */
- public function explain()
- {
- $this->notImplemented();
- }
- /**
- * Sets the fields for a query
- * @link http://www.php.net/manual/en/mongocursor.fields.php
- * @param array $f Fields to return (or not return).
- * @throws MongoCursorException
- * @return MongoCursor
- */
- public function fields(array $f)
- {
- $this->errorIfOpened();
- $this->projection = $f;
- return $this;
- }
- /**
- * Advances the cursor to the next result, and returns that result
- * @link http://www.php.net/manual/en/mongocursor.getnext.php
- * @throws MongoConnectionException
- * @throws MongoCursorTimeoutException
- * @return array Returns the next object
- */
- public function getNext()
- {
- return $this->next();
- }
- /**
- * Checks if there are any more elements in this cursor
- * @link http://www.php.net/manual/en/mongocursor.hasnext.php
- * @throws MongoConnectionException
- * @throws MongoCursorTimeoutException
- * @return bool Returns true if there is another element
- */
- public function hasNext()
- {
- if (! $this->startedIterating) {
- $this->ensureIterator();
- $this->startedIterating = true;
- $this->storeIteratorState();
- $this->cursorNeedsAdvancing = false;
- } elseif ($this->cursorNeedsAdvancing) {
- $this->ensureIterator()->next();
- $this->cursorNeedsAdvancing = false;
- }
- return $this->ensureIterator()->valid();
- }
- /**
- * Gives the database a hint about the query
- * @link http://www.php.net/manual/en/mongocursor.hint.php
- * @param array|string $keyPattern Indexes to use for the query.
- * @throws MongoCursorException
- * @return MongoCursor Returns this cursor
- */
- public function hint($keyPattern)
- {
- $this->errorIfOpened();
- $this->hint = $keyPattern;
- return $this;
- }
- /**
- * Sets whether this cursor will timeout
- * @link http://www.php.net/manual/en/mongocursor.immortal.php
- * @param bool $liveForever If the cursor should be immortal.
- * @throws MongoCursorException
- * @return MongoCursor Returns this cursor
- */
- public function immortal($liveForever = true)
- {
- $this->errorIfOpened();
- $this->noCursorTimeout = $liveForever;
- return $this;
- }
- /**
- * Limits the number of results returned
- * @link http://www.php.net/manual/en/mongocursor.limit.php
- * @param int $num The number of results to return.
- * @throws MongoCursorException
- * @return MongoCursor Returns this cursor
- */
- public function limit($num)
- {
- $this->errorIfOpened();
- $this->limit = $num;
- return $this;
- }
- /**
- * @param int $ms
- * @return $this
- * @throws MongoCursorException
- */
- public function maxTimeMS($ms)
- {
- $this->errorIfOpened();
- $this->maxTimeMS = $ms;
- return $this;
- }
- /**
- * @link http://www.php.net/manual/en/mongocursor.partial.php
- * @param bool $okay [optional] <p>If receiving partial results is okay.</p>
- * @return MongoCursor Returns this cursor.
- */
- public function partial($okay = true)
- {
- $this->allowPartialResults = $okay;
- return $this;
- }
- /**
- * Clears the cursor
- * @link http://www.php.net/manual/en/mongocursor.reset.php
- * @return void
- */
- public function reset()
- {
- parent::reset();
- }
- /**
- * @link http://www.php.net/manual/en/mongocursor.setflag.php
- * @param int $flag
- * @param bool $set
- * @return MongoCursor
- */
- public function setFlag($flag, $set = true)
- {
- $this->notImplemented();
- }
- /**
- * Skips a number of results
- * @link http://www.php.net/manual/en/mongocursor.skip.php
- * @param int $num The number of results to skip.
- * @throws MongoCursorException
- * @return MongoCursor Returns this cursor
- */
- public function skip($num)
- {
- $this->errorIfOpened();
- $this->skip = $num;
- return $this;
- }
- /**
- * Sets whether this query can be done on a slave
- * This method will override the static class variable slaveOkay.
- * @link http://www.php.net/manual/en/mongocursor.slaveOkay.php
- * @param boolean $okay If it is okay to query the slave.
- * @throws MongoCursorException
- * @return MongoCursor Returns this cursor
- */
- public function slaveOkay($okay = true)
- {
- $this->errorIfOpened();
- $this->setReadPreferenceFromSlaveOkay($okay);
- return $this;
- }
- /**
- * Use snapshot mode for the query
- * @link http://www.php.net/manual/en/mongocursor.snapshot.php
- * @throws MongoCursorException
- * @return MongoCursor Returns this cursor
- */
- public function snapshot()
- {
- $this->errorIfOpened();
- $this->snapshot = true;
- return $this;
- }
- /**
- * Sorts the results by given fields
- * @link http://www.php.net/manual/en/mongocursor.sort.php
- * @param array $fields An array of fields by which to sort. Each element in the array has as key the field name, and as value either 1 for ascending sort, or -1 for descending sort
- * @throws MongoCursorException
- * @return MongoCursor Returns the same cursor that this method was called on
- */
- public function sort(array $fields)
- {
- $this->errorIfOpened();
- $this->sort = $fields;
- return $this;
- }
- /**
- * Sets whether this cursor will be left open after fetching the last results
- * @link http://www.php.net/manual/en/mongocursor.tailable.php
- * @param bool $tail If the cursor should be tailable.
- * @return MongoCursor Returns this cursor
- */
- public function tailable($tail = true)
- {
- $this->errorIfOpened();
- $this->tailable = $tail;
- return $this;
- }
- /**
- * @return int|null
- */
- protected function convertCursorType()
- {
- if (! $this->tailable) {
- return null;
- }
- return $this->awaitData ? Find::TAILABLE_AWAIT : Find::TAILABLE;
- }
- /**
- * @return array
- */
- protected function convertModifiers()
- {
- $modifiers = array_key_exists('modifiers', $this->options) ? $this->options['modifiers'] : [];
- foreach (['hint', 'snapshot'] as $modifier) {
- if ($this->$modifier === null) {
- continue;
- }
- $modifiers['$' . $modifier] = $this->$modifier;
- }
- return $modifiers;
- }
- /**
- * @return array
- */
- protected function convertProjection()
- {
- return TypeConverter::convertProjection($this->projection);
- }
- /**
- * @return Cursor
- */
- protected function ensureCursor()
- {
- if ($this->cursor === null) {
- $this->doQuery();
- }
- return $this->cursor;
- }
- /**
- * @param \Traversable $traversable
- * @return \Generator
- */
- protected function wrapTraversable(\Traversable $traversable)
- {
- foreach ($traversable as $key => $value) {
- if (isset($value->_id) && ($value->_id instanceof \MongoDB\BSON\ObjectID || !is_object($value->_id))) {
- $key = (string) $value->_id;
- }
- yield $key => $value;
- }
- }
- /**
- * @return array
- */
- protected function getCursorInfo()
- {
- return [
- 'ns' => $this->ns,
- 'limit' => $this->limit,
- 'batchSize' => (int) $this->batchSize,
- 'skip' => $this->skip,
- 'flags' => $this->flags,
- 'query' => $this->query,
- 'fields' => $this->projection,
- ];
- }
- /**
- * @return array
- */
- public function __sleep()
- {
- return [
- 'allowPartialResults',
- 'awaitData',
- 'flags',
- 'hint',
- 'limit',
- 'maxTimeMS',
- 'noCursorTimeout',
- 'optionNames',
- 'options',
- 'projection',
- 'query',
- 'skip',
- 'snapshot',
- 'sort',
- 'tailable',
- ] + parent::__sleep();
- }
- }
|