GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 4d70f8...b8b9fc )
by De
02:16
created

Collection::hasDocument()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
rs 9.4285
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
/**
4
 * This file is part of the PHPMongo package.
5
 *
6
 * (c) Dmytro Sokil <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sokil\Mongo;
13
14
use Sokil\Mongo\Document\InvalidDocumentException;
15
use Sokil\Mongo\Exception\FeatureNotSupportedException;
16
use Sokil\Mongo\Collection\Definition;
17
use Sokil\Mongo\Enum\Language;
18
19
/**
20
 * Instance of this class is a representation of mongo collection.
21
 * It aggregates \MongoCollection instance.
22
 *
23
 * @link https://github.com/sokil/php-mongo#selecting-database-and-collection Selecting collection
24
 * @link https://github.com/sokil/php-mongo#querying-documents Querying documents
25
 * @link https://github.com/sokil/php-mongo#update-few-documents Update few documents
26
 * @link https://github.com/sokil/php-mongo#deleting-collections-and-documents Deleting collection
27
 *
28
 * @author Dmytro Sokil <[email protected]>
29
 */
30
class Collection implements \Countable
31
{
32
    protected $mongoCollectionClassName = '\MongoCollection';
33
34
    /**
35
     * @var string expression class. This class may be overloaded to define
36
     *  own query methods (whereUserAgeGreatedThan(), etc.)
37
     * @deprecated since 1.13 Use 'expressionClass' declaration in mapping
38
     */
39
    protected $_queryExpressionClass;
40
41
    /**
42
     * @deprecated since 1.13 Use 'documentClass' declaration in mapping
43
     * @var string Default class for document
44
     */
45
    private $documentClass;
46
47
    /**
48
     * List of arrays, where each item array is an index definition.
49
     * Every index definition must contain key 'keys' with list of fields and orders,
50
     * and optional options from @link http://php.net/manual/en/mongocollection.createindex.php:
51
     *
52
     * Example:
53
     * array(
54
     *     array(
55
     *         'keys' => array('field1' => 1, 'field2' => -1),
56
     *         'unique' => true
57
     *     ),
58
     *     ...
59
     * )
60
     * @var array list of indexes
61
     * @deprecated since 1.13 Use 'index' declaration in mapping
62
     */
63
    protected $_index;
64
65
    /**
66
     *
67
     * @var \Sokil\Mongo\Database
68
     */
69
    private $database;
70
71
    /**
72
     *
73
     * @var \MongoCollection
74
     */
75
    private $collection;
76
77
    /**
78
     * @var string
79
     */
80
    private $collectionName;
81
82
    /**
83
     * Implementation of identity map pattern
84
     *
85
     * @var array list of cached documents
86
     */
87
    private $documentPool = array();
88
89
    /**
90
     * @deprecated since 1.13 Use 'versioning' declaration in mapping
91
     * @var bool default value of versioning
92
     */
93
    protected $versioning;
94
95
    /**
96
     * @var \Sokil\Mongo\Collection\Definition collection options
97
     */
98
    private $definition;
99
100
    public function __construct(
101
        Database $database,
102
        $collection,
103
        Definition $definition = null
104
    ) {
105
        // define db
106
        $this->database = $database;
107
108
        // init mongo collection
109
        if ($collection instanceof \MongoCollection) {
110
            $this->collectionName = $collection->getName();
111
            $this->collection = $collection;
112
        } else {
113
            $this->collectionName = $collection;
114
        }
115
116
        // init definition
117
        $this->definition = $definition ? $definition : new Definition();
118
119
        if (!empty($this->documentClass)) {
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$documentClass has been deprecated with message: since 1.13 Use 'documentClass' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
120
            $this->definition->setOption('documentClass', $this->documentClass);
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$documentClass has been deprecated with message: since 1.13 Use 'documentClass' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
121
        }
122
123
        if ($this->versioning !== null) {
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$versioning has been deprecated with message: since 1.13 Use 'versioning' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
124
            $this->definition->setOption('versioning', $this->versioning);
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$versioning has been deprecated with message: since 1.13 Use 'versioning' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
125
        }
126
127
        if (!empty($this->_index)) {
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$_index has been deprecated with message: since 1.13 Use 'index' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
128
            $this->definition->setOption('index', $this->_index);
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$_index has been deprecated with message: since 1.13 Use 'index' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
129
        }
130
131
        if (!empty($this->_queryExpressionClass)) {
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$_queryExpressionClass has been deprecated with message: since 1.13 Use 'expressionClass' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
132
            $this->definition->setOption('expressionClass', $this->_queryExpressionClass);
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Collection::$_queryExpressionClass has been deprecated with message: since 1.13 Use 'expressionClass' declaration in mapping

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
133
        }
134
    }
135
136
    /**
137
     * Start versioning documents on modify
138
     *
139
     * @deprecated since 1.13 Use 'versioning' declaration in mapping
140
     * @return \Sokil\Mongo\Collection
141
     */
142
    public function enableVersioning()
143
    {
144
        $this->definition->setOption('versioning', true);
145
        return $this;
146
    }
147
148
    /**
149
     * Check if versioning enabled
150
     *
151
     * @deprecated since 1.13 Use 'versioning' declaration in mapping
152
     * @return bool
153
     */
154
    public function isVersioningEnabled()
155
    {
156
        return $this->definition->getOption('versioning');
157
    }
158
159
    /**
160
     * Get option
161
     *
162
     * @param string|int $name
163
     * @return mixed
164
     */
165
    public function getOption($name)
166
    {
167
        return $this->definition->getOption($name);
168
    }
169
170
    public function getOptions()
171
    {
172
        return $this->definition->getOptions();
173
    }
174
175
    public function __get($name)
176
    {
177
        // support of deprecated property, use selg::getMongoCollection instead
178
        if ($name === '_mongoCollection') {
179
            return $this->getMongoCollection();
180
        }
181
182
        return $this->getDocument($name);
183
    }
184
185
    /**
186
     * Get name of collection
187
     *
188
     * @return string name of collection
189
     */
190
    public function getName()
191
    {
192
        return $this->collectionName;
193
    }
194
195
    /**
196
     * Get native collection instance of mongo driver
197
     *
198
     * @return \MongoCollection
199
     */
200
    public function getMongoCollection()
201
    {
202
        if (empty($this->collection)) {
203
            $mongoCollectionClassName = $this->mongoCollectionClassName;
204
            $this->collection = new $mongoCollectionClassName(
205
                $this->database->getMongoDB(),
206
                $this->collectionName
207
            );
208
        }
209
210
        return $this->collection;
211
    }
212
213
    /**
214
     *
215
     * @return \Sokil\Mongo\Database
216
     */
217
    public function getDatabase()
218
    {
219
        return $this->database;
220
    }
221
222
    /**
223
     * Delete collection
224
     *
225
     * @return \Sokil\Mongo\Collection
226
     * @throws \Sokil\Mongo\Exception
227
     */
228
    public function delete()
229
    {
230
        $status = $this->getMongoCollection()->drop();
231
        if ($status['ok'] != 1) {
232
            // check if collection exists
233
            if ('ns not found' !== $status['errmsg']) {
234
                // collection exist
235
                throw new Exception('Error deleting collection ' . $this->getName() . ': ' . $status['errmsg']);
236
            }
237
        }
238
239
        return $this;
240
    }
241
242
    /**
243
     * Override to define class name of document by document data
244
     *
245
     * @param array $documentData
246
     * @return string Document class data
247
     */
248
    public function getDocumentClassName(array $documentData = null)
249
    {
250
        $documentClass = $this->definition->getOption('documentClass');
251
252
        if (is_callable($documentClass)) {
253
            return call_user_func($documentClass, $documentData);
254
        }
255
256
        if (class_exists($documentClass)) {
257
            return $documentClass;
258
        }
259
260
        throw new Exception('Property "documentClass" must be callable or valid name of class');
261
    }
262
263
    /**
264
     * Factory method to get not stored Document instance from array
265
     * @param array $data
266
     * @return Document
267
     */
268
    public function createDocument(array $data = null)
269
    {
270
        $className = $this->getDocumentClassName($data);
271
272
        /* @var $document \Sokil\Mongo\Document */
273
        $document = new $className(
274
            $this,
275
            $data,
276
            array('stored' => false) + $this->definition->getOptions()
277
        );
278
279
        // store document to identity map
280
        if ($this->isDocumentPoolEnabled()) {
281
            $collection = $this;
282
            $document->onAfterInsert(function (\Sokil\Mongo\Event $event) use ($collection) {
283
                $collection->addDocumentToDocumentPool($event->getTarget());
284
            });
285
        }
286
287
        return $document;
288
    }
289
290
    /**
291
     * Factory method to get document object from array of stored document
292
     *
293
     * @param array $data
294
     * @return \Sokil\Mongo\Document
295
     */
296
    public function hydrate($data, $useDocumentPool = true)
297
    {
298
        if (!is_array($data) || !isset($data['_id'])) {
299
            throw new Exception('Document must be stored and has _id key');
300
        }
301
302
        // if document already in pool - return it
303
        if ($useDocumentPool && $this->isDocumentPoolEnabled() && $this->isDocumentInDocumentPool($data['_id'])) {
304
            return $this
305
                ->getDocumentFromDocumentPool($data['_id'])
306
                ->mergeUnmodified($data);
307
        }
308
309
        // init document instance
310
        $className = $this->getDocumentClassName($data);
311
        $document = new $className(
312
            $this,
313
            $data,
314
            array('stored' => true) + $this->definition->getOptions()
315
        );
316
317
        // store document in cache
318
        if ($useDocumentPool && $this->isDocumentPoolEnabled()) {
319
            $this->addDocumentToDocumentPool($document);
320
        }
321
322
        return $document;
323
    }
324
325
    /**
326
     * Total count of documents in collection
327
     *
328
     * @return int
329
     */
330
    public function count()
331
    {
332
        return $this->find()->count();
333
    }
334
335
    /**
336
     * Retrieve a list of distinct values for the given key across a collection.
337
     *
338
     * @param string $selector field selector
339
     * @param array|callable|\Sokil\Mongo\Expression $expression expression to search documents
340
     * @return array distinct values
341
     */
342
    public function getDistinct($selector, $expression = null)
343
    {
344
        if ($expression) {
345
            return $this->getMongoCollection()->distinct(
346
                $selector,
347
                Expression::convertToArray($expression)
348
            );
349
        }
350
351
        return $this->getMongoCollection()->distinct($selector);
352
    }
353
354
    /**
355
     * Create new Expression instance to use in query builder or update operations
356
     *
357
     * @return \Sokil\Mongo\Expression
358
     */
359
    public function expression()
360
    {
361
        $className = $this->definition->getExpressionClass();
362
        return new $className;
363
    }
364
365
    /**
366
     * Create Operator instance to use in update operations
367
     *
368
     * @return \Sokil\Mongo\Operator
369
     */
370
    public function operator()
371
    {
372
        return new Operator();
373
    }
374
375
    /**
376
     * Create document query builder
377
     *
378
     * @param $callable callable|null Function to configure query builder&
379
     * @return Cursor
380
     */
381
    public function find($callable = null)
382
    {
383
        /** @var Cursor $cursor */
384
        $cursor = new Cursor($this, array(
385
            'expressionClass'   => $this->definition->getExpressionClass(),
386
            'batchSize'         => $this->definition->getOption('batchSize'),
387
            'clientTimeout'     => $this->definition->getOption('cursorClientTimeout'),
388
            'serverTimeout'     => $this->definition->getOption('cursorServerTimeout'),
389
        ));
390
391
        if (is_callable($callable)) {
392
            $callable($cursor->getExpression());
393
        }
394
395
        return $cursor;
396
    }
397
398
    /**
399
     * Create document query builder
400
     *
401
     * @param callable|null $callable
402
     *
403
     * @return \Sokil\Mongo\Cursor
404
     */
405
    public function findAsArray($callable = null)
406
    {
407
        return $this
408
            ->find($callable)
409
            ->asArray();
410
    }
411
412
    /**
413
     * Stop storing found documents to pool
414
     *
415
     * @return \Sokil\Mongo\Collection
416
     */
417
    public function disableDocumentPool()
418
    {
419
        $this->definition->setOption('documentPool', false);
420
        return $this;
421
    }
422
423
    /**
424
     * Start storing found documents to pool
425
     *
426
     * @return \Sokil\Mongo\Collection
427
     */
428
    public function enableDocumentPool()
429
    {
430
        $this->definition->setOption('documentPool', true);
431
        return $this;
432
    }
433
434
    /**
435
     * Check if document pool enabled and requested documents store to it
436
     *
437
     * @return bool
438
     */
439
    public function isDocumentPoolEnabled()
440
    {
441
        return $this->definition->getOption('documentPool');
442
    }
443
444
    public function clearDocumentPool()
445
    {
446
        $this->documentPool = array();
447
        return $this;
448
    }
449
450
    /**
451
     * Check if documents are in pool
452
     *
453
     * @return bool
454
     */
455
    public function isDocumentPoolEmpty()
456
    {
457
        return !$this->documentPool;
458
    }
459
460
    /**
461
     * Store document to pool
462
     *
463
     * @param array $document
464
     * @return \Sokil\Mongo\Collection
465
     */
466
    public function addDocumentToDocumentPool(Document $document)
467
    {
468
        $documentId = (string) $document->getId();
469
470
        if (!isset($this->documentPool[$documentId])) {
471
            $this->documentPool[$documentId] = $document;
472
        } else {
473
            // merging because document after
474
            // load and before getting in second place may be changed
475
            // and this changes must be preserved:
476
            //
477
            // 1. Document loads and modifies in current session
478
            // 2. Document loads modified in another session
479
            // 3. Document loads once again in current session. Changes from stage 2 merges as unmodified
480
481
            $this->documentPool[$documentId]->mergeUnmodified($document->toArray());
482
        }
483
484
        return $this;
485
    }
486
487
    /**
488
     * Store documents to identity map
489
     *
490
     * @param array $documents list of Document instances
491
     * @return \Sokil\Mongo\Collection
492
     */
493
    public function addDocumentsToDocumentPool(array $documents)
494
    {
495
        foreach ($documents as $document) {
496
            $this->addDocumentToDocumentPool($document);
497
        }
498
499
        return $this;
500
    }
501
502
    /**
503
     * Remove document instance from identity map
504
     *
505
     * @param \Sokil\Mongo\Document $document
506
     * @return \Sokil\Mongo\Collection
507
     */
508
    public function removeDocumentFromDocumentPool(Document $document)
509
    {
510
        unset($this->documentPool[(string) $document]);
511
        return $this;
512
    }
513
514
    /**
515
     * Get document from identity map by it's id
516
     *
517
     * @param string|int|\MongoId $id
518
     * @return \Sokil\Mongo\Document
519
     */
520
    public function getDocumentFromDocumentPool($id)
521
    {
522
        return $this->documentPool[(string) $id];
523
    }
524
525
    /**
526
     * Get documents from pool if they stored
527
     *
528
     * @param array $ids
529
     */
530
    public function getDocumentsFromDocumentPool(array $ids = null)
531
    {
532
        if (!$ids) {
533
            return $this->documentPool;
534
        }
535
536
        return array_intersect_key(
537
            $this->documentPool,
538
            array_flip(array_map('strval', $ids))
539
        );
540
    }
541
542
    /**
543
     * Get number of documents in document pool
544
     *
545
     * @return int
546
     */
547
    public function documentPoolCount()
548
    {
549
        return count($this->documentPool);
550
    }
551
552
    /**
553
     * Check if document exists in identity map
554
     *
555
     * @param \Sokil\Mongo\Document|\MongoId|int|string $document Document instance or it's id
556
     * @return boolean
557
     */
558
    public function isDocumentInDocumentPool($document)
559
    {
560
        if ($document instanceof Document) {
561
            $document = $document->getId();
562
        }
563
564
        return isset($this->documentPool[(string) $document]);
565
    }
566
567
    /**
568
     * Get document by id
569
     * If callable specified, document always loaded directly omitting document pool.
570
     * Method may return document as array if cursor configured through Cursor::asArray()
571
     *
572
     * @param string|\MongoId $id
573
     * @param callable $callable cursor callable used to configure cursor
574
     * @return \Sokil\Mongo\Document|array|null
575
     */
576
    public function getDocument($id, $callable = null)
577
    {
578
        if (!$this->isDocumentPoolEnabled()) {
579
            return $this->getDocumentDirectly($id, $callable);
580
        }
581
582
        if (!$callable && $this->isDocumentInDocumentPool($id)) {
583
            return $this->getDocumentFromDocumentPool($id);
584
        }
585
586
        $document = $this->getDocumentDirectly($id, $callable);
587
588
        // if callable configure cursor to return document as array,
589
        // than it can't be stored to document pool
590
        if ($document instanceof Document) {
591
            $this->addDocumentToDocumentPool($document);
592
        }
593
594
        return $document;
595
    }
596
597
    /**
598
     * Get Document instance by it's reference
599
     *
600
     * @param array $ref reference to document
601
     * @param bool  $useDocumentPool try to get document from pool or fetch document from database
602
     *
603
     * @return Document|null
604
     */
605 View Code Duplication
    public function getDocumentByReference(array $ref, $useDocumentPool = true)
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...
606
    {
607
        $documentArray = $this->getMongoCollection()->getDBRef($ref);
608
        if (null === $documentArray) {
609
            return null;
610
        }
611
612
        return $this->hydrate($documentArray, $useDocumentPool);
613
    }
614
615
    /**
616
     * Get document by id directly omitting cache
617
     * Method may return document as array if cursor configured through Cursor::asArray()
618
     *
619
     * @param string|\MongoId $id
620
     * @param callable $callable cursor callable used to configure cursor
621
     * @return \Sokil\Mongo\Document|array|null
622
     */
623
    public function getDocumentDirectly($id, $callable = null)
624
    {
625
        $cursor = $this->find();
626
627
        if (is_callable($callable)) {
628
            call_user_func($callable, $cursor);
629
        }
630
631
        return $cursor
632
            ->byId($id)
633
            ->skipDocumentPool()
634
            ->findOne();
635
    }
636
637
    /**
638
     * Check if document belongs to collection
639
     *
640
     * @param Document $document
641
     * @return bool
642
     */
643
    public function hasDocument(Document $document)
644
    {
645
        // check connection
646
        if ($document->getCollection()->getDatabase()->getClient()->getDsn() !== $this->getDatabase()->getClient()->getDsn()) {
647
            return false;
648
        }
649
650
        // check database
651
        if ($document->getCollection()->getDatabase()->getName() !== $this->getDatabase()->getName()) {
652
            return false;
653
        }
654
655
        // check collection
656
        return $document->getCollection()->getName() == $this->getName();
657
    }
658
659
    /**
660
     * Get documents by list of id
661
     *
662
     * @param array $idList list of ids
663
     * @param callable $callable cursor callable used to configure cursor
664
     * @return array|null
665
     */
666
    public function getDocuments(array $idList, $callable = null)
667
    {
668
        $idListToFindDirectly = $idList;
669
670
        // try to egt document from pool if enabled
671
        $documentsInDocumentPool = array();
672
        if ($this->isDocumentPoolEnabled() && !$callable) {
673
            $documentsInDocumentPool = $this->getDocumentsFromDocumentPool($idList);
674
            if (count($documentsInDocumentPool) === count($idList)) {
675
                return $documentsInDocumentPool;
676
            }
677
678
            // skip ids already found in pool
679
            $idListToFindDirectly = array_diff_key(
680
                array_map('strval', $idList),
681
                array_keys($documentsInDocumentPool)
682
            );
683
        }
684
685
        // get documents directly
686
        $cursor = $this->find();
687
688
        if (is_callable($callable)) {
689
            call_user_func($callable, $cursor);
690
        }
691
692
        $documentsGettingDirectly = $cursor->byIdList($idListToFindDirectly)->findAll();
693
        if (empty($documentsGettingDirectly)) {
694
            return $documentsInDocumentPool ? $documentsInDocumentPool : array();
695
        }
696
697
        if ($this->isDocumentPoolEnabled()) {
698
            $this->addDocumentsToDocumentPool($documentsGettingDirectly);
699
        }
700
701
        return $documentsGettingDirectly + $documentsInDocumentPool;
702
    }
703
704
    /**
705
     * Creates batch insert operation handler
706
     * @param int|string $writeConcern Write concern. Default is 1 (Acknowledged)
707
     * @param int $timeout Timeout for write concern. Default is 10000 milliseconds
708
     * @param bool $ordered Determins if MongoDB must apply this batch in order (sequentally,
709
     *   one item at a time) or can rearrange it. Defaults to TRUE
710
     * @return BatchInsert
711
     */
712
    public function createBatchInsert($writeConcern = null, $timeout = null, $ordered = null)
713
    {
714
        return new BatchInsert(
715
            $this,
716
            $writeConcern,
717
            $timeout,
718
            $ordered
719
        );
720
    }
721
722
    /**
723
     * Creates batch update operation handler
724
     * @param int|string $writeConcern Write concern. Default is 1 (Acknowledged)
725
     * @param int $timeout Timeout for write concern. Default is 10000 milliseconds
726
     * @param bool $ordered Determins if MongoDB must apply this batch in order (sequentally,
727
     *   one item at a time) or can rearrange it. Defaults to TRUE
728
     * @return BatchUpdate
729
     */
730
    public function createBatchUpdate($writeConcern = null, $timeout = null, $ordered = null)
731
    {
732
        return new BatchUpdate(
733
            $this,
734
            $writeConcern,
735
            $timeout,
736
            $ordered
737
        );
738
    }
739
740
    /**
741
     * Creates batch delete operation handler
742
     * @param int|string $writeConcern Write concern. Default is 1 (Acknowledged)
743
     * @param int $timeout Timeout for write concern. Default is 10000 milliseconds
744
     * @param bool $ordered Determins if MongoDB must apply this batch in order (sequentally,
745
     *   one item at a time) or can rearrange it. Defaults to TRUE
746
     * @return BatchDelete
747
     */
748
    public function createBatchDelete($writeConcern = null, $timeout = null, $ordered = null)
749
    {
750
        return new BatchDelete(
751
            $this,
752
            $writeConcern,
753
            $timeout,
754
            $ordered
755
        );
756
    }
757
758
    /**
759
     * @deprecated since 1.13. Use Document::delete()
760
     * @param \Sokil\Mongo\Document $document
761
     * @return \Sokil\Mongo\Collection
762
     */
763
    public function deleteDocument(Document $document)
764
    {
765
        $document->delete();
766
        return $this;
767
    }
768
769
    /**
770
     * Delete documents by expression
771
     *
772
     * @param Expression|callable|array $expression
773
     * @return \Sokil\Mongo\Collection
774
     * @throws Exception
775
     */
776
    public function batchDelete($expression)
777
    {
778
        // remove
779
        $result = $this->getMongoCollection()->remove(
780
            Expression::convertToArray($expression)
781
        );
782
783
        // check result
784
        if (true !== $result && $result['ok'] != 1) {
785
            throw new Exception('Error removing documents from collection: ' . $result['err']);
786
        }
787
788
        return $this;
789
    }
790
791
    /**
792
     * @deprecated since 1.13. Use Collection::batchDelete();
793
     */
794
    public function deleteDocuments($expression = array())
795
    {
796
        return $this->batchDelete($expression);
797
    }
798
799
    /**
800
     * Insert multiple documents defined as arrays
801
     *
802
     * Prior to version 1.5.0 of the driver it was possible to use MongoCollection::batchInsert(),
803
     * however, as of 1.5.0 that method is now discouraged.
804
     *
805
     * You can use Collection::createBatchInsert()
806
     *
807
     * @param array $rows list of documents to insert, defined as arrays
808
     * @return \Sokil\Mongo\Collection
809
     * @throws \Sokil\Mongo\Document\InvalidDocumentException
810
     * @throws \Sokil\Mongo\Exception
811
     */
812
    public function batchInsert($rows, $validate = true)
813
    {
814
        if ($validate) {
815
            $document = $this->createDocument();
816
            foreach ($rows as $row) {
817
                $document->merge($row);
818
819
                if (!$document->isValid()) {
820
                    throw new InvalidDocumentException('Document is invalid on batch insert');
821
                }
822
823
                $document->reset();
824
            }
825
        }
826
827
        $result = $this->getMongoCollection()->batchInsert($rows);
828
829
        // If the w parameter is set to acknowledge the write,
830
        // returns an associative array with the status of the inserts ("ok")
831
        // and any error that may have occurred ("err").
832 View Code Duplication
        if (is_array($result)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
833
            if ($result['ok'] != 1) {
834
                throw new Exception('Batch insert error: ' . $result['err']);
835
            }
836
837
            return $this;
838
        }
839
840
        // Otherwise, returns TRUE if the batch insert was successfully sent,
841
        // FALSE otherwise.
842
        if (!$result) {
843
            throw new Exception('Batch insert error');
844
        }
845
846
        return $this;
847
    }
848
849
    /**
850
     * @deprecated since 1.13 Use Collection::batchInsert()
851
     */
852
    public function insertMultiple($rows, $validate = true)
853
    {
854
        return $this->batchInsert($rows, $validate);
855
    }
856
857
    /**
858
     * Direct insert of array to MongoDB without creating document object and validation
859
     *
860
     * @param array $document
861
     * @return \Sokil\Mongo\Collection
862
     * @throws Exception
863
     */
864
    public function insert(array $document)
865
    {
866
        $result = $this->getMongoCollection()->insert($document);
867
868
        // if write concern acknowledged
869 View Code Duplication
        if (is_array($result)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
870
            if ($result['ok'] != 1) {
871
                throw new Exception('Insert error: ' . $result['err'] . ': ' . $result['errmsg']);
872
            }
873
874
            return $this;
875
        }
876
877
        // if write concern unacknowledged
878
        if (!$result) {
879
            throw new Exception('Insert error');
880
        }
881
882
        return $this;
883
    }
884
885
    /**
886
     * Update multiple documents
887
     *
888
     * @param \Sokil\Mongo\Expression|array|callable $expression expression to define
889
     *  which documents will change.
890
     * @param \Sokil\Mongo\Operator|array|callable $updateData new data or operators to update
891
     * @param array $options update options, see http://php.net/manual/ru/mongocollection.update.php
892
     * @return \Sokil\Mongo\Collection
893
     * @throws \Sokil\Mongo\Exception
894
     */
895
    public function update($expression, $updateData, array $options = array())
896
    {
897
        // execute update operator
898
        $result = $this->getMongoCollection()->update(
899
            Expression::convertToArray($expression),
900
            Operator::convertToArray($updateData),
901
            $options
902
        );
903
904
        // if write concern acknowledged
905 View Code Duplication
        if (is_array($result)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
906
            if ($result['ok'] != 1) {
907
                throw new Exception(sprintf('Update error: %s: %s', $result['err'], $result['errmsg']));
908
            }
909
            return $this;
910
        }
911
912
        // if write concern unacknowledged
913
        if (!$result) {
914
            throw new Exception('Update error');
915
        }
916
917
        return $this;
918
    }
919
920
    /**
921
     * Update multiple documents
922
     *
923
     * @param \Sokil\Mongo\Expression|array|callable $expression expression to define
924
     *  which documents will change.
925
     * @param \Sokil\Mongo\Operator|array|callable $updateData new data or operators
926
     *  to update
927
     * @return \Sokil\Mongo\Collection
928
     * @throws \Sokil\Mongo\Exception
929
     */
930
    public function batchUpdate($expression, $updateData)
931
    {
932
        return $this->update($expression, $updateData, array(
933
            'multiple'  => true,
934
        ));
935
    }
936
937
    /**
938
     * @deprecated since 1.13 Use Collection::batchUpdate()
939
     */
940
    public function updateMultiple($expression, $updateData)
941
    {
942
        return $this->batchUpdate($expression, $updateData);
943
    }
944
945
    /**
946
     * Update all documents
947
     *
948
     * @deprecated since 1.13. Use Collection::batchUpdate([])
949
     * @param \Sokil\Mongo\Operator|array|callable $updateData new data or operators
950
     * @return \Sokil\Mongo\Collection
951
     * @throws \Sokil\Mongo\Exception
952
     */
953
    public function updateAll($updateData)
954
    {
955
        return $this->update(array(), $updateData, array(
956
            'multiple'  => true,
957
        ));
958
    }
959
960
    /**
961
     * Start aggregation
962
     *
963
     * @link http://docs.mongodb.org/manual/reference/operator/aggregation/
964
     * @return \Sokil\Mongo\Pipeline
965
     */
966
    public function createAggregator()
967
    {
968
        return new Pipeline($this);
969
    }
970
971
    /**
972
     * Aggregate using pipeline
973
     * @link http://docs.mongodb.org/manual/reference/operator/aggregation/
974
     *
975
     * @param callable|array|Pipeline $pipeline list of pipeline stages
976
     * @param array aggregate options
977
     * @param bool $asCursor return result as cursor
978
     *
979
     * @throws \Sokil\Mongo\Exception
980
     * @return array result of aggregation
981
     */
982
    public function aggregate(
983
        $pipeline,
984
        array $options = array(),
985
        $asCursor = false
986
    ) {
987
        // configure through callable
988
        if (is_callable($pipeline)) {
989
            $pipelineConfiguratorCallable = $pipeline;
990
            $pipeline = $this->createAggregator();
991
            call_user_func($pipelineConfiguratorCallable, $pipeline);
992
        }
993
994
        // get aggregation array
995
        if ($pipeline instanceof Pipeline) {
996
            if (!empty($options)) {
997
                $options = array_merge($pipeline->getOptions(), $options);
998
            } else {
999
                $options = $pipeline->getOptions();
1000
            }
1001
            $pipeline = $pipeline->toArray();
1002
        } elseif (!is_array($pipeline)) {
1003
            throw new Exception('Wrong pipeline specified');
1004
        }
1005
1006
        // Check options for supporting by database
1007
        if (!empty($options)) {
1008
            $this->validateAggregationOptions($options);
1009
        }
1010
1011
        // return result as cursor
1012
        if ($asCursor) {
1013
            if (version_compare(\MongoClient::VERSION, '1.5.0', '>=')) {
1014
                return $this->getMongoCollection()->aggregateCursor($pipeline, $options);
0 ignored issues
show
Bug introduced by
The method aggregateCursor() does not exist on MongoCollection. Did you maybe mean aggregate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1015
            } else {
1016
                throw new FeatureNotSupportedException('Aggregate cursor supported from driver version 1.5');
1017
            }
1018
        }
1019
1020
        // prepare command
1021
        $command = array(
1022
            'aggregate' => $this->getName(),
1023
            'pipeline'  => $pipeline,
1024
        );
1025
1026
        // add options
1027
        if (!empty($options)) {
1028
            $command += $options;
1029
        }
1030
1031
        // aggregate
1032
        $status = $this->database->executeCommand($command);
1033
        if ($status['ok'] != 1) {
1034
            throw new Exception('Aggregate error: ' . $status['errmsg']);
1035
        }
1036
1037
        // explain response
1038
        if (!empty($command['explain'])) {
1039
            return $status['stages'];
1040
        }
1041
1042
        // result response
1043
        return $status['result'];
1044
    }
1045
1046
    /**
1047
     * Check if aggragator options supported by database
1048
     *
1049
     * @param array $options
1050
     * @throws FeatureNotSupportedException
1051
     */
1052
    private function validateAggregationOptions(array $options)
1053
    {
1054
        // get db version
1055
        $client = $this->getDatabase()->getClient();
1056
        $dbVersion = $client->getDbVersion();
1057
1058
        // check options for db < 2.6
1059
        if (version_compare($dbVersion, '2.6.0', '<')) {
1060
            if (!empty($options['explain'])) {
1061
                throw new FeatureNotSupportedException('Explain of aggregation implemented only from 2.6.0');
1062
            }
1063
1064
            if (!empty($options['allowDiskUse'])) {
1065
                throw new FeatureNotSupportedException('Option allowDiskUse of aggregation implemented only from 2.6.0');
1066
            }
1067
1068
            if (!empty($options['cursor'])) {
1069
                throw new FeatureNotSupportedException('Option cursor of aggregation implemented only from 2.6.0');
1070
            }
1071
        }
1072
1073
        // check options for db < 3.2
1074
        if (version_compare($dbVersion, '3.2.0', '<')) {
1075
            if (!empty($options['bypassDocumentValidation'])) {
1076
                throw new FeatureNotSupportedException('Option bypassDocumentValidation of aggregation implemented only from 3.2.0');
1077
            }
1078
1079
            if (!empty($options['readConcern'])) {
1080
                throw new FeatureNotSupportedException('Option readConcern of aggregation implemented only from 3.2.0');
1081
            }
1082
        }
1083
    }
1084
1085
    /**
1086
     * Explain aggregation
1087
     *
1088
     * @deprecated use pipeline option 'explain' in Collection::aggregate() or method Pipeline::explain()
1089
     * @param array|Pipeline $pipeline
1090
     * @return array result
1091
     * @throws Exception
1092
     */
1093
    public function explainAggregate($pipeline)
1094
    {
1095
        if (version_compare($this->getDatabase()->getClient()->getDbVersion(), '2.6.0', '<')) {
1096
            throw new Exception('Explain of aggregation implemented only from 2.6.0');
1097
        }
1098
1099
        if ($pipeline instanceof Pipeline) {
1100
            $pipeline = $pipeline->toArray();
1101
        } elseif (!is_array($pipeline)) {
1102
            throw new Exception('Wrong pipeline specified');
1103
        }
1104
1105
        // aggregate
1106
        return $this->database->executeCommand(array(
1107
            'aggregate' => $this->getName(),
1108
            'pipeline'  => $pipeline,
1109
            'explain'   => true
1110
        ));
1111
    }
1112
1113
    /**
1114
     * Validates a collection. The method scans a collection’s data structures
1115
     * for correctness and returns a single document that describes the
1116
     * relationship between the logical collection and the physical
1117
     * representation of the data.
1118
     *
1119
     * @link http://docs.mongodb.org/manual/reference/method/db.collection.validate/
1120
     * @param bool $full Specify true to enable a full validation and to return
1121
     *      full statistics. MongoDB disables full validation by default because it
1122
     *      is a potentially resource-intensive operation.
1123
     * @return array
1124
     * @throws Exception
1125
     */
1126
    public function validate($full = false)
1127
    {
1128
        $response = $this->getMongoCollection()->validate($full);
1129
        if (empty($response) || $response['ok'] != 1) {
1130
            throw new Exception($response['errmsg']);
1131
        }
1132
1133
        return $response;
1134
    }
1135
1136
    /**
1137
     * Create index
1138
     *
1139
     * @deprecated since 1.19 Use self::createIndex()
1140
     * @param array $key
1141
     * @param array $options see @link http://php.net/manual/en/mongocollection.ensureindex.php
1142
     * @return \Sokil\Mongo\Collection
1143
     */
1144
    public function ensureIndex(array $key, array $options = array())
1145
    {
1146
        return $this->createIndex($key, $options);
1147
    }
1148
1149
    /**
1150
     * Create index
1151
     *
1152
     * @param array $key
1153
     * @param array $options see @link http://php.net/manual/en/mongocollection.ensureindex.php
1154
     * @return \Sokil\Mongo\Collection
1155
     */
1156
    public function createIndex(array $key, array $options = array())
1157
    {
1158
        $this->getMongoCollection()->createIndex($key, $options);
1159
        return $this;
1160
    }
1161
    
1162
    /**
1163
     * Delete index
1164
     *
1165
     * @param array $key
1166
     * @return \Sokil\Mongo\Collection
1167
     */
1168
    public function deleteIndex(array $key)
1169
    {
1170
        $this->getMongoCollection()->deleteIndex($key);
1171
        return $this;
1172
    }
1173
1174
    /**
1175
     * Create unique index
1176
     *
1177
     * @param array $key
1178
     * @param boolean $dropDups
1179
     * @return \Sokil\Mongo\Collection
1180
     */
1181
    public function ensureUniqueIndex(array $key, $dropDups = false)
1182
    {
1183
        $this->getMongoCollection()->createIndex($key, array(
1184
            'unique'    => true,
1185
            'dropDups'  => (bool) $dropDups,
1186
        ));
1187
1188
        return $this;
1189
    }
1190
1191
    /**
1192
     * Create sparse index.
1193
     *
1194
     * Sparse indexes only contain entries for documents that have the indexed
1195
     * field, even if the index field contains a null value. The index skips
1196
     * over any document that is missing the indexed field.
1197
     *
1198
     * @link http://docs.mongodb.org/manual/core/index-sparse/
1199
     *
1200
     * @param string|array $key An array specifying the index's fields as its
1201
     *  keys. For each field, the value is either the index direction or index
1202
     *  type. If specifying direction, specify 1 for ascending or -1
1203
     *  for descending.
1204
     *
1205
     * @return Collection
1206
     */
1207
    public function ensureSparseIndex(array $key)
1208
    {
1209
        $this->getMongoCollection()->createIndex(
1210
            $key,
1211
            array(
1212
                'sparse'    => true,
1213
            )
1214
        );
1215
1216
        return $this;
1217
    }
1218
1219
    /**
1220
     * Create TTL index
1221
     *
1222
     * @link http://docs.mongodb.org/manual/tutorial/expire-data/
1223
     *
1224
     * If seconds not specified then document expired at specified time, as
1225
     * described at @link http://docs.mongodb.org/manual/tutorial/expire-data/#expire-documents-at-a-certain-clock-time
1226
     *
1227
     * @param string|array $key key must be date to use TTL
1228
     * @param int $seconds
1229
     * @return \Sokil\Mongo\Collection
1230
     */
1231
    public function ensureTTLIndex(array $key, $seconds = 0)
1232
    {
1233
        $this->getMongoCollection()->createIndex($key, array(
1234
            'expireAfterSeconds' => $seconds,
1235
        ));
1236
1237
        return $this;
1238
    }
1239
1240
    /**
1241
     * Create geo index 2dsphere
1242
     *
1243
     * @link http://docs.mongodb.org/manual/tutorial/build-a-2dsphere-index/
1244
     *
1245
     * @param string $field
1246
     * @return \Sokil\Mongo\Collection
1247
     */
1248 View Code Duplication
    public function ensure2dSphereIndex($field)
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...
1249
    {
1250
        if (is_array($field)) {
1251
            $keys = array_fill_keys($field, '2dsphere');
1252
        } else {
1253
            $keys = array(
1254
                $field => '2dsphere',
1255
            );
1256
        }
1257
1258
        $this->getMongoCollection()->createIndex($keys);
1259
1260
        return $this;
1261
    }
1262
1263
    /**
1264
     * Create geo index 2dsphere
1265
     *
1266
     * @link http://docs.mongodb.org/manual/tutorial/build-a-2d-index/
1267
     *
1268
     * @param string $field
1269
     * @return \Sokil\Mongo\Collection
1270
     */
1271 View Code Duplication
    public function ensure2dIndex($field)
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...
1272
    {
1273
        if (is_array($field)) {
1274
            $keys = array_fill_keys($field, '2d');
1275
        } else {
1276
            $keys = array(
1277
                $field => '2d',
1278
            );
1279
        }
1280
1281
        $this->getMongoCollection()->createIndex($keys);
1282
1283
        return $this;
1284
    }
1285
1286
    /**
1287
     * Create fulltext index
1288
     *
1289
     * @link https://docs.mongodb.org/manual/core/index-text/
1290
     * @link https://docs.mongodb.org/manual/tutorial/specify-language-for-text-index/
1291
     *
1292
     * If a collection contains documents or embedded documents that are in different languages,
1293
     * include a field named language in the documents or embedded documents and specify as its value the language
1294
     * for that document or embedded document.
1295
     *
1296
     * The specified language in the document overrides the default language for the text index.
1297
     * The specified language in an embedded document override the language specified in an enclosing document or
1298
     * the default language for the index.
1299
     *
1300
     * @param   array|string    $field              definition of fields where full text index ensured. May be string to
1301
     *                                              ensure index on one field, array of fields  to create full text index on few
1302
     *                                              fields, and * widdcard '$**'  to create index on all fields of collection.
1303
     *                                              Default value is '$**'
1304
     *
1305
     * @param   array           $weights            For a text index, the weight of an indexed field denotes the significance
1306
     *                                              of the field relative to the other indexed fields in terms of the text
1307
     *                                              search score.
1308
     *
1309
     * @param   string          $defaultLanguage    Default language associated with the indexed data determines the rules to parse
1310
     *                                              word roots (i.e. stemming) and ignore stop words. The default
1311
     *                                              language for the indexed data is english.
1312
     *
1313
     * @param   string          $languageOverride   To use a field with a name other than language, include the
1314
     *                                              language_override option when creating the index.
1315
     *
1316
     * @return Collection
1317
     */
1318
    public function ensureFulltextIndex(
1319
        $field = '$**',
1320
        array $weights = null,
1321
        $defaultLanguage = Language::ENGLISH,
1322
        $languageOverride = null
1323
    ) {
1324
        // keys
1325
        if (is_array($field)) {
1326
            $keys = array_fill_keys($field, 'text');
1327
        } else {
1328
            $keys = array(
1329
                $field => 'text',
1330
            );
1331
        }
1332
1333
        // options
1334
        $options = array(
1335
            'default_language' => $defaultLanguage,
1336
        );
1337
1338
        if (!empty($weights)) {
1339
            $options['weights'] = $weights;
1340
        }
1341
1342
        if (!empty($languageOverride)) {
1343
            $options['language_override'] = $languageOverride;
1344
        }
1345
1346
        // create index
1347
        $this->getMongoCollection()->createIndex($keys, $options);
1348
1349
        return $this;
1350
    }
1351
1352
1353
1354
    /**
1355
     * Create indexes based on self::$_index metadata
1356
     *
1357
     * @return \Sokil\Mongo\Collection
1358
     * @throws \Exception
1359
     */
1360
    public function initIndexes()
1361
    {
1362
        // read index definition from collection options
1363
        // if not specified - use defined in property
1364
        $indexDefinition = $this->definition->getOption('index');
1365
1366
        // ensure indexes
1367
        foreach ($indexDefinition as $options) {
1368
            if (empty($options['keys'])) {
1369
                throw new Exception('Keys not specified');
1370
            }
1371
1372
            $keys = $options['keys'];
1373
            unset($options['keys']);
1374
1375
            if (is_string($keys)) {
1376
                $keys = array($keys => 1);
1377
            }
1378
1379
            $this->getMongoCollection()->createIndex($keys, $options);
1380
        }
1381
1382
        return $this;
1383
    }
1384
1385
    /**
1386
     * Get index info
1387
     * @return array
1388
     */
1389
    public function getIndexes()
1390
    {
1391
        return $this->getMongoCollection()->getIndexInfo();
1392
    }
1393
1394
    public function readPrimaryOnly()
1395
    {
1396
        $this->getMongoCollection()->setReadPreference(\MongoClient::RP_PRIMARY);
1397
        return $this;
1398
    }
1399
1400
    public function readPrimaryPreferred(array $tags = null)
1401
    {
1402
        $this->getMongoCollection()->setReadPreference(\MongoClient::RP_PRIMARY_PREFERRED, $tags);
1403
        return $this;
1404
    }
1405
1406
    public function readSecondaryOnly(array $tags = null)
1407
    {
1408
        $this->getMongoCollection()->setReadPreference(\MongoClient::RP_SECONDARY, $tags);
1409
        return $this;
1410
    }
1411
1412
    public function readSecondaryPreferred(array $tags = null)
1413
    {
1414
        $this->getMongoCollection()->setReadPreference(\MongoClient::RP_SECONDARY_PREFERRED, $tags);
1415
        return $this;
1416
    }
1417
1418
    public function readNearest(array $tags = null)
1419
    {
1420
        $this->getMongoCollection()->setReadPreference(\MongoClient::RP_NEAREST, $tags);
1421
        return $this;
1422
    }
1423
1424
    public function getReadPreference()
1425
    {
1426
        return $this->getMongoCollection()->getReadPreference();
1427
    }
1428
1429
    /**
1430
     * Define write concern for all requests to current collection
1431
     *
1432
     * @param string|integer $w write concern
1433
     * @param int $timeout timeout in milliseconds
1434
     * @throws \Sokil\Mongo\Exception
1435
     * @return \Sokil\Mongo\Collection
1436
     */
1437
    public function setWriteConcern($w, $timeout = 10000)
1438
    {
1439
        if (!$this->getMongoCollection()->setWriteConcern($w, (int) $timeout)) {
1440
            throw new Exception('Error setting write concern');
1441
        }
1442
1443
        return $this;
1444
    }
1445
1446
    /**
1447
     * Define unacknowledged write concern for all requests to current collection
1448
     *
1449
     * @param int $timeout timeout in milliseconds
1450
     * @throws \Sokil\Mongo\Exception
1451
     * @return \Sokil\Mongo\Collection
1452
     */
1453
    public function setUnacknowledgedWriteConcern($timeout = 10000)
1454
    {
1455
        $this->setWriteConcern(0, (int) $timeout);
1456
        return $this;
1457
    }
1458
1459
    /**
1460
     * Define majority write concern for all requests to current collection
1461
     *
1462
     * @param int $timeout timeout in milliseconds
1463
     * @throws \Sokil\Mongo\Exception
1464
     * @return \Sokil\Mongo\Collection
1465
     */
1466
    public function setMajorityWriteConcern($timeout = 10000)
1467
    {
1468
        $this->setWriteConcern('majority', (int) $timeout);
1469
        return $this;
1470
    }
1471
1472
    /**
1473
     * Get currently active write concern on all requests to collection
1474
     *
1475
     * @return int|string write concern
1476
     */
1477
    public function getWriteConcern()
1478
    {
1479
        return $this->getMongoCollection()->getWriteConcern();
1480
    }
1481
1482
    /**
1483
     * Get collection stat
1484
     *
1485
     * @return array collection stat
1486
     */
1487
    public function stats()
1488
    {
1489
        return $this->getDatabase()->executeCommand(array(
1490
            'collstats' => $this->getName(),
1491
        ));
1492
    }
1493
}
1494