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 ( ca936d...4f7f40 )
by De
02:04
created

Cursor::readPrimaryOnly()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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