Completed
Pull Request — master (#63)
by Andreas
21:41
created

MongoCursor::__sleep()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 18

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 20
rs 9.4285
cc 1
eloc 18
nc 1
nop 0
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 */
15
16
use Alcaeus\MongoDbAdapter\AbstractCursor;
17
use Alcaeus\MongoDbAdapter\TypeConverter;
18
use Alcaeus\MongoDbAdapter\ExceptionConverter;
19
use MongoDB\Driver\Cursor;
20
use MongoDB\Driver\ReadPreference;
21
use MongoDB\Operation\Find;
22
23
/**
24
 * Result object for database query.
25
 * @link http://www.php.net/manual/en/class.mongocursor.php
26
 */
27
class MongoCursor extends AbstractCursor implements Iterator
28
{
29
    /**
30
     * @var bool
31
     */
32
    public static $slaveOkay = false;
33
34
    /**
35
     * @var int
36
     */
37
    public static $timeout = 30000;
38
39
    /**
40
     * @var array
41
     */
42
    protected $optionNames = [
43
        'allowPartialResults',
44
        'batchSize',
45
        'cursorType',
46
        'limit',
47
        'maxTimeMS',
48
        'modifiers',
49
        'noCursorTimeout',
50
        'projection',
51
        'readPreference',
52
        'skip',
53
        'sort',
54
    ];
55
56
    /**
57
     * @var array
58
     */
59
    protected $projection;
60
61
    /**
62
     * @var array
63
     */
64
    protected $query;
65
66
    protected $allowPartialResults;
67
    protected $awaitData;
68
    protected $flags = 0;
69
    protected $hint;
70
    protected $limit;
71
    protected $maxTimeMS;
72
    protected $noCursorTimeout;
73
    protected $options = [];
74
    protected $skip;
75
    protected $snapshot;
76
    protected $sort;
77
    protected $tailable;
78
79
    /**
80
     * Create a new cursor
81
     * @link http://www.php.net/manual/en/mongocursor.construct.php
82
     * @param MongoClient $connection Database connection.
83
     * @param string $ns Full name of database and collection.
84
     * @param array $query Database query.
85
     * @param array $fields Fields to return.
86
     */
87
    public function __construct(MongoClient $connection, $ns, array $query = array(), array $fields = array())
88
    {
89
        parent::__construct($connection, $ns);
90
91
        $this->query = $query;
92
        $this->projection = $fields;
93
    }
94
95
    /**
96
     * Adds a top-level key/value pair to a query
97
     * @link http://www.php.net/manual/en/mongocursor.addoption.php
98
     * @param string $key Fieldname to add.
99
     * @param mixed $value Value to add.
100
     * @throws MongoCursorException
101
     * @return MongoCursor Returns this cursor
102
     */
103
    public function addOption($key, $value)
104
    {
105
        $this->errorIfOpened();
106
        $this->options[$key] = $value;
107
108
        return $this;
109
    }
110
111
    /**
112
     * (PECL mongo &gt;= 1.2.11)<br/>
113
     * Sets whether this cursor will wait for a while for a tailable cursor to return more data
114
     * @param bool $wait [optional] <p>If the cursor should wait for more data to become available.</p>
115
     * @return MongoCursor Returns this cursor.
116
     */
117
    public function awaitData($wait = true)
118
    {
119
        $this->errorIfOpened();
120
        $this->awaitData = $wait;
121
122
        return $this;
123
    }
124
125
126
    /**
127
     * Counts the number of results for this query
128
     * @link http://www.php.net/manual/en/mongocursor.count.php
129
     * @param bool $foundOnly Send cursor limit and skip information to the count function, if applicable.
130
     * @return int The number of documents returned by this cursor's query.
131
     */
132
    public function count($foundOnly = false)
133
    {
134
        if ($foundOnly && $this->cursor !== null) {
135
            return iterator_count($this->ensureIterator());
136
        }
137
138
        $optionNames = ['hint', 'maxTimeMS'];
139
        if ($foundOnly) {
140
            $optionNames = array_merge($optionNames, ['limit', 'skip']);
141
        }
142
143
        $options = $this->getOptions($optionNames) + $this->options;
144
        try {
145
            $count = $this->collection->count(TypeConverter::fromLegacy($this->query), $options);
146
        } catch (\MongoDB\Driver\Exception\ExecutionTimeoutException $e) {
147
            throw new MongoCursorTimeoutException($e->getMessage(), $e->getCode(), $e);
148
        } catch (\MongoDB\Driver\Exception\Exception $e) {
149
            throw ExceptionConverter::toLegacy($e);
150
        }
151
152
        return $count;
153
    }
154
155
    /**
156
     * Execute the query
157
     * @link http://www.php.net/manual/en/mongocursor.doquery.php
158
     * @throws MongoConnectionException if it cannot reach the database.
159
     * @return void
160
     */
161
    protected function doQuery()
162
    {
163
        $options = $this->getOptions() + $this->options;
164
165
        try {
166
            $this->cursor = $this->collection->find(TypeConverter::fromLegacy($this->query), $options);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->collection->find(...this->query), $options) of type object<MongoDB\Operation\Cursor> is incompatible with the declared type object<MongoDB\Driver\Cursor> of property $cursor.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
167
        } catch (\MongoDB\Driver\Exception\ExecutionTimeoutException $e) {
168
            throw new MongoCursorTimeoutException($e->getMessage(), $e->getCode(), $e);
169
        } catch (\MongoDB\Driver\Exception\Exception $e) {
170
            throw ExceptionConverter::toLegacy($e);
171
        }
172
    }
173
174
    /**
175
     * Return an explanation of the query, often useful for optimization and debugging
176
     * @link http://www.php.net/manual/en/mongocursor.explain.php
177
     * @return array Returns an explanation of the query.
178
     */
179
    public function explain()
180
    {
181
        $this->notImplemented();
182
    }
183
184
    /**
185
     * Sets the fields for a query
186
     * @link http://www.php.net/manual/en/mongocursor.fields.php
187
     * @param array $f Fields to return (or not return).
188
     * @throws MongoCursorException
189
     * @return MongoCursor
190
     */
191
    public function fields(array $f)
192
    {
193
        $this->errorIfOpened();
194
        $this->projection = $f;
195
196
        return $this;
197
    }
198
199
    /**
200
     * Advances the cursor to the next result, and returns that result
201
     * @link http://www.php.net/manual/en/mongocursor.getnext.php
202
     * @throws MongoConnectionException
203
     * @throws MongoCursorTimeoutException
204
     * @return array Returns the next object
205
     */
206
    public function getNext()
207
    {
208
        return $this->next();
209
    }
210
211
    /**
212
     * Checks if there are any more elements in this cursor
213
     * @link http://www.php.net/manual/en/mongocursor.hasnext.php
214
     * @throws MongoConnectionException
215
     * @throws MongoCursorTimeoutException
216
     * @return bool Returns true if there is another element
217
     */
218
    public function hasNext()
219
    {
220
        $this->errorIfOpened();
221
        $this->notImplemented();
222
    }
223
224
    /**
225
     * Gives the database a hint about the query
226
     * @link http://www.php.net/manual/en/mongocursor.hint.php
227
     * @param array|string $keyPattern Indexes to use for the query.
228
     * @throws MongoCursorException
229
     * @return MongoCursor Returns this cursor
230
     */
231
    public function hint($keyPattern)
232
    {
233
        $this->errorIfOpened();
234
        $this->hint = $keyPattern;
235
236
        return $this;
237
    }
238
239
    /**
240
     * Sets whether this cursor will timeout
241
     * @link http://www.php.net/manual/en/mongocursor.immortal.php
242
     * @param bool $liveForever If the cursor should be immortal.
243
     * @throws MongoCursorException
244
     * @return MongoCursor Returns this cursor
245
     */
246
    public function immortal($liveForever = true)
247
    {
248
        $this->errorIfOpened();
249
        $this->noCursorTimeout = $liveForever;
250
251
        return $this;
252
    }
253
254
    /**
255
     * Limits the number of results returned
256
     * @link http://www.php.net/manual/en/mongocursor.limit.php
257
     * @param int $num The number of results to return.
258
     * @throws MongoCursorException
259
     * @return MongoCursor Returns this cursor
260
     */
261
    public function limit($num)
262
    {
263
        $this->errorIfOpened();
264
        $this->limit = $num;
265
266
        return $this;
267
    }
268
269
    /**
270
     * @param int $ms
271
     * @return $this
272
     * @throws MongoCursorException
273
     */
274
    public function maxTimeMS($ms)
275
    {
276
        $this->errorIfOpened();
277
        $this->maxTimeMS = $ms;
278
279
        return $this;
280
    }
281
282
    /**
283
     * @link http://www.php.net/manual/en/mongocursor.partial.php
284
     * @param bool $okay [optional] <p>If receiving partial results is okay.</p>
285
     * @return MongoCursor Returns this cursor.
286
     */
287
    public function partial($okay = true)
288
    {
289
        $this->allowPartialResults = $okay;
290
291
        return $this;
292
    }
293
294
    /**
295
     * Clears the cursor
296
     * @link http://www.php.net/manual/en/mongocursor.reset.php
297
     * @return void
298
     */
299
    public function reset()
300
    {
301
        parent::reset();
302
    }
303
304
    /**
305
     * @link http://www.php.net/manual/en/mongocursor.setflag.php
306
     * @param int $flag
307
     * @param bool $set
308
     * @return MongoCursor
309
     */
310
    public function setFlag($flag, $set = true)
0 ignored issues
show
Unused Code introduced by
The parameter $flag is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $set is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
311
    {
312
        $this->notImplemented();
313
    }
314
315
    /**
316
     * Skips a number of results
317
     * @link http://www.php.net/manual/en/mongocursor.skip.php
318
     * @param int $num The number of results to skip.
319
     * @throws MongoCursorException
320
     * @return MongoCursor Returns this cursor
321
     */
322
    public function skip($num)
323
    {
324
        $this->errorIfOpened();
325
        $this->skip = $num;
326
327
        return $this;
328
    }
329
330
    /**
331
     * Sets whether this query can be done on a slave
332
     * This method will override the static class variable slaveOkay.
333
     * @link http://www.php.net/manual/en/mongocursor.slaveOkay.php
334
     * @param boolean $okay If it is okay to query the slave.
335
     * @throws MongoCursorException
336
     * @return MongoCursor Returns this cursor
337
     */
338
    public function slaveOkay($okay = true)
339
    {
340
        $this->errorIfOpened();
341
342
        $this->setReadPreferenceFromSlaveOkay($okay);
343
344
        return $this;
345
    }
346
347
    /**
348
     * Use snapshot mode for the query
349
     * @link http://www.php.net/manual/en/mongocursor.snapshot.php
350
     * @throws MongoCursorException
351
     * @return MongoCursor Returns this cursor
352
     */
353
    public function snapshot()
354
    {
355
        $this->errorIfOpened();
356
        $this->snapshot = true;
357
358
        return $this;
359
    }
360
361
    /**
362
     * Sorts the results by given fields
363
     * @link http://www.php.net/manual/en/mongocursor.sort.php
364
     * @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
365
     * @throws MongoCursorException
366
     * @return MongoCursor Returns the same cursor that this method was called on
367
     */
368
    public function sort(array $fields)
369
    {
370
        $this->errorIfOpened();
371
        $this->sort = $fields;
372
373
        return $this;
374
    }
375
376
    /**
377
     * Sets whether this cursor will be left open after fetching the last results
378
     * @link http://www.php.net/manual/en/mongocursor.tailable.php
379
     * @param bool $tail If the cursor should be tailable.
380
     * @return MongoCursor Returns this cursor
381
     */
382
    public function tailable($tail = true)
383
    {
384
        $this->errorIfOpened();
385
        $this->tailable = $tail;
386
387
        return $this;
388
    }
389
390
    /**
391
     * @return int|null
392
     */
393
    protected function convertCursorType()
394
    {
395
        if (! $this->tailable) {
396
            return null;
397
        }
398
399
        return $this->awaitData ? Find::TAILABLE_AWAIT : Find::TAILABLE;
400
    }
401
402
    protected function convertModifiers()
403
    {
404
        $modifiers = array_key_exists('modifiers', $this->options) ? $this->options['modifiers'] : [];
405
406
        foreach (['hint', 'snapshot'] as $modifier) {
407
            if ($this->$modifier === null) {
408
                continue;
409
            }
410
411
            $modifiers['$' . $modifier] = $this->$modifier;
412
        }
413
414
        return $modifiers;
415
    }
416
417
    /**
418
     * @return Cursor
419
     */
420
    protected function ensureCursor()
421
    {
422
        if ($this->cursor === null) {
423
            $this->doQuery();
424
        }
425
426
        return $this->cursor;
427
    }
428
429
    /**
430
     * @param \Traversable $traversable
431
     * @return \Generator
432
     */
433
    protected function wrapTraversable(\Traversable $traversable)
434
    {
435
        foreach ($traversable as $key => $value) {
436
            if (isset($value->_id) && ($value->_id instanceof \MongoDB\BSON\ObjectID || !is_object($value->_id))) {
437
                $key = (string) $value->_id;
438
            }
439
            yield $key => $value;
440
        }
441
    }
442
443
    /**
444
     * @return array
445
     */
446
    protected function getCursorInfo()
447
    {
448
        return [
449
            'ns' => $this->ns,
450
            'limit' => $this->limit,
451
            'batchSize' => $this->batchSize,
452
            'skip' => $this->skip,
453
            'flags' => $this->flags,
454
            'query' => $this->query,
455
            'fields' => $this->projection,
456
        ];
457
    }
458
459
    /**
460
     * @return array
461
     */
462
    public function __sleep()
463
    {
464
        return [
465
            'allowPartialResults',
466
            'awaitData',
467
            'flags',
468
            'hint',
469
            'limit',
470
            'maxTimeMS',
471
            'noCursorTimeout',
472
            'optionNames',
473
            'options',
474
            'projection',
475
            'query',
476
            'skip',
477
            'snapshot',
478
            'sort',
479
            'tailable',
480
        ] + parent::__sleep();
481
    }
482
}
483