Completed
Push — master ( f42a76...e2cf37 )
by Andreas
05:39
created

MongoCursor::sort()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4286
cc 1
eloc 4
nc 1
nop 1
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\TypeConverter;
17
use MongoDB\Collection;
18
use MongoDB\Driver\Cursor;
19
use MongoDB\Operation\Find;
20
21
/**
22
 * Result object for database query.
23
 * @link http://www.php.net/manual/en/class.mongocursor.php
24
 */
25
class MongoCursor implements Iterator
1 ignored issue
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
26
{
27
    /**
28
     * @link http://php.net/manual/en/class.mongocursor.php#mongocursor.props.slaveokay
29
     * @static
30
     * @var bool $slaveOkay
31
     */
32
    public static $slaveOkay = FALSE;
33
34
    /**
35
     * @var int <p>
36
     * Set timeout in milliseconds for all database responses. Use
37
     * <em>-1</em> to wait forever. Can be overridden with
38
     * {link http://php.net/manual/en/mongocursor.timeout.php MongoCursor::timeout()}. This does not cause the
39
     * MongoDB server to cancel the operation; it only instructs the driver to
40
     * stop waiting for a response and throw a
41
     * {@link http://php.net/manual/en/class.mongocursortimeoutexception.php MongoCursorTimeoutException} after a set time.
42
     * </p>
43
     */
44
    static $timeout = 30000;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $timeout.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
45
46
    /**
47
     * @var MongoClient
48
     */
49
    private $connection;
50
51
    /**
52
     * @var string
53
     */
54
    private $ns;
55
56
    /**
57
     * @var array
58
     */
59
    private $query;
60
61
    /**
62
     * @var
63
     */
64
    private $filter;
0 ignored issues
show
Unused Code introduced by
The property $filter is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
65
66
    /**
67
     * @var Collection
68
     */
69
    private $collection;
70
71
    /**
72
     * @var Cursor
73
     */
74
    private $cursor;
75
76
    /**
77
     * @var IteratorIterator
78
     */
79
    private $iterator;
80
81
    private $awaitData;
82
    private $batchSize;
83
    private $limit;
84
    private $maxTimeMS;
0 ignored issues
show
Unused Code introduced by
The property $maxTimeMS is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
85
    private $noCursorTimeout;
86
    private $options = [];
87
    private $projection;
88
    private $skip;
89
    private $sort;
90
    private $tailable;
91
92
    /**
93
     * Create a new cursor
94
     * @link http://www.php.net/manual/en/mongocursor.construct.php
95
     * @param MongoClient $connection Database connection.
96
     * @param string $ns Full name of database and collection.
97
     * @param array $query Database query.
98
     * @param array $fields Fields to return.
99
     * @return MongoCursor Returns the new cursor
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
100
     */
101
    public function __construct(MongoClient $connection, $ns, array $query = array(), array $fields = array())
102
    {
103
        $this->connection = $connection;
104
        $this->ns = $ns;
105
        $this->query = $query;
106
        $this->projection = $fields;
107
108
        $nsParts = explode('.', $ns);
109
        $db = array_shift($nsParts);
110
111
        $this->collection = $connection->selectCollection($db, implode('.', $nsParts))->getCollection();
112
    }
113
114
    /**
115
     * Adds a top-level key/value pair to a query
116
     * @link http://www.php.net/manual/en/mongocursor.addoption.php
117
     * @param string $key Fieldname to add.
118
     * @param mixed $value Value to add.
119
     * @throws MongoCursorException
120
     * @return MongoCursor Returns this cursor
121
     */
122
    public function addOption($key, $value)
123
    {
124
        $this->errorIfOpened();
125
        $this->options[$key] = $value;
126
127
        return $this;
128
    }
129
130
    /**
131
     * (PECL mongo &gt;= 1.2.11)<br/>
132
     * Sets whether this cursor will wait for a while for a tailable cursor to return more data
133
     * @param bool $wait [optional] <p>If the cursor should wait for more data to become available.</p>
134
     * @return MongoCursor Returns this cursor.
135
     */
136
    public function awaitData($wait = true)
137
    {
138
        $this->errorIfOpened();
139
        $this->awaitData = $wait;
140
141
        return $this;
142
    }
143
144
    /**
145
     * Limits the number of elements returned in one batch.
146
     *
147
     * @link http://docs.php.net/manual/en/mongocursor.batchsize.php
148
     * @param int $batchSize The number of results to return per batch
149
     * @return MongoCursor Returns this cursor.
150
     */
151
    public function batchSize($batchSize)
152
    {
153
        $this->errorIfOpened();
154
        $this->batchSize = $batchSize;
155
156
        return $this;
157
    }
158
159
    /**
160
     * Counts the number of results for this query
161
     * @link http://www.php.net/manual/en/mongocursor.count.php
162
     * @param bool $foundOnly Send cursor limit and skip information to the count function, if applicable.
163
     * @return int The number of documents returned by this cursor's query.
164
     */
165
    public function count($foundOnly = false)
166
    {
167
        if ($foundOnly && $this->cursor !== null) {
168
            return iterator_count($this->cursor);
169
        }
170
171
        $options = $foundOnly ? $this->applyOptions($this->options, ['skip', 'limit']) : $this->options;
172
173
        return $this->collection->count($this->query, $options);
174
    }
175
176
    /**
177
     * Returns the current element
178
     * @link http://www.php.net/manual/en/mongocursor.current.php
179
     * @return array
180
     */
181
    public function current()
182
    {
183
        $document = $this->ensureIterator()->current();
184
        if ($document !== null) {
185
            $document = TypeConverter::convertObjectToLegacyArray($document);
186
        }
187
188
        return $document;
189
    }
190
191
    /**
192
     * Checks if there are documents that have not been sent yet from the database for this cursor
193
     * @link http://www.php.net/manual/en/mongocursor.dead.php
194
     * @return boolean Returns if there are more results that have not been sent to the client, yet.
195
     */
196
    public function dead()
197
    {
198
        return $this->ensureCursor()->isDead();
199
    }
200
201
    /**
202
     * Execute the query
203
     * @link http://www.php.net/manual/en/mongocursor.doquery.php
204
     * @throws MongoConnectionException if it cannot reach the database.
205
     * @return void
206
     */
207
    protected function doQuery()
208
    {
209
        $this->notImplemented();
210
    }
211
212
    /**
213
     * Return an explanation of the query, often useful for optimization and debugging
214
     * @link http://www.php.net/manual/en/mongocursor.explain.php
215
     * @return array Returns an explanation of the query.
216
     */
217
    public function explain()
218
    {
219
        $this->notImplemented();
220
    }
221
222
    /**
223
     * Sets the fields for a query
224
     * @link http://www.php.net/manual/en/mongocursor.fields.php
225
     * @param array $f Fields to return (or not return).
226
     * @throws MongoCursorException
227
     * @return MongoCursor
228
     */
229
    public function fields(array $f)
230
    {
231
        $this->errorIfOpened();
232
        $this->projection = $f;
233
234
        return $this;
235
    }
236
237
    /**
238
     * Return the next object to which this cursor points, and advance the cursor
239
     * @link http://www.php.net/manual/en/mongocursor.getnext.php
240
     * @throws MongoConnectionException
241
     * @throws MongoCursorTimeoutException
242
     * @return array Returns the next object
243
     */
244
    public function getNext()
245
    {
246
        $this->next();
247
248
        return $this->current();
249
    }
250
251
    /**
252
     * (PECL mongo &gt;= 1.3.3)<br/>
253
     * @link http://www.php.net/manual/en/mongocursor.getreadpreference.php
254
     * @return array This function returns an array describing the read preference. The array contains the values <em>type</em> for the string
255
     * read preference mode (corresponding to the {@link http://www.php.net/manual/en/class.mongoclient.php MongoClient} constants), and <em>tagsets</em> containing a list of all tag set criteria. If no tag sets were specified, <em>tagsets</em> will not be present in the array.
256
     */
257
    public function getReadPreference()
258
    {
259
        $this->notImplemented();
260
    }
261
262
    /**
263
     * Checks if there are any more elements in this cursor
264
     * @link http://www.php.net/manual/en/mongocursor.hasnext.php
265
     * @throws MongoConnectionException
266
     * @throws MongoCursorTimeoutException
267
     * @return bool Returns true if there is another element
268
     */
269
    public function hasNext()
270
    {
271
        $this->notImplemented();
272
    }
273
274
    /**
275
     * Gives the database a hint about the query
276
     * @link http://www.php.net/manual/en/mongocursor.hint.php
277
     * @param array $key_pattern Indexes to use for the query.
278
     * @throws MongoCursorException
279
     * @return MongoCursor Returns this cursor
280
     */
281
    public function hint(array $key_pattern)
0 ignored issues
show
Unused Code introduced by
The parameter $key_pattern 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...
282
    {
283
        $this->notImplemented();
284
    }
285
286
    /**
287
     * Sets whether this cursor will timeout
288
     * @link http://www.php.net/manual/en/mongocursor.immortal.php
289
     * @param bool $liveForever If the cursor should be immortal.
290
     * @throws MongoCursorException
291
     * @return MongoCursor Returns this cursor
292
     */
293
    public function immortal($liveForever = true)
294
    {
295
        $this->errorIfOpened();
296
        $this->noCursorTimeout = $liveForever;
297
298
        return $this;
299
    }
300
301
    /**
302
     * Gets the query, fields, limit, and skip for this cursor
303
     * @link http://www.php.net/manual/en/mongocursor.info.php
304
     * @return array The query, fields, limit, and skip for this cursor as an associative array.
305
     */
306
    public function info()
307
    {
308
        $this->notImplemented();
309
    }
310
311
    /**
312
     * Returns the current result's _id
313
     * @link http://www.php.net/manual/en/mongocursor.key.php
314
     * @return string The current result's _id as a string.
315
     */
316
    public function key()
317
    {
318
        return $this->ensureIterator()->key();
319
    }
320
321
    /**
322
     * Limits the number of results returned
323
     * @link http://www.php.net/manual/en/mongocursor.limit.php
324
     * @param int $num The number of results to return.
325
     * @throws MongoCursorException
326
     * @return MongoCursor Returns this cursor
327
     */
328
    public function limit($num)
329
    {
330
        $this->errorIfOpened();
331
        $this->limit = $num;
332
333
        return $this;
334
    }
335
336
    /**
337
     * @param int $ms
338
     * @return $this
339
     * @throws MongoCursorException
340
     */
341
    public function maxTimeMS($ms)
342
    {
343
        $this->errorIfOpened();
344
        $this->maxTimeMs = $ms;
0 ignored issues
show
Bug introduced by
The property maxTimeMs does not seem to exist. Did you mean maxTimeMS?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
345
346
        return $this;
347
    }
348
349
    /**
350
     * Advances the cursor to the next result
351
     * @link http://www.php.net/manual/en/mongocursor.next.php
352
     * @throws MongoConnectionException
353
     * @throws MongoCursorTimeoutException
354
     * @return void
355
     */
356
    public function next()
357
    {
358
        $this->ensureIterator()->next();
359
    }
360
361
    /**
362
     * (PECL mongo &gt;= 1.2.0)<br/>
363
     * @link http://www.php.net/manual/en/mongocursor.partial.php
364
     * @param bool $okay [optional] <p>If receiving partial results is okay.</p>
365
     * @return MongoCursor Returns this cursor.
366
     */
367
    public function partial($okay = true)
0 ignored issues
show
Unused Code introduced by
The parameter $okay 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...
368
    {
369
        $this->notImplemented();
370
    }
371
372
    /**
373
     * Clears the cursor
374
     * @link http://www.php.net/manual/en/mongocursor.reset.php
375
     * @return void
376
     */
377
    public function reset()
378
    {
379
        $this->cursor = null;
380
        $this->iterator = null;
381
    }
382
383
    /**
384
     * Returns the cursor to the beginning of the result set
385
     * @throws MongoConnectionException
386
     * @throws MongoCursorTimeoutException
387
     * @return void
388
     */
389
    public function rewind()
390
    {
391
        // Note: rewinding the cursor means recreating it internally
392
        $this->reset();
393
        $this->ensureIterator()->rewind();
394
    }
395
396
    /**
397
     * (PECL mongo &gt;= 1.2.1)<br/>
398
     * @link http://www.php.net/manual/en/mongocursor.setflag.php
399
     * @param int $flag <p>
400
     * Which flag to set. You can not set flag 6 (EXHAUST) as the driver does
401
     * not know how to handle them. You will get a warning if you try to use
402
     * this flag. For available flags, please refer to the wire protocol
403
     * {@link http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-OPQUERY documentation}.
404
     * </p>
405
     * @param bool $set [optional] <p>Whether the flag should be set (<b>TRUE</b>) or unset (<b>FALSE</b>).</p>
406
     * @return MongoCursor
407
     */
408
    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...
409
    {
410
        $this->notImplemented();
411
    }
412
413
    /**
414
     * (PECL mongo &gt;= 1.3.3)<br/>
415
     * @link http://www.php.net/manual/en/mongocursor.setreadpreference.php
416
     * @param string $read_preference <p>The read preference mode: MongoClient::RP_PRIMARY, MongoClient::RP_PRIMARY_PREFERRED, MongoClient::RP_SECONDARY, MongoClient::RP_SECONDARY_PREFERRED, or MongoClient::RP_NEAREST.</p>
417
     * @param array $tags [optional] <p>The read preference mode: MongoClient::RP_PRIMARY, MongoClient::RP_PRIMARY_PREFERRED, MongoClient::RP_SECONDARY, MongoClient::RP_SECONDARY_PREFERRED, or MongoClient::RP_NEAREST.</p>
418
     * @return MongoCursor Returns this cursor.
419
     */
420
    public function setReadPreference($read_preference, array $tags)
0 ignored issues
show
Unused Code introduced by
The parameter $read_preference 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 $tags 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...
421
    {
422
        $this->notImplemented();
423
    }
424
425
    /**
426
     * Skips a number of results
427
     * @link http://www.php.net/manual/en/mongocursor.skip.php
428
     * @param int $num The number of results to skip.
429
     * @throws MongoCursorException
430
     * @return MongoCursor Returns this cursor
431
     */
432
    public function skip($num)
433
    {
434
        $this->errorIfOpened();
435
        $this->skip = $num;
436
437
        return $this;
438
    }
439
440
    /**
441
     * Sets whether this query can be done on a slave
442
     * This method will override the static class variable slaveOkay.
443
     * @link http://www.php.net/manual/en/mongocursor.slaveOkay.php
444
     * @param boolean $okay If it is okay to query the slave.
445
     * @throws MongoCursorException
446
     * @return MongoCursor Returns this cursor
447
     */
448
    public function slaveOkay($okay = true)
0 ignored issues
show
Unused Code introduced by
The parameter $okay 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...
449
    {
450
        $this->notImplemented();
451
    }
452
453
    /**
454
     * Use snapshot mode for the query
455
     * @link http://www.php.net/manual/en/mongocursor.snapshot.php
456
     * @throws MongoCursorException
457
     * @return MongoCursor Returns this cursor
458
     */
459
    public function snapshot()
460
    {
461
        $this->notImplemented();
462
    }
463
464
    /**
465
     * Sorts the results by given fields
466
     * @link http://www.php.net/manual/en/mongocursor.sort.php
467
     * @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
468
     * @throws MongoCursorException
469
     * @return MongoCursor Returns the same cursor that this method was called on
470
     */
471
    public function sort(array $fields)
472
    {
473
        $this->errorIfOpened();
474
        $this->sort = $fields;
475
476
        return $this;
477
    }
478
479
    /**
480
     * Sets whether this cursor will be left open after fetching the last results
481
     * @link http://www.php.net/manual/en/mongocursor.tailable.php
482
     * @param bool $tail If the cursor should be tailable.
483
     * @return MongoCursor Returns this cursor
484
     */
485
    public function tailable($tail = true)
486
    {
487
        $this->errorIfOpened();
488
        $this->tailable = $tail;
489
490
        return $this;
491
    }
492
493
    /**
494
     * Sets a client-side timeout for this query
495
     * @link http://www.php.net/manual/en/mongocursor.timeout.php
496
     * @param int $ms The number of milliseconds for the cursor to wait for a response. By default, the cursor will wait forever.
497
     * @throws MongoCursorTimeoutException
498
     * @return MongoCursor Returns this cursor
499
     */
500
    public function timeout($ms)
0 ignored issues
show
Unused Code introduced by
The parameter $ms 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...
501
    {
502
        $this->notImplemented();
503
    }
504
505
    /**
506
     * Checks if the cursor is reading a valid result.
507
     * @link http://www.php.net/manual/en/mongocursor.valid.php
508
     * @return boolean If the current result is not null.
509
     */
510
    public function valid()
511
    {
512
        return $this->ensureIterator()->valid();
513
    }
514
515
    private function applyOptions($options, $optionNames)
516
    {
517
        foreach ($optionNames as $option) {
518
            if ($this->$option === null) {
519
                continue;
520
            }
521
522
            $options[$option] = $this->$option;
523
        }
524
525
        return $options;
526
    }
527
528
    /**
529
     * @return Cursor
530
     */
531
    private function ensureCursor()
532
    {
533
        if ($this->cursor === null) {
534
            $options = $this->applyOptions($this->options, ['skip', 'limit', 'sort', 'batchSize', 'projection']);
535
536
            if ($this->tailable) {
537
                $options['cursorType'] = $this->awaitData ? Find::TAILABLE : Find::TAILABLE_AWAIT;
538
            }
539
540
            $this->cursor = $this->collection->find($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...
541
        }
542
543
        return $this->cursor;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->cursor; of type MongoDB\Operation\Cursor|MongoDB\Driver\Cursor adds the type MongoDB\Operation\Cursor to the return on line 543 which is incompatible with the return type documented by MongoCursor::ensureCursor of type MongoDB\Driver\Cursor.
Loading history...
544
    }
545
546
    private function errorIfOpened()
547
    {
548
        if ($this->cursor === null) {
549
            return;
550
        }
551
552
        throw new MongoCursorException('cannot modify cursor after beginning iteration.');
553
    }
554
555
    /**
556
     * @return IteratorIterator
557
     */
558
    private function ensureIterator()
559
    {
560
        if ($this->iterator === null) {
561
            $this->iterator = new IteratorIterator($this->ensureCursor());
562
        }
563
564
        return $this->iterator;
565
    }
566
567
    protected function notImplemented()
568
    {
569
        throw new \Exception('Not implemented');
570
    }
571
}
572