Completed
Push — master ( a83c37...ecb281 )
by Andreas
03:01
created

MongoCollection::getCollection()   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
19
/**
20
 * Represents a database collection.
21
 * @link http://www.php.net/manual/en/class.mongocollection.php
22
 */
23
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...
24
{
25
    use Helper\ReadPreference;
26
    use Helper\SlaveOkay;
27
    use Helper\WriteConcern;
28
29
    const ASCENDING = 1;
30
    const DESCENDING = -1;
31
32
    /**
33
     * @var MongoDB
34
     */
35
    public $db = NULL;
36
37
    /**
38
     * @var string
39
     */
40
    protected $name;
41
42
    /**
43
     * @var \MongoDB\Collection
44
     */
45
    protected $collection;
46
47
    /**
48
     * Creates a new collection
49
     *
50
     * @link http://www.php.net/manual/en/mongocollection.construct.php
51
     * @param MongoDB $db Parent database.
52
     * @param string $name Name for this collection.
53
     * @throws Exception
54
     * @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...
55
     */
56
    public function __construct(MongoDB $db, $name)
57
    {
58
        $this->db = $db;
59
        $this->name = $name;
60
61
        $this->setReadPreferenceFromArray($db->getReadPreference());
62
        $this->setWriteConcernFromArray($db->getWriteConcern());
63
64
        $this->createCollectionObject();
65
    }
66
67
    /**
68
     * Gets the underlying collection for this object
69
     *
70
     * @internal This part is not of the ext-mongo API and should not be used
71
     * @return \MongoDB\Collection
72
     */
73
    public function getCollection()
74
    {
75
        return $this->collection;
76
    }
77
78
    /**
79
     * String representation of this collection
80
     *
81
     * @link http://www.php.net/manual/en/mongocollection.--tostring.php
82
     * @return string Returns the full name of this collection.
83
     */
84
    public function __toString()
85
    {
86
        return (string) $this->db . '.' . $this->name;
87
    }
88
89
    /**
90
     * Gets a collection
91
     *
92
     * @link http://www.php.net/manual/en/mongocollection.get.php
93
     * @param string $name The next string in the collection name.
94
     * @return MongoCollection
95
     */
96
    public function __get($name)
97
    {
98
        // Handle w and wtimeout properties that replicate data stored in $readPreference
99
        if ($name === 'w' || $name === 'wtimeout') {
100
            return $this->getWriteConcern()[$name];
101
        }
102
103
        return $this->db->selectCollection($this->name . '.' . $name);
104
    }
105
106
    /**
107
     * @param string $name
108
     * @param mixed $value
109
     */
110 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...
111
    {
112
        if ($name === 'w' || $name === 'wtimeout') {
113
            $this->setWriteConcernFromArray([$name => $value] + $this->getWriteConcern());
114
            $this->createCollectionObject();
115
        }
116
    }
117
118
    /**
119
     * Perform an aggregation using the aggregation framework
120
     *
121
     * @link http://www.php.net/manual/en/mongocollection.aggregate.php
122
     * @param array $pipeline
123
     * @param array $op
124
     * @return array
125
     */
126
    public function aggregate(array $pipeline, array $op = [])
127
    {
128
        if (! TypeConverter::isNumericArray($pipeline)) {
129
            $pipeline = [];
130
            $options = [];
131
132
            $i = 0;
133
            foreach (func_get_args() as $operator) {
134
                $i++;
135
                if (! is_array($operator)) {
136
                    trigger_error("Argument $i is not an array", E_WARNING);
137
                    return;
138
                }
139
140
                $pipeline[] = $operator;
141
            }
142
        } else {
143
            $options = $op;
144
        }
145
146
        $command = [
147
            'aggregate' => $this->name,
148
            'pipeline' => $pipeline
149
        ];
150
151
        $command += $options;
152
153
        return $this->db->command($command);
154
    }
155
156
    /**
157
     * Execute an aggregation pipeline command and retrieve results through a cursor
158
     *
159
     * @link http://php.net/manual/en/mongocollection.aggregatecursor.php
160
     * @param array $pipeline
161
     * @param array $options
162
     * @return MongoCommandCursor
163
     */
164
    public function aggregateCursor(array $pipeline, array $options = [])
165
    {
166
        // Build command manually, can't use mongo-php-library here
167
        $command = [
168
            'aggregate' => $this->name,
169
            'pipeline' => $pipeline
170
        ];
171
172
        // Convert cursor option
173
        if (! isset($options['cursor'])) {
174
            $options['cursor'] = true;
175
        }
176
177
        $command += $options;
178
179
        $cursor = new MongoCommandCursor($this->db->getConnection(), (string) $this, $command);
180
        $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...
181
182
        return $cursor;
183
    }
184
185
    /**
186
     * Returns this collection's name
187
     *
188
     * @link http://www.php.net/manual/en/mongocollection.getname.php
189
     * @return string
190
     */
191
    public function getName()
192
    {
193
        return $this->name;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199
    public function setReadPreference($readPreference, $tags = null)
200
    {
201
        $result = $this->setReadPreferenceFromParameters($readPreference, $tags);
202
        $this->createCollectionObject();
203
204
        return $result;
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210
    public function setWriteConcern($wstring, $wtimeout = 0)
211
    {
212
        $result = $this->setWriteConcernFromParameters($wstring, $wtimeout);
213
        $this->createCollectionObject();
214
215
        return $result;
216
    }
217
218
    /**
219
     * Drops this collection
220
     *
221
     * @link http://www.php.net/manual/en/mongocollection.drop.php
222
     * @return array Returns the database response.
223
     */
224
    public function drop()
225
    {
226
        return TypeConverter::toLegacy($this->collection->drop());
227
    }
228
229
    /**
230
     * Validates this collection
231
     *
232
     * @link http://www.php.net/manual/en/mongocollection.validate.php
233
     * @param bool $scan_data Only validate indices, not the base collection.
234
     * @return array Returns the database's evaluation of this object.
235
     */
236
    public function validate($scan_data = FALSE)
237
    {
238
        $command = [
239
            'validate' => $this->name,
240
            'full'     => $scan_data,
241
        ];
242
243
        return $this->db->command($command);
244
    }
245
246
    /**
247
     * Inserts an array into the collection
248
     *
249
     * @link http://www.php.net/manual/en/mongocollection.insert.php
250
     * @param array|object $a
251
     * @param array $options
252
     * @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.
253
     * @throws MongoCursorException if the "w" option is set and the write fails.
254
     * @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.
255
     * @return bool|array Returns an array containing the status of the insertion if the "w" option is set.
256
     */
257
    public function insert(&$a, array $options = [])
258
    {
259
        if (! $this->ensureDocumentHasMongoId($a)) {
260
            trigger_error(sprintf('%s expects parameter %d to be an array or object, %s given', __METHOD__, 1, gettype($a)), E_WARNING);
261
            return;
262
        }
263
264
        $result = $this->collection->insertOne(
265
            TypeConverter::fromLegacy($a),
266
            $this->convertWriteConcernOptions($options)
267
        );
268
269
        if (! $result->isAcknowledged()) {
270
            return true;
271
        }
272
273
        return [
274
            'ok' => 1.0,
275
            'n' => 0,
276
            'err' => null,
277
            'errmsg' => null,
278
        ];
279
    }
280
281
    /**
282
     * Inserts multiple documents into this collection
283
     *
284
     * @link http://www.php.net/manual/en/mongocollection.batchinsert.php
285
     * @param array $a An array of arrays.
286
     * @param array $options Options for the inserts.
287
     * @throws MongoCursorException
288
     * @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.
289
     */
290
    public function batchInsert(array &$a, array $options = [])
291
    {
292
        foreach ($a as $key => $item) {
293
            $this->ensureDocumentHasMongoId($a[$key]);
294
        }
295
296
        $result = $this->collection->insertMany(
297
            TypeConverter::fromLegacy(array_values($a)),
298
            $this->convertWriteConcernOptions($options)
299
        );
300
301
        if (! $result->isAcknowledged()) {
302
            return true;
303
        }
304
305
        return [
306
            'connectionId' => 0,
307
            'n' => 0,
308
            'syncMillis' => 0,
309
            'writtenTo' => null,
310
            'err' => null,
311
            'errmsg' => null,
312
        ];
313
    }
314
315
    /**
316
     * Update records based on a given criteria
317
     *
318
     * @link http://www.php.net/manual/en/mongocollection.update.php
319
     * @param array $criteria Description of the objects to update.
320
     * @param array $newobj The object with which to update the matching records.
321
     * @param array $options
322
     * @throws MongoCursorException
323
     * @return boolean
324
     */
325
    public function update(array $criteria , array $newobj, array $options = [])
326
    {
327
        $multiple = isset($options['multiple']) ? $options['multiple'] : false;
328
        $method = $multiple ? 'updateMany' : 'updateOne';
329
        unset($options['multiple']);
330
331
        /** @var \MongoDB\UpdateResult $result */
332
        $result = $this->collection->$method(
333
            TypeConverter::fromLegacy($criteria),
334
            TypeConverter::fromLegacy($newobj),
335
            $this->convertWriteConcernOptions($options)
336
        );
337
338
        if (! $result->isAcknowledged()) {
339
            return true;
340
        }
341
342
        return [
343
            'ok' => 1.0,
344
            'nModified' => $result->getModifiedCount(),
345
            'n' => $result->getMatchedCount(),
346
            'err' => null,
347
            'errmsg' => null,
348
            'updatedExisting' => $result->getUpsertedCount() == 0,
349
        ];
350
    }
351
352
    /**
353
     * Remove records from this collection
354
     *
355
     * @link http://www.php.net/manual/en/mongocollection.remove.php
356
     * @param array $criteria Query criteria for the documents to delete.
357
     * @param array $options An array of options for the remove operation.
358
     * @throws MongoCursorException
359
     * @throws MongoCursorTimeoutException
360
     * @return bool|array Returns an array containing the status of the removal
361
     * if the "w" option is set. Otherwise, returns TRUE.
362
     */
363
    public function remove(array $criteria = [], array $options = [])
364
    {
365
        $multiple = isset($options['justOne']) ? !$options['justOne'] : true;
366
        $method = $multiple ? 'deleteMany' : 'deleteOne';
367
368
        /** @var \MongoDB\DeleteResult $result */
369
        $result = $this->collection->$method(
370
            TypeConverter::fromLegacy($criteria),
371
            $this->convertWriteConcernOptions($options)
372
        );
373
374
        if (! $result->isAcknowledged()) {
375
            return true;
376
        }
377
378
        return [
379
            'ok' => 1.0,
380
            'n' => $result->getDeletedCount(),
381
            'err' => null,
382
            'errmsg' => null
383
        ];
384
    }
385
386
    /**
387
     * Querys this collection
388
     *
389
     * @link http://www.php.net/manual/en/mongocollection.find.php
390
     * @param array $query The fields for which to search.
391
     * @param array $fields Fields of the results to return.
392
     * @return MongoCursor
393
     */
394 View Code Duplication
    public function find(array $query = [], array $fields = [])
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...
395
    {
396
        $cursor = new MongoCursor($this->db->getConnection(), (string) $this, $query, $fields);
397
        $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...
398
399
        return $cursor;
400
    }
401
402
    /**
403
     * Retrieve a list of distinct values for the given key across a collection
404
     *
405
     * @link http://www.php.net/manual/ru/mongocollection.distinct.php
406
     * @param string $key The key to use.
407
     * @param array $query An optional query parameters
408
     * @return array|bool Returns an array of distinct values, or FALSE on failure
409
     */
410
    public function distinct($key, array $query = [])
411
    {
412
        return array_map([TypeConverter::class, 'toLegacy'], $this->collection->distinct($key, $query));
413
    }
414
415
    /**
416
     * Update a document and return it
417
     *
418
     * @link http://www.php.net/manual/ru/mongocollection.findandmodify.php
419
     * @param array $query The query criteria to search for.
420
     * @param array $update The update criteria.
421
     * @param array $fields Optionally only return these fields.
422
     * @param array $options An array of options to apply, such as remove the match document from the DB and return it.
423
     * @return array Returns the original document, or the modified document when new is set.
424
     */
425
    public function findAndModify(array $query, array $update = null, array $fields = null, array $options = [])
426
    {
427
        $query = TypeConverter::fromLegacy($query);
428
429
        if (isset($options['remove'])) {
430
            unset($options['remove']);
431
            $document = $this->collection->findOneAndDelete($query, $options);
432
        } else {
433
            $update = is_array($update) ? TypeConverter::fromLegacy($update) : [];
434
435
            if (isset($options['new'])) {
436
                $options['returnDocument'] = \MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER;
437
                unset($options['new']);
438
            }
439
440
            $options['projection'] = is_array($fields) ? TypeConverter::fromLegacy($fields) : [];
441
442
            $document = $this->collection->findOneAndUpdate($query, $update, $options);
443
        }
444
445
        if ($document) {
446
            $document = TypeConverter::toLegacy($document);
447
        }
448
449
        return $document;
450
    }
451
452
    /**
453
     * Querys this collection, returning a single element
454
     *
455
     * @link http://www.php.net/manual/en/mongocollection.findone.php
456
     * @param array $query The fields for which to search.
457
     * @param array $fields Fields of the results to return.
458
     * @param array $options
459
     * @return array|null
460
     */
461
    public function findOne(array $query = [], array $fields = [], array $options = [])
462
    {
463
        $options = ['projection' => $fields] + $options;
464
465
        $document = $this->collection->findOne(TypeConverter::fromLegacy($query), $options);
466
        if ($document !== null) {
467
            $document = TypeConverter::toLegacy($document);
468
        }
469
470
        return $document;
471
    }
472
473
    /**
474
     * Creates an index on the given field(s), or does nothing if the index already exists
475
     *
476
     * @link http://www.php.net/manual/en/mongocollection.createindex.php
477
     * @param array $keys Field or fields to use as index.
478
     * @param array $options [optional] This parameter is an associative array of the form array("optionname" => <boolean>, ...).
479
     * @return array Returns the database response.
480
     *
481
     * @todo This method does not yet return the correct result
482
     */
483
    public function createIndex(array $keys, array $options = [])
484
    {
485
        // Note: this is what the result array should look like
486
//        $expected = [
487
//            'createdCollectionAutomatically' => true,
488
//            'numIndexesBefore' => 1,
489
//            'numIndexesAfter' => 2,
490
//            'ok' => 1.0
491
//        ];
492
493
        return $this->collection->createIndex($keys, $options);
494
    }
495
496
    /**
497
     * Creates an index on the given field(s), or does nothing if the index already exists
498
     *
499
     * @link http://www.php.net/manual/en/mongocollection.ensureindex.php
500
     * @param array $keys Field or fields to use as index.
501
     * @param array $options [optional] This parameter is an associative array of the form array("optionname" => <boolean>, ...).
502
     * @return boolean always true
503
     * @deprecated Use MongoCollection::createIndex() instead.
504
     */
505
    public function ensureIndex(array $keys, array $options = [])
506
    {
507
        $this->createIndex($keys, $options);
508
509
        return true;
510
    }
511
512
    /**
513
     * Deletes an index from this collection
514
     *
515
     * @link http://www.php.net/manual/en/mongocollection.deleteindex.php
516
     * @param string|array $keys Field or fields from which to delete the index.
517
     * @return array Returns the database response.
518
     */
519
    public function deleteIndex($keys)
520
    {
521
        if (is_string($keys)) {
522
            $indexName = $keys;
523
        } elseif (is_array($keys)) {
524
            $indexName = \MongoDB\generate_index_name($keys);
525
        } else {
526
            throw new \InvalidArgumentException();
527
        }
528
529
        return TypeConverter::toLegacy($this->collection->dropIndex($indexName));
530
    }
531
532
    /**
533
     * Delete all indexes for this collection
534
     *
535
     * @link http://www.php.net/manual/en/mongocollection.deleteindexes.php
536
     * @return array Returns the database response.
537
     */
538
    public function deleteIndexes()
539
    {
540
        return TypeConverter::toLegacy($this->collection->dropIndexes());
541
    }
542
543
    /**
544
     * Returns an array of index names for this collection
545
     *
546
     * @link http://www.php.net/manual/en/mongocollection.getindexinfo.php
547
     * @return array Returns a list of index names.
548
     */
549
    public function getIndexInfo()
550
    {
551
        $convertIndex = function(\MongoDB\Model\IndexInfo $indexInfo) {
552
            return [
553
                'v' => $indexInfo->getVersion(),
554
                'key' => $indexInfo->getKey(),
555
                'name' => $indexInfo->getName(),
556
                'ns' => $indexInfo->getNamespace(),
557
            ];
558
        };
559
560
        return array_map($convertIndex, iterator_to_array($this->collection->listIndexes()));
561
    }
562
563
    /**
564
     * Counts the number of documents in this collection
565
     *
566
     * @link http://www.php.net/manual/en/mongocollection.count.php
567
     * @param array|stdClass $query
568
     * @param array $options
569
     * @return int Returns the number of documents matching the query.
570
     */
571
    public function count($query = [], array $options = [])
572
    {
573
        return $this->collection->count(TypeConverter::fromLegacy($query), $options);
574
    }
575
576
    /**
577
     * Saves an object to this collection
578
     *
579
     * @link http://www.php.net/manual/en/mongocollection.save.php
580
     * @param array|object $a Array to save. If an object is used, it may not have protected or private properties.
581
     * @param array $options Options for the save.
582
     * @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.
583
     * @throws MongoCursorException if the "w" option is set and the write fails.
584
     * @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.
585
     * @return array|boolean If w was set, returns an array containing the status of the save.
586
     * Otherwise, returns a boolean representing if the array was not empty (an empty array will not be inserted).
587
     */
588
    public function save(&$a, array $options = [])
589
    {
590
        $id = $this->ensureDocumentHasMongoId($a);
591
592
        $document = (array) $a;
593
        unset($document['_id']);
594
595
        $options['upsert'] = true;
596
597
        return $this->update(['_id' => $id], ['$set' => $document], $options);
598
    }
599
600
    /**
601
     * Creates a database reference
602
     *
603
     * @link http://www.php.net/manual/en/mongocollection.createdbref.php
604
     * @param array|object $document_or_id Object to which to create a reference.
605
     * @return array Returns a database reference array.
606
     */
607 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...
608
    {
609
        if ($document_or_id instanceof \MongoId) {
610
            $id = $document_or_id;
611
        } elseif (is_object($document_or_id)) {
612
            if (! isset($document_or_id->_id)) {
613
                return null;
614
            }
615
616
            $id = $document_or_id->_id;
617
        } elseif (is_array($document_or_id)) {
618
            if (! isset($document_or_id['_id'])) {
619
                return null;
620
            }
621
622
            $id = $document_or_id['_id'];
623
        } else {
624
            $id = $document_or_id;
625
        }
626
627
        return MongoDBRef::create($this->name, $id);
628
    }
629
630
    /**
631
     * Fetches the document pointed to by a database reference
632
     *
633
     * @link http://www.php.net/manual/en/mongocollection.getdbref.php
634
     * @param array $ref A database reference.
635
     * @return array Returns the database document pointed to by the reference.
636
     */
637
    public function getDBRef(array $ref)
638
    {
639
        return $this->db->getDBRef($ref);
640
    }
641
642
    /**
643
     * Performs an operation similar to SQL's GROUP BY command
644
     *
645
     * @link http://www.php.net/manual/en/mongocollection.group.php
646
     * @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.
647
     * @param array $initial Initial value of the aggregation counter object.
648
     * @param MongoCode|string $reduce A function that aggregates (reduces) the objects iterated.
649
     * @param array $condition An condition that must be true for a row to be considered.
650
     * @return array
651
     */
652
    public function group($keys, array $initial, $reduce, array $condition = [])
653
    {
654
        if (is_string($reduce)) {
655
            $reduce = new MongoCode($reduce);
656
        }
657
658
        $command = [
659
            'group' => [
660
                'ns' => $this->name,
661
                '$reduce' => (string)$reduce,
662
                'initial' => $initial,
663
                'cond' => $condition,
664
            ],
665
        ];
666
667
        if ($keys instanceof MongoCode) {
668
            $command['group']['$keyf'] = (string)$keys;
669
        } else {
670
            $command['group']['key'] = $keys;
671
        }
672
        if (array_key_exists('condition', $condition)) {
673
            $command['group']['cond'] = $condition['condition'];
674
        }
675
        if (array_key_exists('finalize', $condition)) {
676
            if ($condition['finalize'] instanceof MongoCode) {
677
                $condition['finalize'] = (string)$condition['finalize'];
678
            }
679
            $command['group']['finalize'] = $condition['finalize'];
680
        }
681
682
        return $this->db->command($command);
683
    }
684
685
    /**
686
     * Returns an array of cursors to iterator over a full collection in parallel
687
     *
688
     * @link http://www.php.net/manual/en/mongocollection.parallelcollectionscan.php
689
     * @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.
690
     * @return MongoCommandCursor[]
691
     */
692
    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...
693
    {
694
        $this->notImplemented();
695
    }
696
697
    protected function notImplemented()
698
    {
699
        throw new \Exception('Not implemented');
700
    }
701
702
    /**
703
     * @return \MongoDB\Collection
704
     */
705 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...
706
    {
707
        $options = [
708
            'readPreference' => $this->readPreference,
709
            'writeConcern' => $this->writeConcern,
710
        ];
711
712
        if ($this->collection === null) {
713
            $this->collection = $this->db->getDb()->selectCollection($this->name, $options);
714
        } else {
715
            $this->collection = $this->collection->withOptions($options);
716
        }
717
    }
718
719
    /**
720
     * Converts legacy write concern options to a WriteConcern object
721
     *
722
     * @param array $options
723
     * @return array
724
     */
725
    private function convertWriteConcernOptions(array $options)
726
    {
727
        if (isset($options['safe'])) {
728
            $options['w'] = ($options['safe']) ? 1 : 0;
729
        }
730
731
        if (isset($options['wtimeout']) && !isset($options['wTimeoutMS'])) {
732
            $options['wTimeoutMS'] = $options['wtimeout'];
733
        }
734
735
        if (isset($options['w']) || !isset($options['wTimeoutMS'])) {
736
            $collectionWriteConcern = $this->getWriteConcern();
737
            $writeConcern = $this->createWriteConcernFromParameters(
738
                isset($options['w']) ? $options['w'] : $collectionWriteConcern['w'],
739
                isset($options['wTimeoutMS']) ? $options['wTimeoutMS'] : $collectionWriteConcern['wtimeout']
740
            );
741
742
            $options['writeConcern'] = $writeConcern;
743
        }
744
745
        unset($options['safe']);
746
        unset($options['w']);
747
        unset($options['wTimeout']);
748
        unset($options['wTimeoutMS']);
749
750
        return $options;
751
    }
752
753
    /**
754
     * @param array|object $document
755
     * @return MongoId
756
     */
757
    private function ensureDocumentHasMongoId(&$document)
758
    {
759
        if (is_array($document)) {
760
            if (! isset($document['_id'])) {
761
                $document['_id'] = new \MongoId();
762
            }
763
764
            return $document['_id'];
765
        } elseif (is_object($document)) {
766
            if (! isset($document->_id)) {
767
                $document->_id = new \MongoId();
768
            }
769
770
            return $document->_id;
771
        }
772
773
        return null;
774
    }
775
}
776
777