Completed
Pull Request — master (#20)
by
unknown
02:35
created

MongoCollection::notImplemented()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
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\Helper;
17
use Alcaeus\MongoDbAdapter\TypeConverter;
18
use Alcaeus\MongoDbAdapter\ExceptionConverter;
19
20
/**
21
 * Represents a database collection.
22
 * @link http://www.php.net/manual/en/class.mongocollection.php
23
 */
24
class MongoCollection
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...
25
{
26
    use Helper\ReadPreference;
27
    use Helper\SlaveOkay;
28
    use Helper\WriteConcern;
29
30
    const ASCENDING = 1;
31
    const DESCENDING = -1;
32
33
    /**
34
     * @var MongoDB
35
     */
36
    public $db = NULL;
37
38
    /**
39
     * @var string
40
     */
41
    protected $name;
42
43
    /**
44
     * @var \MongoDB\Collection
45
     */
46
    protected $collection;
47
48
    /**
49
     * Creates a new collection
50
     *
51
     * @link http://www.php.net/manual/en/mongocollection.construct.php
52
     * @param MongoDB $db Parent database.
53
     * @param string $name Name for this collection.
54
     * @throws Exception
55
     * @return MongoCollection
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...
56
     */
57
    public function __construct(MongoDB $db, $name)
58
    {
59
        $this->checkCollectionName($name);
60
        $this->db = $db;
61
        $this->name = $name;
62
63
        $this->setReadPreferenceFromArray($db->getReadPreference());
64
        $this->setWriteConcernFromArray($db->getWriteConcern());
65
66
        $this->createCollectionObject();
67
    }
68
69
    /**
70
     * Gets the underlying collection for this object
71
     *
72
     * @internal This part is not of the ext-mongo API and should not be used
73
     * @return \MongoDB\Collection
74
     */
75
    public function getCollection()
76
    {
77
        return $this->collection;
78
    }
79
80
    /**
81
     * String representation of this collection
82
     *
83
     * @link http://www.php.net/manual/en/mongocollection.--tostring.php
84
     * @return string Returns the full name of this collection.
85
     */
86
    public function __toString()
87
    {
88
        return (string) $this->db . '.' . $this->name;
89
    }
90
91
    /**
92
     * Gets a collection
93
     *
94
     * @link http://www.php.net/manual/en/mongocollection.get.php
95
     * @param string $name The next string in the collection name.
96
     * @return MongoCollection
97
     */
98
    public function __get($name)
99
    {
100
        // Handle w and wtimeout properties that replicate data stored in $readPreference
101
        if ($name === 'w' || $name === 'wtimeout') {
102
            return $this->getWriteConcern()[$name];
103
        }
104
105
        return $this->db->selectCollection($this->name . '.' . $name);
106
    }
107
108
    /**
109
     * @param string $name
110
     * @param mixed $value
111
     */
112 View Code Duplication
    public function __set($name, $value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
    {
114
        if ($name === 'w' || $name === 'wtimeout') {
115
            $this->setWriteConcernFromArray([$name => $value] + $this->getWriteConcern());
116
            $this->createCollectionObject();
117
        }
118
    }
119
120
    /**
121
     * Perform an aggregation using the aggregation framework
122
     *
123
     * @link http://www.php.net/manual/en/mongocollection.aggregate.php
124
     * @param array $pipeline
125
     * @param array $op
126
     * @return array
127
     */
128
    public function aggregate(array $pipeline, array $op = [])
129
    {
130
        if (! TypeConverter::isNumericArray($pipeline)) {
131
            $pipeline = [];
132
            $options = [];
133
134
            $i = 0;
135
            foreach (func_get_args() as $operator) {
136
                $i++;
137
                if (! is_array($operator)) {
138
                    trigger_error("Argument $i is not an array", E_WARNING);
139
                    return;
140
                }
141
142
                $pipeline[] = $operator;
143
            }
144
        } else {
145
            $options = $op;
146
        }
147
148
        $command = [
149
            'aggregate' => $this->name,
150
            'pipeline' => $pipeline
151
        ];
152
153
        $command += $options;
154
155
        try {
156
            return $this->db->command($command);
157
        } catch (MongoCursorTimeoutException $e) {
158
            throw new MongoExecutionTimeoutException($e->getMessage(), $e->getCode(), $e->getPrevious());
159
        }
160
    }
161
162
    /**
163
     * Execute an aggregation pipeline command and retrieve results through a cursor
164
     *
165
     * @link http://php.net/manual/en/mongocollection.aggregatecursor.php
166
     * @param array $pipeline
167
     * @param array $options
168
     * @return MongoCommandCursor
169
     */
170
    public function aggregateCursor(array $pipeline, array $options = [])
171
    {
172
        // Build command manually, can't use mongo-php-library here
173
        $command = [
174
            'aggregate' => $this->name,
175
            'pipeline' => $pipeline
176
        ];
177
178
        // Convert cursor option
179
        if (! isset($options['cursor'])) {
180
            $options['cursor'] = true;
181
        }
182
183
        $command += $options;
184
185
        $cursor = new MongoCommandCursor($this->db->getConnection(), (string) $this, $command);
186
        $cursor->setReadPreference($this->getReadPreference());
0 ignored issues
show
Documentation introduced by
$this->getReadPreference() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
187
188
        return $cursor;
189
    }
190
191
    /**
192
     * Returns this collection's name
193
     *
194
     * @link http://www.php.net/manual/en/mongocollection.getname.php
195
     * @return string
196
     */
197
    public function getName()
198
    {
199
        return $this->name;
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205
    public function setReadPreference($readPreference, $tags = null)
206
    {
207
        $result = $this->setReadPreferenceFromParameters($readPreference, $tags);
208
        $this->createCollectionObject();
209
210
        return $result;
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function setWriteConcern($wstring, $wtimeout = 0)
217
    {
218
        $result = $this->setWriteConcernFromParameters($wstring, $wtimeout);
219
        $this->createCollectionObject();
220
221
        return $result;
222
    }
223
224
    /**
225
     * Drops this collection
226
     *
227
     * @link http://www.php.net/manual/en/mongocollection.drop.php
228
     * @return array Returns the database response.
229
     */
230
    public function drop()
231
    {
232
        return TypeConverter::toLegacy($this->collection->drop());
233
    }
234
235
    /**
236
     * Validates this collection
237
     *
238
     * @link http://www.php.net/manual/en/mongocollection.validate.php
239
     * @param bool $scan_data Only validate indices, not the base collection.
240
     * @return array Returns the database's evaluation of this object.
241
     */
242
    public function validate($scan_data = FALSE)
243
    {
244
        $command = [
245
            'validate' => $this->name,
246
            'full'     => $scan_data,
247
        ];
248
249
        return $this->db->command($command);
250
    }
251
252
    /**
253
     * Inserts an array into the collection
254
     *
255
     * @link http://www.php.net/manual/en/mongocollection.insert.php
256
     * @param array|object $a
257
     * @param array $options
258
     * @throws MongoException if the inserted document is empty or if it contains zero-length keys. Attempting to insert an object with protected and private properties will cause a zero-length key error.
259
     * @throws MongoCursorException if the "w" option is set and the write fails.
260
     * @throws MongoCursorTimeoutException if the "w" option is set to a value greater than one and the operation takes longer than MongoCursor::$timeout milliseconds to complete. This does not kill the operation on the server, it is a client-side timeout. The operation in MongoCollection::$wtimeout is milliseconds.
261
     * @return bool|array Returns an array containing the status of the insertion if the "w" option is set.
262
     */
263
    public function insert($a, array $options = [])
264
    {
265
        if (! count((array)$a)) {
266
            throw new \MongoException('document must be an array or object');
267
        }
268
269
        try {
270
            $result = $this->collection->insertOne(
271
                TypeConverter::fromLegacy($a),
272
                $this->convertWriteConcernOptions($options)
273
            );
274
        } catch (\MongoDB\Driver\Exception\BulkWriteException $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\BulkWriteException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
275
            $writeResult = $e->getWriteResult();
276
            $writeError = $writeResult->getWriteErrors()[0];
277
            return [
278
                'ok' => 0.0,
279
                'n' => 0,
280
                'err' => $writeError->getCode(),
281
                'errmsg' => $writeError->getMessage(),
282
            ];
283
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
284
            ExceptionConverter::toLegacy($e);
285
        }
286
287
288
        if (! $result->isAcknowledged()) {
289
            return true;
290
        }
291
292
        return [
293
            'ok' => 1.0,
294
            'n' => 0,
295
            'err' => null,
296
            'errmsg' => null,
297
        ];
298
    }
299
300
    /**
301
     * Inserts multiple documents into this collection
302
     *
303
     * @link http://www.php.net/manual/en/mongocollection.batchinsert.php
304
     * @param array $a An array of arrays.
305
     * @param array $options Options for the inserts.
306
     * @throws MongoCursorException
307
     * @return mixed If "safe" is set, returns an associative array with the status of the inserts ("ok") and any error that may have occured ("err"). Otherwise, returns TRUE if the batch insert was successfully sent, FALSE otherwise.
308
     */
309
    public function batchInsert(array $a, array $options = [])
310
    {
311
        try {
312
            $result = $this->collection->insertMany(
313
                TypeConverter::fromLegacy($a),
314
                $this->convertWriteConcernOptions($options)
315
            );
316
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
317
            ExceptionConverter::toLegacy($e);
318
        }
319
320
        if (! $result->isAcknowledged()) {
321
            return true;
322
        }
323
324
        return [
325
            'connectionId' => 0,
326
            'n' => 0,
327
            'syncMillis' => 0,
328
            'writtenTo' => null,
329
            'err' => null,
330
            'errmsg' => null,
331
        ];
332
    }
333
334
    /**
335
     * Update records based on a given criteria
336
     *
337
     * @link http://www.php.net/manual/en/mongocollection.update.php
338
     * @param array $criteria Description of the objects to update.
339
     * @param array $newobj The object with which to update the matching records.
340
     * @param array $options
341
     * @throws MongoCursorException
342
     * @return boolean
343
     */
344
    public function update(array $criteria , array $newobj, array $options = [])
345
    {
346
        $multiple = isset($options['multiple']) ? $options['multiple'] : false;
347
        $method = $multiple ? 'updateMany' : 'updateOne';
348
        unset($options['multiple']);
349
350
        try {
351
            /** @var \MongoDB\UpdateResult $result */
352
            $result = $this->collection->$method(
353
                TypeConverter::fromLegacy($criteria),
354
                TypeConverter::fromLegacy($newobj),
355
                $this->convertWriteConcernOptions($options)
356
            );
357
        } catch (\MongoDB\Driver\Exception\BulkWriteException $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\BulkWriteException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
358
            $writeResult = $e->getWriteResult();
359
            $writeError = $writeResult->getWriteErrors()[0];
360
            return [
361
                'ok' => 0.0,
362
                'nModified' => $writeResult->getModifiedCount(),
363
                'n' => $writeResult->getMatchedCount(),
364
                'err' => $writeError->getCode(),
365
                'errmsg' => $writeError->getMessage(),
366
                'updatedExisting' => $writeResult->getUpsertedCount() == 0,
367
            ];
368
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
369
            ExceptionConverter::toLegacy($e);
370
        }
371
372
        if (! $result->isAcknowledged()) {
373
            return true;
374
        }
375
376
        return [
377
            'ok' => 1.0,
378
            'nModified' => $result->getModifiedCount(),
379
            'n' => $result->getMatchedCount(),
380
            'err' => null,
381
            'errmsg' => null,
382
            'updatedExisting' => $result->getUpsertedCount() == 0,
383
        ];
384
    }
385
386
    /**
387
     * Remove records from this collection
388
     *
389
     * @link http://www.php.net/manual/en/mongocollection.remove.php
390
     * @param array $criteria Query criteria for the documents to delete.
391
     * @param array $options An array of options for the remove operation.
392
     * @throws MongoCursorException
393
     * @throws MongoCursorTimeoutException
394
     * @return bool|array Returns an array containing the status of the removal
395
     * if the "w" option is set. Otherwise, returns TRUE.
396
     */
397
    public function remove(array $criteria = [], array $options = [])
398
    {
399
        $multiple = isset($options['justOne']) ? !$options['justOne'] : true;
400
        $method = $multiple ? 'deleteMany' : 'deleteOne';
401
402
        try {
403
            /** @var \MongoDB\DeleteResult $result */
404
            $result = $this->collection->$method(
405
                TypeConverter::fromLegacy($criteria),
406
                $this->convertWriteConcernOptions($options)
407
            );
408
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
409
            ExceptionConverter::toLegacy($e);
410
        }
411
412
        if (! $result->isAcknowledged()) {
413
            return true;
414
        }
415
416
        return [
417
            'ok' => 1.0,
418
            'n' => $result->getDeletedCount(),
419
            'err' => null,
420
            'errmsg' => null
421
        ];
422
    }
423
424
    /**
425
     * Querys this collection
426
     *
427
     * @link http://www.php.net/manual/en/mongocollection.find.php
428
     * @param array $query The fields for which to search.
429
     * @param array $fields Fields of the results to return.
430
     * @return MongoCursor
431
     */
432
    public function find(array $query = [], array $fields = [])
433
    {
434
        $cursor = new MongoCursor($this->db->getConnection(), (string) $this, $query, $fields);
435
        $cursor->setReadPreference($this->getReadPreference());
0 ignored issues
show
Documentation introduced by
$this->getReadPreference() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
436
437
        return $cursor;
438
    }
439
440
    /**
441
     * Retrieve a list of distinct values for the given key across a collection
442
     *
443
     * @link http://www.php.net/manual/ru/mongocollection.distinct.php
444
     * @param string $key The key to use.
445
     * @param array $query An optional query parameters
446
     * @return array|bool Returns an array of distinct values, or FALSE on failure
447
     */
448
    public function distinct($key, array $query = [])
449
    {
450
        try {
451
            return array_map([TypeConverter::class, 'toLegacy'], $this->collection->distinct($key, $query));
452
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
453
            return false;
454
        }
455
    }
456
457
    /**
458
     * Update a document and return it
459
     *
460
     * @link http://www.php.net/manual/ru/mongocollection.findandmodify.php
461
     * @param array $query The query criteria to search for.
462
     * @param array $update The update criteria.
463
     * @param array $fields Optionally only return these fields.
464
     * @param array $options An array of options to apply, such as remove the match document from the DB and return it.
465
     * @return array Returns the original document, or the modified document when new is set.
466
     */
467
    public function findAndModify(array $query, array $update = null, array $fields = null, array $options = [])
468
    {
469
        $query = TypeConverter::fromLegacy($query);
470
        try {
471
            if (isset($options['remove'])) {
472
                unset($options['remove']);
473
                $document = $this->collection->findOneAndDelete($query, $options);
474
            } else {
475
                $update = is_array($update) ? TypeConverter::fromLegacy($update) : [];
476
477
                if (isset($options['new'])) {
478
                    $options['returnDocument'] = \MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER;
479
                    unset($options['new']);
480
                }
481
482
                $options['projection'] = is_array($fields) ? TypeConverter::fromLegacy($fields) : [];
483
484
                $document = $this->collection->findOneAndUpdate($query, $update, $options);
485
            }
486
        } catch (\MongoDB\Driver\Exception\ConnectionException $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\ConnectionException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
487
            throw new MongoResultException($e->getMessage(), $e->getCode(), $e);
488
        } catch (\MongoDB\Driver\Exception\ExecutionTimeoutException $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\ExecutionTimeoutException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
489
            ExceptionConverter::toLegacy($e);
490
        }
491
492
        if ($document) {
493
            $document = TypeConverter::toLegacy($document);
0 ignored issues
show
Bug introduced by
The variable $document does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
494
        }
495
496
        return $document;
497
    }
498
499
    /**
500
     * Querys this collection, returning a single element
501
     *
502
     * @link http://www.php.net/manual/en/mongocollection.findone.php
503
     * @param array $query The fields for which to search.
504
     * @param array $fields Fields of the results to return.
505
     * @param array $options
506
     * @return array|null
507
     */
508
    public function findOne(array $query = [], array $fields = [], array $options = [])
509
    {
510
        $options = ['projection' => $fields] + $options;
511
        try {
512
            $document = $this->collection->findOne(TypeConverter::fromLegacy($query), $options);
513
        } catch (\MongoDB\Driver\Exception\ExecutionTimeoutException $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\ExecutionTimeoutException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
514
            throw new MongoExecutionTimeoutException($e->getMessage(), $e->getCode(), $e);
515
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
516
            ExceptionConverter::toLegacy($e);
517
        }
518
519
        if ($document !== null) {
520
            $document = TypeConverter::toLegacy($document);
521
        }
522
523
        return $document;
524
    }
525
526
    /**
527
     * Creates an index on the given field(s), or does nothing if the index already exists
528
     *
529
     * @link http://www.php.net/manual/en/mongocollection.createindex.php
530
     * @param array $keys Field or fields to use as index.
531
     * @param array $options [optional] This parameter is an associative array of the form array("optionname" => <boolean>, ...).
532
     * @return array Returns the database response.
533
     *
534
     * @todo This method does not yet return the correct result
535
     */
536
    public function createIndex(array $keys, array $options = [])
537
    {
538
        if (! is_array($keys) || ! count($keys)) {
539
            throw new MongoException('keys cannot be empty');
540
        }
541
542
        // duplicate
543
        $indexes = $this->collection->listIndexes();
544
        foreach ($indexes as $index) {
545
            if ($index->getKey() === $keys) {
546
                throw new \MongoDuplicateKeyException();
547
            }
548
        }
549
550
        try {
551
            $this->collection->createIndex($keys, $this->convertWriteConcernOptions($options));
552
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
553
            ExceptionConverter::toLegacy($e);
554
        }
555
556
        return [
557
            'createdCollectionAutomatically' => true,
558
            'numIndexesBefore' => count($indexes),
559
            'numIndexesAfter' => count($indexes) + 1,
560
            'ok' => 1.0
561
        ];
562
    }
563
564
    /**
565
     * Creates an index on the given field(s), or does nothing if the index already exists
566
     *
567
     * @link http://www.php.net/manual/en/mongocollection.ensureindex.php
568
     * @param array $keys Field or fields to use as index.
569
     * @param array $options [optional] This parameter is an associative array of the form array("optionname" => <boolean>, ...).
570
     * @return boolean always true
571
     * @deprecated Use MongoCollection::createIndex() instead.
572
     */
573
    public function ensureIndex(array $keys, array $options = [])
574
    {
575
        $this->createIndex($keys, $options);
576
577
        return true;
578
    }
579
580
    /**
581
     * Deletes an index from this collection
582
     *
583
     * @link http://www.php.net/manual/en/mongocollection.deleteindex.php
584
     * @param string|array $keys Field or fields from which to delete the index.
585
     * @return array Returns the database response.
586
     */
587
    public function deleteIndex($keys)
588
    {
589
        if (is_string($keys)) {
590
            $indexName = $keys;
591
        } elseif (is_array($keys)) {
592
            $indexName = \MongoDB\generate_index_name($keys);
593
        } else {
594
            throw new \InvalidArgumentException();
595
        }
596
597
        return TypeConverter::toLegacy($this->collection->dropIndex($indexName));
598
    }
599
600
    /**
601
     * Delete all indexes for this collection
602
     *
603
     * @link http://www.php.net/manual/en/mongocollection.deleteindexes.php
604
     * @return array Returns the database response.
605
     */
606
    public function deleteIndexes()
607
    {
608
        return TypeConverter::toLegacy($this->collection->dropIndexes());
609
    }
610
611
    /**
612
     * Returns an array of index names for this collection
613
     *
614
     * @link http://www.php.net/manual/en/mongocollection.getindexinfo.php
615
     * @return array Returns a list of index names.
616
     */
617
    public function getIndexInfo()
618
    {
619
        $convertIndex = function(\MongoDB\Model\IndexInfo $indexInfo) {
620
            return [
621
                'v' => $indexInfo->getVersion(),
622
                'key' => $indexInfo->getKey(),
623
                'name' => $indexInfo->getName(),
624
                'ns' => $indexInfo->getNamespace(),
625
            ];
626
        };
627
628
        return array_map($convertIndex, iterator_to_array($this->collection->listIndexes()));
629
    }
630
631
    /**
632
     * Counts the number of documents in this collection
633
     *
634
     * @link http://www.php.net/manual/en/mongocollection.count.php
635
     * @param array|stdClass $query
636
     * @param array $options
637
     * @return int Returns the number of documents matching the query.
638
     */
639
    public function count($query = [], array $options = [])
640
    {
641
        try {
642
            return $this->collection->count(TypeConverter::fromLegacy($query), $options);
643
        } catch (\MongoDB\Driver\Exception\ExecutionTimeoutException $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\ExecutionTimeoutException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
644
            throw new MongoExecutionTimeoutException($e->getMessage(), $e->getCode(), $e);
645
        } catch (\MongoDB\Driver\Exception\Exception $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
646
            ExceptionConverter::toLegacy($e);
647
        }
648
    }
649
650
    /**
651
     * Saves an object to this collection
652
     *
653
     * @link http://www.php.net/manual/en/mongocollection.save.php
654
     * @param array|object $a Array to save. If an object is used, it may not have protected or private properties.
655
     * @param array $options Options for the save.
656
     * @throws MongoException if the inserted document is empty or if it contains zero-length keys. Attempting to insert an object with protected and private properties will cause a zero-length key error.
657
     * @throws MongoCursorException if the "w" option is set and the write fails.
658
     * @throws MongoCursorTimeoutException if the "w" option is set to a value greater than one and the operation takes longer than MongoCursor::$timeout milliseconds to complete. This does not kill the operation on the server, it is a client-side timeout. The operation in MongoCollection::$wtimeout is milliseconds.
659
     * @return array|boolean If w was set, returns an array containing the status of the save.
660
     * Otherwise, returns a boolean representing if the array was not empty (an empty array will not be inserted).
661
     */
662
    public function save($a, array $options = [])
663
    {
664
        if (is_object($a)) {
665
            $a = (array) $a;
666
        }
667
668
        if ( ! array_key_exists('_id', $a)) {
669
            $id = new \MongoId();
670
        } else {
671
            $id = $a['_id'];
672
            unset($a['_id']);
673
        }
674
        $options['upsert'] = true;
675
676
        if (! count($a)) {
677
            throw new MongoException('document can not be empty');
678
        }
679
680
        return $this->update(['_id' => $id], ['$set' => $a], $options);
681
    }
682
683
    /**
684
     * Creates a database reference
685
     *
686
     * @link http://www.php.net/manual/en/mongocollection.createdbref.php
687
     * @param array|object $document_or_id Object to which to create a reference.
688
     * @return array Returns a database reference array.
689
     */
690 View Code Duplication
    public function createDBRef($document_or_id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
691
    {
692
        if ($document_or_id instanceof \MongoId) {
693
            $id = $document_or_id;
694
        } elseif (is_object($document_or_id)) {
695
            if (! isset($document_or_id->_id)) {
696
                return null;
697
            }
698
699
            $id = $document_or_id->_id;
700
        } elseif (is_array($document_or_id)) {
701
            if (! isset($document_or_id['_id'])) {
702
                return null;
703
            }
704
705
            $id = $document_or_id['_id'];
706
        } else {
707
            $id = $document_or_id;
708
        }
709
710
        return MongoDBRef::create($this->name, $id);
711
    }
712
713
    /**
714
     * Fetches the document pointed to by a database reference
715
     *
716
     * @link http://www.php.net/manual/en/mongocollection.getdbref.php
717
     * @param array $ref A database reference.
718
     * @return array Returns the database document pointed to by the reference.
719
     */
720
    public function getDBRef(array $ref)
721
    {
722
        return $this->db->getDBRef($ref);
723
    }
724
725
    /**
726
     * Performs an operation similar to SQL's GROUP BY command
727
     *
728
     * @link http://www.php.net/manual/en/mongocollection.group.php
729
     * @param mixed $keys Fields to group by. If an array or non-code object is passed, it will be the key used to group results.
730
     * @param array $initial Initial value of the aggregation counter object.
731
     * @param MongoCode|string $reduce A function that aggregates (reduces) the objects iterated.
732
     * @param array $condition An condition that must be true for a row to be considered.
733
     * @return array
734
     */
735
    public function group($keys, array $initial, $reduce, array $condition = [])
736
    {
737
        if (is_string($reduce)) {
738
            $reduce = new MongoCode($reduce);
739
        }
740
741
        $command = [
742
            'group' => [
743
                'ns' => $this->name,
744
                '$reduce' => (string)$reduce,
745
                'initial' => $initial,
746
                'cond' => $condition,
747
            ],
748
        ];
749
750
        if ($keys instanceof MongoCode) {
751
            $command['group']['$keyf'] = (string)$keys;
752
        } else {
753
            $command['group']['key'] = $keys;
754
        }
755
        if (array_key_exists('condition', $condition)) {
756
            $command['group']['cond'] = $condition['condition'];
757
        }
758
        if (array_key_exists('finalize', $condition)) {
759
            if ($condition['finalize'] instanceof MongoCode) {
760
                $condition['finalize'] = (string)$condition['finalize'];
761
            }
762
            $command['group']['finalize'] = $condition['finalize'];
763
        }
764
765
        return $this->db->command($command);
766
    }
767
768
    /**
769
     * Returns an array of cursors to iterator over a full collection in parallel
770
     *
771
     * @link http://www.php.net/manual/en/mongocollection.parallelcollectionscan.php
772
     * @param int $num_cursors The number of cursors to request from the server. Please note, that the server can return less cursors than you requested.
773
     * @return MongoCommandCursor[]
774
     */
775
    public function parallelCollectionScan($num_cursors)
0 ignored issues
show
Unused Code introduced by
The parameter $num_cursors 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...
776
    {
777
        $this->notImplemented();
778
    }
779
780
    protected function notImplemented()
781
    {
782
        throw new \Exception('Not implemented');
783
    }
784
785
    /**
786
     * @return \MongoDB\Collection
787
     */
788 View Code Duplication
    private function createCollectionObject()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
789
    {
790
        $options = [
791
            'readPreference' => $this->readPreference,
792
            'writeConcern' => $this->writeConcern,
793
        ];
794
795
        if ($this->collection === null) {
796
            $this->collection = $this->db->getDb()->selectCollection($this->name, $options);
797
        } else {
798
            $this->collection = $this->collection->withOptions($options);
799
        }
800
    }
801
802
    /**
803
     * Converts legacy write concern options to a WriteConcern object
804
     *
805
     * @param array $options
806
     * @return array
807
     */
808
    private function convertWriteConcernOptions(array $options)
809
    {
810
        if (isset($options['safe'])) {
811
            $options['w'] = ($options['safe']) ? 1 : 0;
812
        }
813
814
        if (isset($options['wtimeout']) && !isset($options['wTimeoutMS'])) {
815
            $options['wTimeoutMS'] = $options['wtimeout'];
816
        }
817
818
        if (isset($options['w']) || !isset($options['wTimeoutMS'])) {
819
            $collectionWriteConcern = $this->getWriteConcern();
820
            $writeConcern = $this->createWriteConcernFromParameters(
821
                isset($options['w']) ? $options['w'] : $collectionWriteConcern['w'],
822
                isset($options['wTimeoutMS']) ? $options['wTimeoutMS'] : $collectionWriteConcern['wtimeout']
823
            );
824
825
            $options['writeConcern'] = $writeConcern;
826
        }
827
828
        unset($options['safe']);
829
        unset($options['w']);
830
        unset($options['wTimeout']);
831
        unset($options['wTimeoutMS']);
832
833
        return $options;
834
    }
835
836
    private function checkCollectionName($name)
837
    {
838
        if (empty($name)) {
839
            throw new Exception('Collection name cannot be empty');
840
        } elseif (strpos($name, chr(0)) !== false) {
841
            throw new Exception('Collection name cannot contain null bytes');
842
        }
843
    }
844
}
845
846