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
Branch master (36ec0a)
by De
04:12 queued 02:09
created

Cursor::isResultAsArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
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
     *
414
     * @return \MongoCursor
415
     */
416
    private function getCursor()
417
    {
418
        if ($this->cursor) {
419
            return $this->cursor;
420
        }
421
422
        $this->cursor = $this->collection
423
            ->getMongoCollection()
424
            ->find($this->expression->toArray(), $this->fields);
425
426
        if ($this->skip) {
427
            $this->cursor->skip($this->skip);
428
        }
429
430
        if ($this->limit) {
431
            $this->cursor->limit($this->limit);
432
        }
433
434
        if ($this->options['batchSize']) {
435
            $this->cursor->batchSize($this->options['batchSize']);
436
        }
437
438
        if ($this->options['clientTimeout']) {
439
            $this->cursor->timeout($this->options['clientTimeout']);
440
        }
441
442
        if ($this->options['serverTimeout']) {
443
            $this->cursor->maxTimeMS($this->options['clientTimeout']);
444
        }
445
446
        if (!empty($this->sort)) {
447
            $this->cursor->sort($this->sort);
448
        }
449
450
        if ($this->hint) {
451
            $this->cursor->hint($this->hint);
452
        }
453
454
        // log request
455
        if ($this->client->hasLogger()) {
456
            $this->client->getLogger()->debug(get_called_class() . ': ' . json_encode(array(
457
                'collection' => $this->collection->getName(),
458
                'query' => $this->expression->toArray(),
459
                'project' => $this->fields,
460
                'sort' => $this->sort,
461
            )));
462
        }
463
464
        $this->cursor->rewind();
465
466
        // define read preferences
467
        if (!empty($this->readPreference)) {
468
            $this->cursor->setReadPreference(
469
                $this->readPreference['type'],
470
                $this->readPreference['tagsets']
471
            );
472
        }
473
474
        return $this->cursor;
475
    }
476
477
    /**
478
     * Count documents in result without applying limit and offset
479
     * @return int count
480
     */
481
    public function count()
482
    {
483
        return (int) $this->collection
484
            ->getMongoCollection()
485
            ->count($this->expression->toArray());
486
    }
487
488
    public function explain()
489
    {
490
        if (Client::isEmulationMode()) {
491
            throw new FeatureNotSupportedException('Feature not implemented in emulation mode');
492
        }
493
494
        return $this->getCursor()->explain();
495
    }
496
497
    /**
498
     * Count documents in result with applying limit and offset
499
     *
500
     * ext-mongo:1.0.7	Added limit and skip as second and third parameters, respectively.
501
     * ext-mongo:1.6.0	The second parameter is now an options array. Passing limit and skip as the second and third
502
     *                  parameters, respectively, is deprecated.
503
     *
504
     * @return int
505
     */
506
    public function limitedCount()
507
    {
508
        if (version_compare(\MongoClient::VERSION, '1.0.7', '<')) {
509
            throw new FeatureNotSupportedException('Limit and skip not supported in ext-mongo versions prior to 1.0.7');
510
        }
511
512
        return (int) $this->collection
513
            ->getMongoCollection()
514
            ->count(
515
                $this->expression->toArray(),
516
                $this->limit,
517
                $this->skip
518
            );
519
    }
520
521
522
    /**
523
     * Gte list of \MongoId of current search query
524
     * @return array
525
     */
526
    public function getIdList()
527
    {
528
        return self::mixedToMongoIdList($this->findAll());
529
    }
530
531
    /**
532
     * Find one document which correspond to expression
533
     *
534
     * @return Document|array|null
535
     *
536
     * @throws CursorException
537
     */
538
    public function findOne()
539
    {
540
        try {
541
            $mongoDocument = $this->collection
542
                ->getMongoCollection()
543
                ->findOne(
544
                    $this->expression->toArray(),
545
                    $this->fields
546
                );
547
        } catch (\Exception $e) {
548
            throw new CursorException(
549
                $e->getMessage(),
550
                $e->getCode(),
551
                $e
552
            );
553
        }
554
555
        if (empty($mongoDocument)) {
556
            return null;
557
        }
558
559
        if (true === $this->isResultAsArray) {
560
            return $mongoDocument;
561
        }
562
563
        return $this->collection->hydrate(
564
            $mongoDocument,
565
            $this->isDocumentPoolUsed()
566
        );
567
    }
568
569
    /**
570
     *
571
     * @return array result of searching
572
     */
573
    public function findAll()
574
    {
575
        return iterator_to_array($this);
576
    }
577
578
    /**
579
     * Get random document
580
     * @return
581
     */
582
    public function findRandom()
583
    {
584
        $count = $this->count();
585
586
        if (!$count) {
587
            return null;
588
        }
589
590
        if (1 === $count) {
591
            return $this->findOne();
592
        }
593
594
        return $this
595
            ->skip(mt_rand(0, $count - 1))
596
            ->limit(1)
597
            ->current();
598
    }
599
600
    /**
601
     * Get query builder's expression
602
     *
603
     * @return Expression
604
     */
605
    public function getExpression()
606
    {
607
        return $this->expression;
608
    }
609
610
    /**
611
     * Get MongoDB query array
612
     *
613
     * @return array
614
     */
615
    public function getMongoQuery()
616
    {
617
        return $this->expression->toArray();
618
    }
619
    
620
    /**
621
     * Return the values from a single field in the result set of documents
622
     *
623
     * @param string $fieldName
624
     * @return array
625
     */
626
    public function pluck($fieldName)
627
    {
628
        $isEmbeddedDocumentField = false !== strpos($fieldName, '.');
629
630
        $valueList = array();
631
632
        if ($isEmbeddedDocumentField) {
633
            // get result
634
            if ($this->isResultAsArray) {
635
                $cursor = clone $this;
636
                $documentObjectList = $cursor->asObject()->findAll();
637
                unset($cursor);
638
            } else {
639
                $documentObjectList = $this->findAll();
640
            }
641
            // get value of field
642
            foreach ($documentObjectList as $key => $documentObject) {
643
                $valueList[$key] = $documentObject->get($fieldName);
644
            }
645
        } else {
646
            // get result
647
            if ($this->isResultAsArray) {
648
                $documentArrayList = $this->findAll();
649
            } else {
650
                $cursor = clone $this;
651
                $documentArrayList = $cursor->asArray()->findAll();
652
                unset($cursor);
653
            }
654
            // get values of field
655
            $valueList = array_column($documentArrayList, $fieldName, '_id');
656
        }
657
658
        return $valueList;
659
    }
660
661
    /**
662
     * Get document instance and remove it from collection
663
     *
664
     * @return \Sokil\Mongo\Document
665
     */
666
    public function findAndRemove()
667
    {
668
        $mongoDocument = $this->collection->getMongoCollection()->findAndModify(
669
            $this->expression->toArray(),
670
            null,
671
            $this->fields,
672
            array(
673
                'remove' => true,
674
                'sort' => $this->sort,
675
            )
676
        );
677
678
        if (empty($mongoDocument)) {
679
            return null;
680
        }
681
682
        return $this->collection->hydrate(
683
            $mongoDocument,
684
            $this->isDocumentPoolUsed()
685
        );
686
    }
687
688
    /**
689
     * Find first document and update it
690
     *
691
     * @param Operator $operator operations with document to update
692
     * @param bool $upsert if document not found - create
693
     * @param bool $returnUpdated if true - return updated document
694
     *
695
     * @return null|Document
696
     */
697
    public function findAndUpdate(Operator $operator, $upsert = false, $returnUpdated = true)
698
    {
699
        $mongoDocument = $this->collection
700
            ->getMongoCollection()
701
            ->findAndModify(
702
                $this->expression->toArray(),
703
                $operator ? $operator->toArray() : null,
704
                $this->fields,
705
                array(
706
                    'new' => $returnUpdated,
707
                    'sort' => $this->sort,
708
                    'upsert' => $upsert,
709
                )
710
            );
711
712
        if (empty($mongoDocument)) {
713
            return null;
714
        }
715
716
        return $this->collection->hydrate($mongoDocument, $this->isDocumentPoolUsed());
717
    }
718
719
    /**
720
     * Apply callable to all documents in cursor
721
     *
722
     * @param callable $handler
723
     * @return array
724
     */
725 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...
726
    {
727
        $result = array();
728
729
        foreach ($this as $id => $document) {
730
            $result[$id] = $handler($document);
731
        }
732
733
        return $result;
734
    }
735
736
    /**
737
     * Filter documents in cursor by condition in callable
738
     *
739
     * @param callable $handler
740
     * @return array
741
     */
742 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...
743
    {
744
        $result = array();
745
746
        foreach ($this as $id => $document) {
747
            if (!$handler($document)) {
748
                continue;
749
            }
750
751
            $result[$id] = $document;
752
        }
753
754
        return $result;
755
    }
756
757
    /**
758
     * Get result set of documents.
759
     *
760
     * @return \Sokil\Mongo\ResultSet
761
     */
762
    public function getResultSet()
763
    {
764
        return new ResultSet($this->findAll());
765
    }
766
767
    /**
768
     * Get paginator
769
     *
770
     * @param int $page page number
771
     * @param int $itemsOnPage number of items on page
772
     * @return Paginator
773
     */
774
    public function paginate($page, $itemsOnPage = 30)
775
    {
776
        $paginator = new Paginator($this);
777
778
        return $paginator
779
            ->setCurrentPage($page)
780
            ->setItemsOnPage($itemsOnPage);
781
    }
782
783
    public function current()
784
    {
785
        $mongoDocument = $this->getCursor()->current();
786
        if (empty($mongoDocument)) {
787
            return null;
788
        }
789
790
        if ($this->isResultAsArray) {
791
            return $mongoDocument;
792
        }
793
794
        return $this->collection->hydrate(
795
            $mongoDocument,
796
            $this->isDocumentPoolUsed()
797
        );
798
    }
799
800
    public function key()
801
    {
802
        return $this->getCursor()->key();
803
    }
804
805
    public function next()
806
    {
807
        $this->getCursor()->next();
808
        return $this;
809
    }
810
811
    public function rewind()
812
    {
813
        $this->getCursor()->rewind();
814
        return $this;
815
    }
816
817
    public function valid()
818
    {
819
        return $this->getCursor()->valid();
820
    }
821
822
    public function readPrimaryOnly()
823
    {
824
        $this->readPreference = array(
825
            'type'      => \MongoClient::RP_PRIMARY,
826
            'tagsets'   => array(),
827
        );
828
829
        return $this;
830
    }
831
832
    public function readPrimaryPreferred(array $tags = null)
833
    {
834
        $this->readPreference = array(
835
            'type'      => \MongoClient::RP_PRIMARY_PREFERRED,
836
            'tagsets'   => $tags,
837
        );
838
839
        return $this;
840
    }
841
842
    public function readSecondaryOnly(array $tags = null)
843
    {
844
        $this->readPreference = array(
845
            'type'      => \MongoClient::RP_SECONDARY,
846
            'tagsets'   => $tags,
847
        );
848
849
        return $this;
850
    }
851
852
    public function readSecondaryPreferred(array $tags = null)
853
    {
854
        $this->readPreference = array(
855
            'type'      => \MongoClient::RP_SECONDARY_PREFERRED,
856
            'tagsets'   => $tags,
857
        );
858
859
        return $this;
860
    }
861
862
    public function readNearest(array $tags = null)
863
    {
864
        $this->readPreference = array(
865
            'type'      => \MongoClient::RP_NEAREST,
866
            'tagsets'   => $tags,
867
        );
868
869
        return $this;
870
    }
871
872
    /**
873
     * @return array
874
     */
875
    public function getReadPreference()
876
    {
877
        if ($this->cursor) {
878
            return $this->cursor->getReadPreference();
879
        }
880
881
        return $this->readPreference;
882
    }
883
884
    public function isDocumentPoolUsed()
885
    {
886
        return $this->isDocumentPoolUsed;
887
    }
888
889
    public function useDocumentPool()
890
    {
891
        $this->isDocumentPoolUsed = true;
892
        return $this;
893
    }
894
895
    public function skipDocumentPool()
896
    {
897
        $this->isDocumentPoolUsed = false;
898
        return $this;
899
    }
900
901
    /**
902
     * Specify index to use
903
     *
904
     * @link http://docs.mongodb.org/manual/reference/operator/meta/hint/
905
     * @param array|string $specification Specify the index either by the index name or by document
906
     * @return \Sokil\Mongo\Cursor
907
     */
908
    public function hint($specification)
909
    {
910
        $this->hint = $specification;
911
        return $this;
912
    }
913
914
    /**
915
     * Copy selected documents to another collection
916
     *
917
     * @param string $targetCollectionName
918
     * @param string|null $targetDatabaseName Target database name. If not specified - use current
919
     *
920
     * @return Cursor
921
     *
922
     * @throws WriteException
923
     */
924
    public function copyToCollection($targetCollectionName, $targetDatabaseName = null)
925
    {
926
        // target database
927
        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...
928
            $database = $this->collection->getDatabase();
929
        } else {
930
            $database = $this->client->getDatabase($targetDatabaseName);
931
        }
932
933
        // target collection
934
        $targetMongoCollection = $database
935
            ->getCollection($targetCollectionName)
936
            ->getMongoCollection();
937
938
        // cursor
939
        $cursor = $this->getCursor();
940
941
        $batchLimit = 100;
942
        $inProgress = true;
943
944
        // copy data
945
        while ($inProgress) {
946
            // get next pack of documents
947
            $documentList = array();
948
            for ($i = 0; $i < $batchLimit; $i++) {
949
                if (!$cursor->valid()) {
950
                    $inProgress = false;
951
952
                    if (!empty($documentList)) {
953
                        // still need batch insert
954
                        break;
955
                    } else {
956
                        // no documents to insert - just exit
957
                        break(2);
958
                    }
959
                }
960
961
                $documentList[] = $cursor->current();
962
                $cursor->next();
963
            }
964
965
            // insert
966
            $result = $targetMongoCollection->batchInsert($documentList);
967
968
            // With passed write concern, returns an associative array with the status of the inserts ("ok")
969
            // and any error that may have occurred ("err").
970
            // Otherwise, returns TRUE if the batch insert was successfully sent, FALSE otherwise.
971
            if (is_array($result)) {
972
                if ($result['ok'] != 1) {
973
                    throw new WriteException('Batch insert error: ' . $result['err']);
974
                }
975
            } elseif (false === $result) {
976
                throw new WriteException('Batch insert error');
977
            }
978
        }
979
980
        return $this;
981
    }
982
983
    /**
984
     * Move selected documents to another collection.
985
     * Documents will be removed from source collection only after
986
     * copying them to target collection.
987
     *
988
     * @param string $targetCollectionName
989
     * @param string|null $targetDatabaseName Target database name. If not specified - use current
990
     */
991
    public function moveToCollection($targetCollectionName, $targetDatabaseName = null)
992
    {
993
        // copy to target
994
        $this->copyToCollection($targetCollectionName, $targetDatabaseName);
995
996
        // remove from source
997
        $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...
998
    }
999
1000
    /**
1001
     * Used to get hash that uniquely identifies current query
1002
     *
1003
     * @return string
1004
     */
1005
    public function getHash()
1006
    {
1007
        $hash = array();
1008
1009
        // expression
1010
        $hash[] = json_encode($this->expression->toArray());
1011
1012
        // sorts
1013 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...
1014
            $sort = $this->sort;
1015
            ksort($sort);
1016
            $hash[] = implode('', array_merge(array_keys($sort), array_values($sort)));
1017
        }
1018
1019
        // fields
1020 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...
1021
            $fields = $this->fields;
1022
            ksort($fields);
1023
            $hash[] = implode('', array_merge(array_keys($fields), array_values($fields)));
1024
        }
1025
1026
        // skip and limit
1027
        $hash[] = $this->skip;
1028
        $hash[] = $this->limit;
1029
1030
        // get hash
1031
        return md5(implode(':', $hash));
1032
    }
1033
1034
    /**
1035
     * Get list of MongoId objects from array of strings, MongoId's and Document's
1036
     *
1037
     * @param array $list
1038
     * @return array list of \MongoId
1039
     */
1040
    public static function mixedToMongoIdList(array $list)
1041
    {
1042
        return array_map(function ($element) {
1043
            // MongoId
1044
            if ($element instanceof \MongoId) {
1045
                return $element;
1046
            }
1047
1048
            // \Sokil\Mongo\Document
1049
            if ($element instanceof Document) {
1050
                return $element->getId();
1051
            }
1052
1053
            // array with id key
1054
            if (is_array($element)) {
1055
                if (!isset($element['_id'])) {
1056
                    throw new \InvalidArgumentException('Array must have _id key');
1057
                }
1058
                return $element['_id'];
1059
            }
1060
1061
            // string
1062
            if (is_string($element)) {
1063
                try {
1064
                    return new \MongoId($element);
1065
                } catch (\MongoException $e) {
1066
                    return $element;
1067
                }
1068
            }
1069
1070
            // int
1071
            if (is_int($element)) {
1072
                return $element;
1073
            }
1074
1075
            throw new \InvalidArgumentException('Must be \MongoId, \Sokil\Mongo\Document, array with _id key, string or integer');
1076
        }, array_values($list));
1077
    }
1078
}
1079