Completed
Pull Request — master (#12)
by
unknown
02:42
created

MongoCollection::ensureIndex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 5
rs 9.4286
cc 1
eloc 3
nc 1
nop 2
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 MongoDB\Driver\ReadPreference;
19
use MongoDB\Driver\WriteConcern;
20
21
/**
22
 * Represents a database collection.
23
 * @link http://www.php.net/manual/en/class.mongocollection.php
24
 */
25
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...
26
{
27
    use Helper\ReadPreference;
28
    use Helper\WriteConcern;
29
    use Helper\Slave;
30
31
    const ASCENDING = 1;
32
    const DESCENDING = -1;
33
34
    /**
35
     * @var MongoDB
36
     */
37
    public $db = NULL;
38
39
    /**
40
     * @var string
41
     */
42
    protected $name;
43
44
    /**
45
     * @var \MongoDB\Collection
46
     */
47
    protected $collection;
48
49
    /**
50
     * Creates a new collection
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->db = $db;
60
        $this->name = $name;
61
62
        $this->setReadPreferenceFromArray($db->getReadPreference());
63
        $this->setWriteConcernFromArray($db->getWriteConcern());
64
65
        $this->createCollectionObject();
66
    }
67
68
    /**
69
     * Gets the underlying collection for this object
70
     *
71
     * @internal This part is not of the ext-mongo API and should not be used
72
     * @return \MongoDB\Collection
73
     */
74
    public function getCollection()
75
    {
76
        return $this->collection;
77
    }
78
79
    /**
80
     * String representation of this collection
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
     * @link http://www.php.net/manual/en/mongocollection.get.php
92
     * @param string $name The next string in the collection name.
93
     * @return MongoCollection
94
     */
95
    public function __get($name)
96
    {
97
        // Handle w and wtimeout properties that replicate data stored in $readPreference
98
        if ($name === 'w' || $name === 'wtimeout') {
99
            return $this->getWriteConcern()[$name];
100
        }
101
102
        return $this->db->selectCollection($this->name . '.' . $name);
103
    }
104
105
    /**
106
     * @param string $name
107
     * @param mixed $value
108
     */
109 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...
110
    {
111
        if ($name === 'w' || $name === 'wtimeout') {
112
            $this->setWriteConcernFromArray([$name => $value] + $this->getWriteConcern());
113
            $this->createCollectionObject();
114
        }
115
    }
116
117
    /**
118
     * @link http://www.php.net/manual/en/mongocollection.aggregate.php
119
     * @param array $pipeline
120
     * @param array $op
121
     * @return array
122
     */
123
    public function aggregate(array $pipeline, array $op = [])
124
    {
125
        if (! TypeConverter::isNumericArray($pipeline)) {
126
            $pipeline = [];
127
            $options = [];
128
129
            $i = 0;
130
            foreach (func_get_args() as $operator) {
131
                $i++;
132
                if (! is_array($operator)) {
133
                    trigger_error("Argument $i is not an array", E_WARNING);
134
                    return;
135
                }
136
137
                $pipeline[] = $operator;
138
            }
139
        } else {
140
            $options = $op;
141
        }
142
143
        $command = [
144
            'aggregate' => $this->name,
145
            'pipeline' => $pipeline
146
        ];
147
148
        $command += $options;
149
150
        return $this->db->command($command, [], $hash);
151
    }
152
153
    /**
154
     * @link http://php.net/manual/en/mongocollection.aggregatecursor.php
155
     * @param array $pipeline
156
     * @param array $options
157
     * @return MongoCommandCursor
158
     */
159
    public function aggregateCursor(array $pipeline, array $options = [])
160
    {
161
        // Build command manually, can't use mongo-php-library here
162
        $command = [
163
            'aggregate' => $this->name,
164
            'pipeline' => $pipeline
165
        ];
166
167
        // Convert cursor option
168
        if (! isset($options['cursor']) || $options['cursor'] === true || $options['cursor'] === []) {
169
            // Cursor option needs to be an object convert bools and empty arrays since those won't be handled by TypeConverter
170
            $options['cursor'] = new \stdClass;
171
        }
172
173
        $command += $options;
174
175
        $cursor = new MongoCommandCursor($this->db->getConnection(), (string)$this, $command);
176
        $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...
177
178
        return $cursor;
179
    }
180
181
    /**
182
     * Returns this collection's name
183
     * @link http://www.php.net/manual/en/mongocollection.getname.php
184
     * @return string
185
     */
186
    public function getName()
187
    {
188
        return $this->name;
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194
    public function setSlaveOkay($ok = true)
195
    {
196
        $result = $this->setSlaveOkayFromParameter($ok);
197
        $this->createCollectionObject();
198
199
        return $result;
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
     * @link http://www.php.net/manual/en/mongocollection.drop.php
227
     * @return array Returns the database response.
228
     */
229
    public function drop()
230
    {
231
        return $this->collection->drop();
232
    }
233
234
    /**
235
     * Validates this collection
236
     * @link http://www.php.net/manual/en/mongocollection.validate.php
237
     * @param bool $scan_data Only validate indices, not the base collection.
238
     * @return array Returns the database's evaluation of this object.
239
     */
240
    public function validate($scan_data = FALSE)
241
    {
242
        $command = [
243
            'validate' => $this->name,
244
            'full'     => $scan_data,
245
        ];
246
        $result = $this->db->command($command, [], $hash);
247
        if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
248
            return $result;
249
        }
250
251
        return false;
252
    }
253
254
    /**
255
     * Inserts an array into the collection
256
     * @link http://www.php.net/manual/en/mongocollection.insert.php
257
     * @param array|object $a
258
     * @param array $options
259
     * @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.
260
     * @throws MongoCursorException if the "w" option is set and the write fails.
261
     * @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.
262
     * @return bool|array Returns an array containing the status of the insertion if the "w" option is set.
263
     */
264
    public function insert($a, array $options = array())
265
    {
266
        return $this->collection->insertOne(TypeConverter::convertLegacyArrayToObject($a), $options);
267
    }
268
269
    /**
270
     * Inserts multiple documents into this collection
271
     * @link http://www.php.net/manual/en/mongocollection.batchinsert.php
272
     * @param array $a An array of arrays.
273
     * @param array $options Options for the inserts.
274
     * @throws MongoCursorException
275
     * @return mixed f "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.
276
     */
277
    public function batchInsert(array $a, array $options = array())
278
    {
279
        return $this->collection->insertMany($a, $options);
280
    }
281
282
    /**
283
     * Update records based on a given criteria
284
     * @link http://www.php.net/manual/en/mongocollection.update.php
285
     * @param array $criteria Description of the objects to update.
286
     * @param array $newobj The object with which to update the matching records.
287
     * @param array $options This parameter is an associative array of the form
288
     *        array("optionname" => boolean, ...).
289
     *
290
     *        Currently supported options are:
291
     *          "upsert": If no document matches $$criteria, a new document will be created from $$criteria and $$new_object (see upsert example).
292
     *
293
     *          "multiple": All documents matching $criteria will be updated. MongoCollection::update has exactly the opposite behavior of MongoCollection::remove- it updates one document by
294
     *          default, not all matching documents. It is recommended that you always specify whether you want to update multiple documents or a single document, as the
295
     *          database may change its default behavior at some point in the future.
296
     *
297
     *          "safe" Can be a boolean or integer, defaults to false. If false, the program continues executing without waiting for a database response. If true, the program will wait for
298
     *          the database response and throw a MongoCursorException if the update did not succeed. If you are using replication and the master has changed, using "safe" will make the driver
299
     *          disconnect from the master, throw and exception, and attempt to find a new master on the next operation (your application must decide whether or not to retry the operation on the new master).
300
     *          If you do not use "safe" with a replica set and the master changes, there will be no way for the driver to know about the change so it will continuously and silently fail to write.
301
     *          If safe is an integer, will replicate the update to that many machines before returning success (or throw an exception if the replication times out, see wtimeout).
302
     *          This overrides the w variable set on the collection.
303
     *
304
     *         "fsync": Boolean, defaults to false. Forces the update to be synced to disk before returning success. If true, a safe update is implied and will override setting safe to false.
305
     *
306
     *         "timeout" Integer, defaults to MongoCursor::$timeout. If "safe" is set, this sets how long (in milliseconds) for the client to wait for a database response. If the database does
307
     *         not respond within the timeout period, a MongoCursorTimeoutException will be thrown
308
     * @throws MongoCursorException
309
     * @return boolean
310
     */
311
    public function update(array $criteria , array $newobj, array $options = array())
312
    {
313
        $multiple = ($options['multiple']) ? $options['multiple'] : false;
314
//        $multiple = $options['multiple'] ?? false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
315
        $method = $multiple ? 'updateMany' : 'updateOne';
316
317
        return $this->collection->$method($criteria, $newobj, $options);
318
    }
319
320
    /**
321
     * (PECL mongo &gt;= 0.9.0)<br/>
322
     * Remove records from this collection
323
     * @link http://www.php.net/manual/en/mongocollection.remove.php
324
     * @param array $criteria [optional] <p>Query criteria for the documents to delete.</p>
325
     * @param array $options [optional] <p>An array of options for the remove operation. Currently available options
326
     * include:
327
     * </p><ul>
328
     * <li><p><em>"w"</em></p><p>See {@link http://www.php.net/manual/en/mongo.writeconcerns.php Write Concerns}. The default value for <b>MongoClient</b> is <em>1</em>.</p></li>
329
     * <li>
330
     * <p>
331
     * <em>"justOne"</em>
332
     * </p>
333
     * <p>
334
     * Specify <strong><code>TRUE</code></strong> to limit deletion to just one document. If <strong><code>FALSE</code></strong> or
335
     * omitted, all documents matching the criteria will be deleted.
336
     * </p>
337
     * </li>
338
     * <li><p><em>"fsync"</em></p><p>Boolean, defaults to <b>FALSE</b>. If journaling is enabled, it works exactly like <em>"j"</em>. If journaling is not enabled, the write operation blocks until it is synced to database files on disk. If <strong><code>TRUE</code></strong>, an acknowledged insert is implied and this option will override setting <em>"w"</em> to <em>0</em>.</p><blockquote class="note"><p><strong class="note">Note</strong>: <span class="simpara">If journaling is enabled, users are strongly encouraged to use the <em>"j"</em> option instead of <em>"fsync"</em>. Do not use <em>"fsync"</em> and <em>"j"</em> simultaneously, as that will result in an error.</p></blockquote></li>
339
     * <li><p><em>"j"</em></p><p>Boolean, defaults to <b>FALSE</b>. Forces the write operation to block until it is synced to the journal on disk. If <strong><code>TRUE</code></strong>, an acknowledged write is implied and this option will override setting <em>"w"</em> to <em>0</em>.</p><blockquote class="note"><p><strong class="note">Note</strong>: <span class="simpara">If this option is used and journaling is disabled, MongoDB 2.6+ will raise an error and the write will fail; older server versions will simply ignore the option.</p></blockquote></li>
340
     * <li><p><em>"socketTimeoutMS"</em></p><p>This option specifies the time limit, in milliseconds, for socket communication. If the server does not respond within the timeout period, a <b>MongoCursorTimeoutException</b> will be thrown and there will be no way to determine if the server actually handled the write or not. A value of <em>-1</em> may be specified to block indefinitely. The default value for <b>MongoClient</b> is <em>30000</em> (30 seconds).</p></li>
341
     * <li><p><em>"w"</em></p><p>See {@link http://www.php.net/manual/en/mongo.writeconcerns.php Write Concerns }. The default value for <b>MongoClient</b> is <em>1</em>.</p></li>
342
     * <li><p><em>"wTimeoutMS"</em></p><p>This option specifies the time limit, in milliseconds, for {@link http://www.php.net/manual/en/mongo.writeconcerns.php write concern} acknowledgement. It is only applicable when <em>"w"</em> is greater than <em>1</em>, as the timeout pertains to replication. If the write concern is not satisfied within the time limit, a <a href="class.mongocursorexception.php" class="classname">MongoCursorException</a> will be thrown. A value of <em>0</em> may be specified to block indefinitely. The default value for {@link http://www.php.net/manual/en/class.mongoclient.php MongoClient} is <em>10000</em> (ten seconds).</p></li>
343
     * </ul>
344
     *
345
     * <p>
346
     * The following options are deprecated and should no longer be used:
347
     * </p><ul>
348
     * <li><p><em>"safe"</em></p><p>Deprecated. Please use the {@link http://www.php.net/manual/en/mongo.writeconcerns.php write concern} <em>"w"</em> option.</p></li>
349
     * <li><p><em>"timeout"</em></p><p>Deprecated alias for <em>"socketTimeoutMS"</em>.</p></li>
350
     * <li><p><b>"wtimeout"</b></p><p>Deprecated alias for <em>"wTimeoutMS"</em>.</p></p>
351
     * @throws MongoCursorException
352
     * @throws MongoCursorTimeoutException
353
     * @return bool|array <p>Returns an array containing the status of the removal if the
354
     * <em>"w"</em> option is set. Otherwise, returns <b>TRUE</b>.
355
     * </p>
356
     * <p>
357
     * Fields in the status array are described in the documentation for
358
     * <b>MongoCollection::insert()</b>.
359
     * </p>
360
     */
361
    public function remove(array $criteria = array(), array $options = array())
362
    {
363
        $multiple = isset($options['justOne']) ? !$options['justOne'] : false;
364
//        $multiple = !$options['justOne'] ?? false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
365
        $method = $multiple ? 'deleteMany' : 'deleteOne';
366
367
        return $this->collection->$method($criteria, $options);
368
    }
369
370
    /**
371
     * Querys this collection
372
     * @link http://www.php.net/manual/en/mongocollection.find.php
373
     * @param array $query The fields for which to search.
374
     * @param array $fields Fields of the results to return.
375
     * @return MongoCursor
376
     */
377
    public function find(array $query = array(), array $fields = array())
378
    {
379
        $cursor = new MongoCursor($this->db->getConnection(), (string)$this, $query, $fields);
380
        $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...
381
382
        return $cursor;
383
    }
384
385
    /**
386
     * Retrieve a list of distinct values for the given key across a collection
387
     * @link http://www.php.net/manual/ru/mongocollection.distinct.php
388
     * @param string $key The key to use.
389
     * @param array $query An optional query parameters
390
     * @return array|bool Returns an array of distinct values, or <b>FALSE</b> on failure
391
     */
392
    public function distinct($key, array $query = [])
393
    {
394
        return array_map([TypeConverter::class, 'convertToLegacyType'], $this->collection->distinct($key, $query));
395
    }
396
397
    /**
398
     * Update a document and return it
399
     * @link http://www.php.net/manual/ru/mongocollection.findandmodify.php
400
     * @param array $query The query criteria to search for.
401
     * @param array $update The update criteria.
402
     * @param array $fields Optionally only return these fields.
403
     * @param array $options An array of options to apply, such as remove the match document from the DB and return it.
404
     * @return array Returns the original document, or the modified document when new is set.
405
     */
406
    public function findAndModify(array $query, array $update = NULL, array $fields = NULL, array $options = [])
407
    {
408
        $query = TypeConverter::convertLegacyArrayToObject($query);
409
        if (isset($options['remove'])) {
410
            unset($options['remove']);
411
            $document = $this->collection->findOneAndDelete($query, $options);
412
        } else {
413
            if (is_array($update)) {
414
                $update = TypeConverter::convertLegacyArrayToObject($update);
415
            }
416
            if (is_array($fields)) {
417
                $fields = TypeConverter::convertLegacyArrayToObject($fields);
418
            }
419
            if (isset($options['new'])) {
420
                $options['returnDocument'] = \MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER;
421
                unset($options['new']);
422
            }
423
            if ($fields) {
424
                $options['projection'] = $fields;
425
            }
426
            $document = $this->collection->findOneAndUpdate($query, $update, $options);
0 ignored issues
show
Bug introduced by
It seems like $update defined by parameter $update on line 406 can also be of type null; however, MongoDB\Collection::findOneAndUpdate() does only seem to accept array|object, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
427
        }
428
        if ($document) {
429
            $document = TypeConverter::convertObjectToLegacyArray($document);
430
        }
431
        return $document;
432
    }
433
434
    /**
435
     * Querys this collection, returning a single element
436
     * @link http://www.php.net/manual/en/mongocollection.findone.php
437
     * @param array $query The fields for which to search.
438
     * @param array $fields Fields of the results to return.
439
     * @return array|null
440
     */
441
    public function findOne(array $query = array(), array $fields = array())
442
    {
443
        $document = $this->collection->findOne(TypeConverter::convertLegacyArrayToObject($query), ['projection' => $fields]);
444
        if ($document !== null) {
445
            $document = TypeConverter::convertObjectToLegacyArray($document);
446
        }
447
448
        return $document;
449
    }
450
451
    /**
452
     * Creates an index on the given field(s), or does nothing if the index already exists
453
     * @link http://www.php.net/manual/en/mongocollection.createindex.php
454
     * @param array $keys Field or fields to use as index.
455
     * @param array $options [optional] This parameter is an associative array of the form array("optionname" => <boolean>, ...).
456
     * @return array Returns the database response.
457
     */
458
    public function createIndex(array $keys, array $options = array())
459
    {
460
        return $this->collection->createIndex($keys, $options);
461
    }
462
463
    /**
464
     * @deprecated Use MongoCollection::createIndex() instead.
465
     * Creates an index on the given field(s), or does nothing if the index already exists
466
     * @link http://www.php.net/manual/en/mongocollection.ensureindex.php
467
     * @param array $keys Field or fields to use as index.
468
     * @param array $options [optional] This parameter is an associative array of the form array("optionname" => <boolean>, ...).
469
     * @return boolean always true
470
     */
471
    public function ensureIndex(array $keys, array $options = array())
472
    {
473
        $this->createIndex($keys, $options);
474
        return true;
475
    }
476
477
    /**
478
     * Deletes an index from this collection
479
     * @link http://www.php.net/manual/en/mongocollection.deleteindex.php
480
     * @param string|array $keys Field or fields from which to delete the index.
481
     * @return array Returns the database response.
482
     */
483
    public function deleteIndex($keys)
484
    {
485
        if (is_string($keys)) {
486
            $indexName = $keys;
487
        } elseif (is_array($keys)) {
488
            $indexName = self::toIndexString($keys);
489
        } else {
490
            throw new \InvalidArgumentException();
491
        }
492
        return $this->collection->dropIndex($indexName);
493
    }
494
495
    /**
496
     * Delete all indexes for this collection
497
     * @link http://www.php.net/manual/en/mongocollection.deleteindexes.php
498
     * @return array Returns the database response.
499
     */
500
    public function deleteIndexes()
501
    {
502
        return $this->collection->dropIndexes();
503
    }
504
505
    /**
506
     * Returns an array of index names for this collection
507
     * @link http://www.php.net/manual/en/mongocollection.getindexinfo.php
508
     * @return array Returns a list of index names.
509
     */
510
    public function getIndexInfo()
511
    {
512
        $convertIndex = function($indexInfo) {
513
            return $indexInfo->__debugInfo();
514
        };
515
        return array_map($convertIndex, iterator_to_array($this->collection->listIndexes()));
516
    }
517
518
    /**
519
     * Counts the number of documents in this collection
520
     * @link http://www.php.net/manual/en/mongocollection.count.php
521
     * @param array|stdClass $query
522
     * @return int Returns the number of documents matching the query.
523
     */
524
    public function count($query = array())
525
    {
526
        return $this->collection->count($query);
527
    }
528
529
    /**
530
     * Saves an object to this collection
531
     * @link http://www.php.net/manual/en/mongocollection.save.php
532
     * @param array|object $a Array to save. If an object is used, it may not have protected or private properties.
533
     * Note: If the parameter does not have an _id key or property, a new MongoId instance will be created and assigned to it.
534
     * See MongoCollection::insert() for additional information on this behavior.
535
     * @param array $options Options for the save.
536
     * <dl>
537
     * <dt>"w"
538
     * <dd>See WriteConcerns. The default value for MongoClient is 1.
539
     * <dt>"fsync"
540
     * <dd>Boolean, defaults to FALSE. Forces the insert to be synced to disk before returning success. If TRUE, an acknowledged insert is implied and will override setting w to 0.
541
     * <dt>"timeout"
542
     * <dd>Integer, defaults to MongoCursor::$timeout. If "safe" is set, this sets how long (in milliseconds) for the client to wait for a database response. If the database does not respond within the timeout period, a MongoCursorTimeoutException will be thrown.
543
     * <dt>"safe"
544
     * <dd>Deprecated. Please use the WriteConcern w option.
545
     * </dl>
546
     * @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.
547
     * @throws MongoCursorException if the "w" option is set and the write fails.
548
     * @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.
549
     * @return array|boolean If w was set, returns an array containing the status of the save.
550
     * Otherwise, returns a boolean representing if the array was not empty (an empty array will not be inserted).
551
     */
552
    public function save($a, array $options = array())
0 ignored issues
show
Unused Code introduced by
The parameter $options 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...
553
    {
554
        if (is_object($a)) {
555
            $a = (array)$a;
556
        }
557
        if ( ! array_key_exists('_id', $a)) {
558
            $id = new \MongoId();
559
        } else {
560
            $id = $a['_id'];
561
            unset($a['_id']);
562
        }
563
        $filter = ['_id' => $id];
564
        $filter = TypeConverter::convertLegacyArrayToObject($filter);
565
        $a = TypeConverter::convertLegacyArrayToObject($a);
566
        return $this->collection->updateOne($filter, ['$set' => $a], ['upsert' => true]);
567
    }
568
569
    /**
570
     * Creates a database reference
571
     * @link http://www.php.net/manual/en/mongocollection.createdbref.php
572
     * @param array $a Object to which to create a reference.
573
     * @return array Returns a database reference array.
574
     */
575
    public function createDBRef(array $a)
576
    {
577
        return \MongoDBRef::create($this->name, $a['_id']);
578
    }
579
580
    /**
581
     * Fetches the document pointed to by a database reference
582
     * @link http://www.php.net/manual/en/mongocollection.getdbref.php
583
     * @param array $ref A database reference.
584
     * @return array Returns the database document pointed to by the reference.
585
     */
586
    public function getDBRef(array $ref)
587
    {
588
        return \MongoDBRef::get($this->db, $ref);
589
    }
590
591
    /**
592
     * @param  mixed $keys
593
     * @static
594
     * @return string
595
     */
596
    protected static function toIndexString($keys)
597
    {
598
        $result = '';
599
        foreach ($keys as $name => $direction) {
600
            $result .= sprintf('%s_%d', $name, $direction);
601
        }
602
        return $result;
603
    }
604
605
    /**
606
     * Performs an operation similar to SQL's GROUP BY command
607
     * @link http://www.php.net/manual/en/mongocollection.group.php
608
     * @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.
609
     * @param array $initial Initial value of the aggregation counter object.
610
     * @param MongoCode $reduce A function that aggregates (reduces) the objects iterated.
611
     * @param array $condition An condition that must be true for a row to be considered.
612
     * @return array
613
     */
614
    public function group($keys, array $initial, $reduce, array $condition = [])
615
    {
616
        if (is_string($reduce)) {
617
            $reduce = new MongoCode($reduce);
618
        }
619
        if ( ! $reduce instanceof MongoCode) {
620
            throw new \InvalidArgumentExcption('reduce parameter should be a string or MongoCode instance.');
621
        }
622
        $command = [
623
            'group' => [
624
                'ns'      => $this->name,
625
                '$reduce' => (string)$reduce,
626
                'initial' => $initial,
627
                'cond'    => $condition,
628
            ],
629
        ];
630
631
        if ($keys instanceof MongoCode) {
632
            $command['group']['$keyf'] = (string)$keys;
633
        } else {
634
            $command['group']['key'] = $keys;
635
        }
636
        if (array_key_exists('condition', $condition)) {
637
            $command['group']['cond'] = $condition['condition'];
638
        }
639
        if (array_key_exists('finalize', $condition)) {
640
            if ($condition['finalize'] instanceof MongoCode) {
641
                $condition['finalize'] = (string)$condition['finalize'];
642
            }
643
            $command['group']['finalize'] = $condition['finalize'];
644
        }
645
646
        $result = $this->db->command($command, [], $hash);
647
        unset($result['waitedMS']);
648
        $result['ok'] = (int)$result['ok'];
649
        if (count($result['retval'])) {
650
            $result['retval'] = current($result['retval']);
651
        }
652
        return $result;
653
    }
654
655
    // public function parallelCollectionScan(int $num_cursors)
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
656
    // {
657
    //     $command = [
658
    //         'parallelCollectionScan' => $this->name,
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
659
    //         'numCursors'             => $num_cursors,
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
660
    //     ];
661
    //     $result = $this->db->command($command, [], $hash);
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
662
    //     if ($result) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
663
    //         return $result;
664
    //     }
665
    //     return false;
666
    // }
667
668
    protected function notImplemented()
669
    {
670
        throw new \Exception('Not implemented');
671
    }
672
673
    /**
674
     * @return \MongoDB\Collection
675
     */
676 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...
677
    {
678
        $options = [
679
            'readPreference' => $this->readPreference,
680
            'writeConcern' => $this->writeConcern,
681
        ];
682
683
        if ($this->collection === null) {
684
            $this->collection = $this->db->getDb()->selectCollection($this->name, $options);
685
        } else {
686
            $this->collection = $this->collection->withOptions($options);
687
        }
688
    }
689
}
690
691