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 ( ac64c8...dabaeb )
by De
02:10
created

Cursor::setServerTimeout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
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\Exception\CursorException;
15
use Sokil\Mongo\Exception\FeatureNotSupportedException;
16
17
/**
18
 * @mixin Expression
19
 */
20
class Cursor implements
21
    \Iterator,
22
    \Countable
23
{
24
    /**
25
     *
26
     * @var \Sokil\Mongo\Client
27
     */
28
    private $client;
29
30
    /**
31
     *
32
     * @var \Sokil\Mongo\Collection
33
     */
34
    private $collection;
35
36
    /**
37
     *
38
     * @var array
39
     */
40
    private $fields = array();
41
42
    /**
43
     *
44
     * @var \MongoCursor
45
     */
46
    private $cursor;
47
    /**
48
     *
49
     * @var Expression
50
     */
51
    private $expression;
52
53
    /**
54
     * Offset
55
     * @var int
56
     */
57
    private $skip = 0;
58
59
    /**
60
     * Limit
61
     * @var int
62
     */
63
    private $limit = 0;
64
65
    /**
66
     * Definition of sort
67
     * @var array
68
     */
69
    private $sort = array();
70
71
    /**
72
     * Definition of read preference
73
     * @var array
74
     */
75
    private $readPreference = array();
76
77
    /**
78
     * Return result as array or as Document instance
79
     * @var boolean
80
     */
81
    private $isResultAsArray = false;
82
83
    /**
84
     * Cursor options
85
     * @var array
86
     */
87
    private $options = array(
88
        'expressionClass' => '\Sokil\Mongo\Expression',
89
        /**
90
         * @link http://docs.mongodb.org/manual/reference/method/cursor.batchSize/
91
         * @var int number of documents to return in each batch of the response from the MongoDB instance
92
         */
93
        'batchSize' => null,
94
        // client timeout
95
        'clientTimeout' => null,
96
        // Specifies a cumulative time limit in milliseconds to be allowed by the server for processing operations on the cursor.
97
        'serverTimeout' => null,
98
    );
99
100
    /**
101
     * Use document pool to create Document object from array
102
     * @var bool
103
     */
104
    private $isDocumentPoolUsed = true;
105
106
    /**
107
     * Index hinting
108
     * @param \Sokil\Mongo\Collection $collection
109
     * @param array $options
110
     */
111
    private $hint;
112
113
    public function __construct(Collection $collection, array $options = null)
114
    {
115
        $this->collection = $collection;
116
117
        $this->client = $this->collection->getDatabase()->getClient();
118
119
        if (!empty($options)) {
120
            $this->options = $options + $this->options;
121
        }
122
123
        // expression
124
        $this->expression = $this->expression();
125
    }
126
127
    public function __call($name, $arguments)
128
    {
129
        call_user_func_array(
130
            array($this->expression, $name),
131
            $arguments
132
        );
133
134
        return $this;
135
    }
136
137
    /**
138
     * Get option
139
     *
140
     * @param string|int $name
141
     * @param mixed $default
142
     *
143
     * @return mixed
144
     */
145
    public function getOption($name, $default = null)
146
    {
147
        return isset($this->options[$name]) ? $this->options[$name] : $default;
148
    }
149
150
    /**
151
     * Get result as array
152
     *
153
     * @return $this
154
     */
155
    public function asArray()
156
    {
157
        $this->isResultAsArray = true;
158
        return $this;
159
    }
160
161
    /**
162
     * Get result as object
163
     * @return $this
164
     */
165
    public function asObject()
166
    {
167
        $this->isResultAsArray = false;
168
        return $this;
169
    }
170
171
    /**
172
     * Check if result returned as array
173
     * @return bool
174
     */
175
    public function isResultAsArray()
176
    {
177
        return $this->isResultAsArray;
178
    }
179
180
    /**
181
     * Return only specified fields
182
     *
183
     * @param array $fields
184
     * @return Cursor
185
     */
186
    public function fields(array $fields)
187
    {
188
        $this->fields = array_fill_keys($fields, 1);
189
190
        $this->skipDocumentPool();
191
192
        return $this;
193
    }
194
195
    /**
196
     * Return all fields except specified
197
     *
198
     * @param array $fields
199
     * @return \Sokil\Mongo\Cursor
200
     */
201
    public function skipFields(array $fields)
202
    {
203
        $this->fields = array_fill_keys($fields, 0);
204
205
        $this->skipDocumentPool();
206
207
        return $this;
208
    }
209
210
    /**
211
     * Append field to accept list
212
     *
213
     * @param string $field field name
214
     *
215
     * @return Cursor
216
     */
217
    public function field($field)
218
    {
219
        $this->fields[$field] = 1;
220
221
        $this->skipDocumentPool();
222
223
        return $this;
224
    }
225
226
    /**
227
     * Append field to skip list
228
     *
229
     * @param string $field field name
230
     * @return Cursor
231
     */
232
    public function skipField($field)
233
    {
234
        $this->fields[$field] = 0;
235
236
        $this->skipDocumentPool();
237
238
        return $this;
239
    }
240
241
    /**
242
     * Paginate list of sub-documents
243
     *
244
     * @param string $field
245
     * @param integer $limit
246
     * @param integer $skip
247
     * @return \Sokil\Mongo\Cursor
248
     * @throws Exception
249
     */
250
    public function slice($field, $limit, $skip = null)
251
    {
252
        $limit  = (int) $limit;
253
        $skip   = (int) $skip;
254
255
        if ($skip) {
256
            $this->fields[$field] = array('$slice' => array($skip, $limit));
257
        } else {
258
            $this->fields[$field] = array('$slice' => $limit);
259
        }
260
261
        $this->skipDocumentPool();
262
263
        return $this;
264
    }
265
266
    /**
267
     * Merge expression
268
     * @param \Sokil\Mongo\Expression $expression
269
     * @return \Sokil\Mongo\Cursor
270
     */
271
    public function query(Expression $expression)
272
    {
273
        $this->expression->merge($expression);
274
        return $this;
275
    }
276
277
    /**
278
     * Helper to create new expression
279
     *
280
     * @return \Sokil\Mongo\Expression
281
     */
282
    public function expression()
283
    {
284
        return new $this->options['expressionClass'];
285
    }
286
287
    /**
288
     * Filter by list of \MongoId
289
     *
290
     * @param array $idList list of ids
291
     * @return \Sokil\Mongo\Cursor
292
     */
293
    public function byIdList(array $idList)
294
    {
295
        $this->expression->whereIn('_id', self::mixedToMongoIdList($idList));
296
        return $this;
297
    }
298
299
    /**
300
     * Filter by id
301
     *
302
     * @param string|\MongoId $id id of document
303
     * @return \Sokil\Mongo\Cursor
304
     */
305
    public function byId($id)
306
    {
307
        if ($id instanceof \MongoId) {
308
            $this->expression->where('_id', $id);
309
        } else {
310
            try {
311
                $this->expression->where('_id', new \MongoId($id));
312
            } catch (\MongoException $e) {
313
                $this->expression->where('_id', $id);
314
            }
315
        }
316
317
        return $this;
318
    }
319
320
    /**
321
     * Skip defined number of documents
322
     *
323
     * @param int $skip number of documents to skip
324
     * @return \Sokil\Mongo\Cursor
325
     */
326
    public function skip($skip)
327
    {
328
        $this->skip = (int) $skip;
329
330
        return $this;
331
    }
332
333
    /**
334
     * Limit result set to specified number of elements
335
     *
336
     * @param int $limit number of elements in result set
337
     * @param int|null $offset number of elements to skip
338
     * @return \Sokil\Mongo\Cursor
339
     */
340
    public function limit($limit, $offset = null)
341
    {
342
        $this->limit = (int) $limit;
343
344
        if (null !== $offset) {
345
            $this->skip($offset);
346
        }
347
348
        return $this;
349
    }
350
351
    /**
352
     * Specifies the number of documents to return in each batch of the response from the MongoDB instance.
353
     *
354
     * @param int $size number of documents
355
     * @link http://docs.mongodb.org/manual/reference/method/cursor.batchSize/
356
     * @return \Sokil\Mongo\Cursor
357
     */
358
    public function setBatchSize($size)
359
    {
360
        $this->options['batchSize'] = (int) $size;
361
362
        return $this;
363
    }
364
365
    /**
366
     * Instructs the driver to stop waiting for a response and throw a
367
     * MongoCursorTimeoutException after a set time.
368
     * A timeout can be set at any time and will affect subsequent queries on
369
     * the cursor, including fetching more results from the database.
370
     *
371
     * @param int $ms
372
     * @return Cursor
373
     */
374
    public function setClientTimeout($ms)
375
    {
376
        $this->options['clientTimeout'] = (int) $ms;
377
        return $this;
378
    }
379
380
    /**
381
     * Server-side timeout for a query,
382
     * Specifies a cumulative time limit in milliseconds to be allowed
383
     * by the server for processing operations on the cursor.
384
     *
385
     * @param int $ms
386
     * @return \Sokil\Mongo\Cursor
387
     */
388
    public function setServerTimeout($ms)
389
    {
390
        $this->options['serverTimeout'] = (int) $ms;
391
        return $this;
392
    }
393
394
    /**
395
     * Sort result by specified keys and directions
396
     *
397
     *  An array of fields by which to sort. Each element in the array has as key the field name, and as value either
398
     * 1 for ascending sort, or -1 for descending sort. Each result is first sorted on the first field in the array,
399
     * then (if it exists) on the second field in the array, etc. This means that the order of the fields in the
400
     * fields array is important. See also the examples section.
401
     *
402
     * @param array $sort
403
     * @return Cursor
404
     */
405
    public function sort(array $sort)
406
    {
407
        $this->sort = $sort;
408
        return $this;
409
    }
410
411
    /**
412
     *
413
     * @return \MongoCursor
414
     */
415
    private function getCursor()
416
    {
417
        if ($this->cursor) {
418
            return $this->cursor;
419
        }
420
421
        $this->cursor = $this->collection
422
            ->getMongoCollection()
423
            ->find($this->expression->toArray(), $this->fields);
424
425
        if ($this->skip) {
426
            $this->cursor->skip($this->skip);
427
        }
428
429
        if ($this->limit) {
430
            $this->cursor->limit($this->limit);
431
        }
432
433
        if ($this->options['batchSize']) {
434
            $this->cursor->batchSize($this->options['batchSize']);
435
        }
436
437
        if ($this->options['clientTimeout']) {
438
            $this->cursor->timeout($this->options['clientTimeout']);
439
        }
440
441
        if ($this->options['serverTimeout']) {
442
            $this->cursor->maxTimeMS($this->options['clientTimeout']);
443
        }
444
445
        if (!empty($this->sort)) {
446
            $this->cursor->sort($this->sort);
447
        }
448
449
        if ($this->hint) {
450
            $this->cursor->hint($this->hint);
451
        }
452
453
        // log request
454
        if ($this->client->hasLogger()) {
455
            $this->client->getLogger()->debug(get_called_class() . ': ' . json_encode(array(
456
                'collection' => $this->collection->getName(),
457
                'query' => $this->expression->toArray(),
458
                'project' => $this->fields,
459
                'sort' => $this->sort,
460
            )));
461
        }
462
463
        $this->cursor->rewind();
464
465
        // define read preferences
466
        if (!empty($this->readPreference)) {
467
            $this->cursor->setReadPreference(
468
                $this->readPreference['type'],
469
                $this->readPreference['tagsets']
470
            );
471
        }
472
473
        return $this->cursor;
474
    }
475
476
    /**
477
     * Count documents in result without applying limit and offset
478
     * @return int count
479
     */
480
    public function count()
481
    {
482
        return (int) $this->collection
483
            ->getMongoCollection()
484
            ->count($this->expression->toArray());
485
    }
486
487
    public function explain()
488
    {
489
        if (Client::isEmulationMode()) {
490
            throw new FeatureNotSupportedException('Feature not implemented in emulation mode');
491
        }
492
493
        return $this->getCursor()->explain();
494
    }
495
496
    /**
497
     * Count documents in result with applying limit and offset
498
     *
499
     * ext-mongo:1.0.7	Added limit and skip as second and third parameters, respectively.
500
     * ext-mongo:1.6.0	The second parameter is now an options array. Passing limit and skip as the second and third
501
     *                  parameters, respectively, is deprecated.
502
     *
503
     * @return int
504
     */
505
    public function limitedCount()
506
    {
507
        if (version_compare(\MongoClient::VERSION, '1.0.7', '<')) {
508
            throw new FeatureNotSupportedException('Limit and skip not supported in ext-mongo versions prior to 1.0.7');
509
        }
510
511
        return (int) $this->collection
512
            ->getMongoCollection()
513
            ->count(
514
                $this->expression->toArray(),
515
                $this->limit,
516
                $this->skip
517
            );
518
    }
519
520
521
    /**
522
     * Gte list of \MongoId of current search query
523
     * @return array
524
     */
525
    public function getIdList()
526
    {
527
        return self::mixedToMongoIdList($this->findAll());
528
    }
529
530
    /**
531
     * Find one document which correspond to expression
532
     *
533
     * @return Document|array|null
534
     *
535
     * @throws CursorException
536
     */
537
    public function findOne()
538
    {
539
        try {
540
            $mongoDocument = $this->collection
541
                ->getMongoCollection()
542
                ->findOne(
543
                    $this->expression->toArray(),
544
                    $this->fields
545
                );
546
        } catch (\Exception $e) {
547
            throw new CursorException(
548
                $e->getMessage(),
549
                $e->getCode(),
550
                $e
551
            );
552
        }
553
554
        if (empty($mongoDocument)) {
555
            return null;
556
        }
557
558
        if (true === $this->isResultAsArray) {
559
            return $mongoDocument;
560
        }
561
562
        return $this->collection->hydrate(
563
            $mongoDocument,
564
            $this->isDocumentPoolUsed()
565
        );
566
    }
567
568
    /**
569
     *
570
     * @return array result of searching
571
     */
572
    public function findAll()
573
    {
574
        return iterator_to_array($this);
575
    }
576
577
    /**
578
     * Get random document
579
     * @return
580
     */
581
    public function findRandom()
582
    {
583
        $count = $this->count();
584
585
        if (!$count) {
586
            return null;
587
        }
588
589
        if (1 === $count) {
590
            return $this->findOne();
591
        }
592
593
        return $this
594
            ->skip(mt_rand(0, $count - 1))
595
            ->limit(1)
596
            ->current();
597
    }
598
599
    /**
600
     * Get query builder's expression
601
     *
602
     * @return Expression
603
     */
604
    public function getExpression()
605
    {
606
        return $this->expression;
607
    }
608
609
    /**
610
     * Get MongoDB query array
611
     *
612
     * @return array
613
     */
614
    public function getMongoQuery()
615
    {
616
        return $this->expression->toArray();
617
    }
618
    
619
    /**
620
     * Return the values from a single field in the result set of documents
621
     *
622
     * @param string $fieldName
623
     * @return array
624
     */
625
    public function pluck($fieldName)
626
    {
627
        $isEmbeddedDocumentField = false !== strpos($fieldName, '.');
628
629
        $valueList = array();
630
631
        if ($isEmbeddedDocumentField) {
632
            // get result
633
            if ($this->isResultAsArray) {
634
                $cursor = clone $this;
635
                $documentObjectList = $cursor->asObject()->findAll();
636
                unset($cursor);
637
            } else {
638
                $documentObjectList = $this->findAll();
639
            }
640
            // get value of field
641
            foreach ($documentObjectList as $key => $documentObject) {
642
                $valueList[$key] = $documentObject->get($fieldName);
643
            }
644
        } else {
645
            // get result
646
            if ($this->isResultAsArray) {
647
                $documentArrayList = $this->findAll();
648
            } else {
649
                $cursor = clone $this;
650
                $documentArrayList = $cursor->asArray()->findAll();
651
                unset($cursor);
652
            }
653
            // get values of field
654
            $valueList = array_column($documentArrayList, $fieldName, '_id');
655
        }
656
657
        return $valueList;
658
    }
659
660
    /**
661
     * Get document instance and remove it from collection
662
     *
663
     * @return \Sokil\Mongo\Document
664
     */
665
    public function findAndRemove()
666
    {
667
        $mongoDocument = $this->collection->getMongoCollection()->findAndModify(
668
            $this->expression->toArray(),
669
            null,
670
            $this->fields,
671
            array(
672
                'remove' => true,
673
                'sort' => $this->sort,
674
            )
675
        );
676
677
        if (empty($mongoDocument)) {
678
            return null;
679
        }
680
681
        return $this->collection->hydrate(
682
            $mongoDocument,
683
            $this->isDocumentPoolUsed()
684
        );
685
    }
686
687
    /**
688
     * Find first document and update it
689
     *
690
     * @param Operator $operator operations with document to update
691
     * @param bool $upsert if document not found - create
692
     * @param bool $returnUpdated if true - return updated document
693
     *
694
     * @return null|Document
695
     */
696
    public function findAndUpdate(Operator $operator, $upsert = false, $returnUpdated = true)
697
    {
698
        $mongoDocument = $this->collection
699
            ->getMongoCollection()
700
            ->findAndModify(
701
                $this->expression->toArray(),
702
                $operator ? $operator->toArray() : null,
703
                $this->fields,
704
                array(
705
                    'new' => $returnUpdated,
706
                    'sort' => $this->sort,
707
                    'upsert' => $upsert,
708
                )
709
            );
710
711
        if (empty($mongoDocument)) {
712
            return null;
713
        }
714
715
        return $this->collection->hydrate($mongoDocument, $this->isDocumentPoolUsed());
716
    }
717
718
    /**
719
     * Apply callable to all documents in cursor
720
     *
721
     * @param callable $handler
722
     * @return array
723
     */
724 View Code Duplication
    public function map($handler)
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...
725
    {
726
        $result = array();
727
728
        foreach ($this as $id => $document) {
729
            $result[$id] = $handler($document);
730
        }
731
732
        return $result;
733
    }
734
735
    /**
736
     * Filter documents in cursor by condition in callable
737
     *
738
     * @param callable $handler
739
     * @return array
740
     */
741 View Code Duplication
    public function filter($handler)
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...
742
    {
743
        $result = array();
744
745
        foreach ($this as $id => $document) {
746
            if (!$handler($document)) {
747
                continue;
748
            }
749
750
            $result[$id] = $document;
751
        }
752
753
        return $result;
754
    }
755
756
    /**
757
     * Get result set of documents.
758
     *
759
     * @return \Sokil\Mongo\ResultSet
760
     */
761
    public function getResultSet()
762
    {
763
        return new ResultSet($this->findAll());
764
    }
765
766
    /**
767
     * Get paginator
768
     *
769
     * @param int $page page number
770
     * @param int $itemsOnPage number of items on page
771
     * @return Paginator
772
     */
773
    public function paginate($page, $itemsOnPage = 30)
774
    {
775
        $paginator = new Paginator($this);
776
777
        return $paginator
778
            ->setCurrentPage($page)
779
            ->setItemsOnPage($itemsOnPage);
780
    }
781
782
    public function current()
783
    {
784
        $mongoDocument = $this->getCursor()->current();
785
        if (empty($mongoDocument)) {
786
            return null;
787
        }
788
789
        if ($this->isResultAsArray) {
790
            return $mongoDocument;
791
        }
792
793
        return $this->collection->hydrate(
794
            $mongoDocument,
795
            $this->isDocumentPoolUsed()
796
        );
797
    }
798
799
    public function key()
800
    {
801
        return $this->getCursor()->key();
802
    }
803
804
    public function next()
805
    {
806
        $this->getCursor()->next();
807
        return $this;
808
    }
809
810
    public function rewind()
811
    {
812
        $this->getCursor()->rewind();
813
        return $this;
814
    }
815
816
    public function valid()
817
    {
818
        return $this->getCursor()->valid();
819
    }
820
821
    public function readPrimaryOnly()
822
    {
823
        $this->readPreference = array(
824
            'type'      => \MongoClient::RP_PRIMARY,
825
            'tagsets'   => array(),
826
        );
827
828
        return $this;
829
    }
830
831
    public function readPrimaryPreferred(array $tags = null)
832
    {
833
        $this->readPreference = array(
834
            'type'      => \MongoClient::RP_PRIMARY_PREFERRED,
835
            'tagsets'   => $tags,
836
        );
837
838
        return $this;
839
    }
840
841
    public function readSecondaryOnly(array $tags = null)
842
    {
843
        $this->readPreference = array(
844
            'type'      => \MongoClient::RP_SECONDARY,
845
            'tagsets'   => $tags,
846
        );
847
848
        return $this;
849
    }
850
851
    public function readSecondaryPreferred(array $tags = null)
852
    {
853
        $this->readPreference = array(
854
            'type'      => \MongoClient::RP_SECONDARY_PREFERRED,
855
            'tagsets'   => $tags,
856
        );
857
858
        return $this;
859
    }
860
861
    public function readNearest(array $tags = null)
862
    {
863
        $this->readPreference = array(
864
            'type'      => \MongoClient::RP_NEAREST,
865
            'tagsets'   => $tags,
866
        );
867
868
        return $this;
869
    }
870
871
    /**
872
     * @return array
873
     */
874
    public function getReadPreference()
875
    {
876
        if ($this->cursor) {
877
            return $this->cursor->getReadPreference();
878
        }
879
880
        return $this->readPreference;
881
    }
882
883
    public function isDocumentPoolUsed()
884
    {
885
        return $this->isDocumentPoolUsed;
886
    }
887
888
    public function useDocumentPool()
889
    {
890
        $this->isDocumentPoolUsed = true;
891
        return $this;
892
    }
893
894
    public function skipDocumentPool()
895
    {
896
        $this->isDocumentPoolUsed = false;
897
        return $this;
898
    }
899
900
    /**
901
     * Specify index to use
902
     *
903
     * @link http://docs.mongodb.org/manual/reference/operator/meta/hint/
904
     * @param array|string $specification Specify the index either by the index name or by document
905
     * @return \Sokil\Mongo\Cursor
906
     */
907
    public function hint($specification)
908
    {
909
        $this->hint = $specification;
910
        return $this;
911
    }
912
913
    /**
914
     * Copy selected documents to another collection
915
     *
916
     * @param string $targetCollectionName
917
     * @param string|null $targetDatabaseName Target database name. If not specified - use current
918
     */
919
    public function copyToCollection($targetCollectionName, $targetDatabaseName = null)
920
    {
921
        // target database
922
        if (!$targetDatabaseName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $targetDatabaseName of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
923
            $database = $this->collection->getDatabase();
924
        } else {
925
            $database = $this->client->getDatabase($targetDatabaseName);
926
        }
927
928
        // target collection
929
        $targetMongoCollection = $database
930
            ->getCollection($targetCollectionName)
931
            ->getMongoCollection();
932
933
        // cursor
934
        $cursor = $this->getCursor();
935
936
        $batchLimit = 100;
937
        $inProgress = true;
938
939
        // copy data
940
        while ($inProgress) {
941
            // get next pack of documents
942
            $documentList = array();
943
            for ($i = 0; $i < $batchLimit; $i++) {
944
                if (!$cursor->valid()) {
945
                    $inProgress = false;
946
947
                    if (!empty($documentList)) {
948
                        // still need batch insert
949
                        break;
950
                    } else {
951
                        // no documents to insert - just exit
952
                        break(2);
953
                    }
954
                }
955
956
                $documentList[] = $cursor->current();
957
                $cursor->next();
958
            }
959
960
            // insert
961
            $result = $targetMongoCollection->batchInsert($documentList);
962
963
            // check result
964 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...
965
                if ($result['ok'] != 1) {
966
                    throw new Exception('Batch insert error: ' . $result['err']);
967
                }
968
            } elseif (!$result) {
969
                throw new Exception('Batch insert error');
970
            }
971
        }
972
973
        return $this;
974
    }
975
976
    /**
977
     * Move selected documents to another collection.
978
     * Documents will be removed from source collection only after
979
     * copying them to target collection.
980
     *
981
     * @param string $targetCollectionName
982
     * @param string|null $targetDatabaseName Target database name. If not specified - use current
983
     */
984
    public function moveToCollection($targetCollectionName, $targetDatabaseName = null)
985
    {
986
        // copy to target
987
        $this->copyToCollection($targetCollectionName, $targetDatabaseName);
988
989
        // remove from source
990
        $this->collection->batchDelete($this->expression);
0 ignored issues
show
Documentation introduced by
$this->expression is of type object<Sokil\Mongo\Expression>, but the function expects a callable.

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...
991
    }
992
993
    /**
994
     * Used to get hash that uniquely identifies current query
995
     *
996
     * @return string
997
     */
998
    public function getHash()
999
    {
1000
        $hash = array();
1001
1002
        // expression
1003
        $hash[] = json_encode($this->expression->toArray());
1004
1005
        // sorts
1006 View Code Duplication
        if (!empty($this->sort)) {
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...
1007
            $sort = $this->sort;
1008
            ksort($sort);
1009
            $hash[] = implode('', array_merge(array_keys($sort), array_values($sort)));
1010
        }
1011
1012
        // fields
1013 View Code Duplication
        if (!empty($this->fields)) {
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...
1014
            $fields = $this->fields;
1015
            ksort($fields);
1016
            $hash[] = implode('', array_merge(array_keys($fields), array_values($fields)));
1017
        }
1018
1019
        // skip and limit
1020
        $hash[] = $this->skip;
1021
        $hash[] = $this->limit;
1022
1023
        // get hash
1024
        return md5(implode(':', $hash));
1025
    }
1026
1027
    /**
1028
     * Get list of MongoId objects from array of strings, MongoId's and Document's
1029
     *
1030
     * @param array $list
1031
     * @return array list of \MongoId
1032
     */
1033
    public static function mixedToMongoIdList(array $list)
1034
    {
1035
        return array_map(function ($element) {
1036
            // MongoId
1037
            if ($element instanceof \MongoId) {
1038
                return $element;
1039
            }
1040
1041
            // \Sokil\Mongo\Document
1042
            if ($element instanceof Document) {
1043
                return $element->getId();
1044
            }
1045
1046
            // array with id key
1047
            if (is_array($element)) {
1048
                if (!isset($element['_id'])) {
1049
                    throw new \InvalidArgumentException('Array must have _id key');
1050
                }
1051
                return $element['_id'];
1052
            }
1053
1054
            // string
1055
            if (is_string($element)) {
1056
                try {
1057
                    return new \MongoId($element);
1058
                } catch (\MongoException $e) {
1059
                    return $element;
1060
                }
1061
            }
1062
1063
            // int
1064
            if (is_int($element)) {
1065
                return $element;
1066
            }
1067
1068
            throw new \InvalidArgumentException('Must be \MongoId, \Sokil\Mongo\Document, array with _id key, string or integer');
1069
        }, array_values($list));
1070
    }
1071
}
1072