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 ( f6151a...357aa0 )
by De
02:51
created

Cursor::byIdList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 5
rs 9.4285
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
class Cursor implements \Iterator, \Countable
15
{
16
    /**
17
     *
18
     * @var \Sokil\Mongo\Client
19
     */
20
    private $client;
21
22
    /**
23
     *
24
     * @var \Sokil\Mongo\Collection
25
     */
26
    private $collection;
27
28
    /**
29
     *
30
     * @var array
31
     */
32
    private $fields = array();
33
34
    /**
35
     *
36
     * @var \MongoCursor
37
     */
38
    private $cursor;
39
    /**
40
     *
41
     * @var \Sokil\Mongo\Expression
42
     */
43
    private $expression;
44
45
    private $skip = 0;
46
47
    private $limit = 0;
48
49
50
    private $sort = array();
51
52
    private $readPreference = array();
53
54
    /**
55
     * Return result as array or as Document instance
56
     * @var boolean 
57
     */
58
    private $resultAsArray = false;
59
60
    /**
61
     * Cursor options
62
     * @var array
63
     */
64
    private $options = array(
65
        'expressionClass' => '\Sokil\Mongo\Expression',
66
        /**
67
         * @link http://docs.mongodb.org/manual/reference/method/cursor.batchSize/
68
         * @var int number of documents to return in each batch of the response from the MongoDB instance
69
         */
70
        'batchSize' => null,
71
        // client timeout
72
        'clientTimeout' => null,
73
        // Specifies a cumulative time limit in milliseconds to be allowed by the server for processing operations on the cursor.
74
        'serverTimeout' => null,
75
    );
76
77
    /**
78
     * Use document pool to create Document object from array
79
     * @var bool
80
     */
81
    private $isDocumentPoolUsed = true;
82
83
    /**
84
     * Index hinting
85
     * @param \Sokil\Mongo\Collection $collection
86
     * @param array $options
87
     */
88
    private $hint;
89
90
    public function __construct(Collection $collection, array $options = null)
91
    {
92
        $this->collection = $collection;
93
94
        $this->client = $this->collection->getDatabase()->getClient();
95
96
        if ($options) {
97
            $this->options = $options + $this->options;
98
        }
99
100
        // expression
101
        $this->expression = $this->expression();
102
    }
103
104
    public function __call($name, $arguments)
105
    {
106
        call_user_func_array(array($this->expression, $name), $arguments);
107
        return $this;
108
    }
109
110
    /**
111
     * Get option
112
     *
113
     * @param string|int $name
114
     * @return mixed
115
     */
116
    public function getOption($name, $default = null)
117
    {
118
        return isset($this->options[$name]) ? $this->options[$name] : $default;
119
    }
120
121
    public function asArray()
122
    {
123
        $this->resultAsArray = true;
124
        return $this;
125
    }
126
127
    public function asObject()
128
    {
129
        $this->resultAsArray = false;
130
        return $this;
131
    }
132
133
    /**
134
     * Check if result returned as array
135
     *
136
     * @return bool
137
     */
138
    public function isResultAsArray()
139
    {
140
        return $this->resultAsArray;
141
    }
142
143
    /**
144
     * Return only specified fields
145
     *
146
     * @param array $fields
147
     * @return \Sokil\Mongo\Cursor
148
     */
149
    public function fields(array $fields)
150
    {
151
        $this->fields = array_fill_keys($fields, 1);
152
153
        $this->skipDocumentPool();
154
155
        return $this;
156
    }
157
158
    /**
159
     * Return all fields except specified
160
     *
161
     * @param array $fields
162
     * @return \Sokil\Mongo\Cursor
163
     */
164
    public function skipFields(array $fields)
165
    {
166
        $this->fields = array_fill_keys($fields, 0);
167
168
        $this->skipDocumentPool();
169
170
        return $this;
171
    }
172
173
    /**
174
     * Append field to accept list
175
     *
176
     * @param string $field field name
177
     * @return \Sokil\Mongo\Cursor
178
     */
179
    public function field($field)
180
    {
181
        $this->fields[$field] = 1;
182
183
        $this->skipDocumentPool();
184
185
        return $this;
186
    }
187
188
    /**
189
     * Append field to skip list
190
     *
191
     * @param string $field field name
192
     * @return \Sokil\Mongo\Cursor
193
     */
194
    public function skipField($field)
195
    {
196
        $this->fields[$field] = 0;
197
198
        $this->skipDocumentPool();
199
200
        return $this;
201
    }
202
203
    /**
204
     * Paginate list of sub-documents
205
     *
206
     * @param string $field
207
     * @param integer $limit
208
     * @param integer $skip
209
     * @return \Sokil\Mongo\Cursor
210
     * @throws Exception
211
     */
212
    public function slice($field, $limit, $skip = null)
213
    {
214
        $limit  = (int) $limit;
215
        $skip   = (int) $skip;
216
217
        if($skip) {
218
            $this->fields[$field] = array('$slice' => array($skip, $limit));
219
        }
220
        else {
221
            $this->fields[$field] = array('$slice' => $limit);
222
        }
223
224
        $this->skipDocumentPool();
225
226
        return $this;
227
    }
228
229
    /**
230
     * Merge expression
231
     * @param \Sokil\Mongo\Expression $expression
232
     * @return \Sokil\Mongo\Cursor
233
     */
234
    public function query(Expression $expression)
235
    {
236
        $this->expression->merge($expression);
237
        return $this;
238
    }
239
240
    /**
241
     * Helper to create new expression
242
     *
243
     * @return \Sokil\Mongo\Expression
244
     */
245
    public function expression()
246
    {
247
        return new $this->options['expressionClass'];
248
    }
249
250
    /**
251
     * Filter by list of \MongoId
252
     *
253
     * @param array $idList list of ids
254
     * @return \Sokil\Mongo\Cursor
255
     */
256
    public function byIdList(array $idList)
257
    {
258
        $this->expression->whereIn('_id', self::mixedToMongoIdList($idList));
259
        return $this;
260
    }
261
262
    /**
263
     * Filter by id
264
     *
265
     * @param string|\MongoId $id id of document
266
     * @return \Sokil\Mongo\Cursor
267
     */
268
    public function byId($id)
269
    {
270
        if($id instanceof \MongoId) {
271
            $this->expression->where('_id', $id);
272
        } else {
273
            try {
274
                $this->expression->where('_id', new \MongoId($id));
275
            } catch (\MongoException $e) {
276
                $this->expression->where('_id', $id);
277
            }
278
        }
279
280
        return $this;
281
    }
282
283
    /**
284
     * Skip defined number of documents
285
     *
286
     * @param int $skip number of documents to skip
287
     * @return \Sokil\Mongo\Cursor
288
     */
289
    public function skip($skip)
290
    {
291
        $this->skip = (int) $skip;
292
293
        return $this;
294
    }
295
296
    /**
297
     * Limit result set to specified number of elements
298
     *
299
     * @param int $limit number of elements in result set
300
     * @param int|null $offset number of elements to skip
301
     * @return \Sokil\Mongo\Cursor
302
     */
303
    public function limit($limit, $offset = null)
304
    {
305
        $this->limit = (int) $limit;
306
307
        if(null !== $offset) {
308
            $this->skip($offset);
309
        }
310
311
        return $this;
312
    }
313
314
    /**
315
     * Specifies the number of documents to return in each batch of the response from the MongoDB instance.
316
     *
317
     * @param int $size number of documents
318
     * @link http://docs.mongodb.org/manual/reference/method/cursor.batchSize/
319
     * @return \Sokil\Mongo\Cursor
320
     */
321
    public function setBatchSize($size)
322
    {
323
        $this->options['batchSize'] = (int) $size;
324
325
        return $this;
326
    }
327
328
    /**
329
     * Instructs the driver to stop waiting for a response and throw a
330
     * MongoCursorTimeoutException after a set time,
331
     * A timeout can be set at any time and will affect subsequent queries on
332
     * the cursor, including fetching more results from the database.
333
     * @param type $ms
334
     * @return \Sokil\Mongo\Cursor
335
     */
336
    public function setClientTimeout($ms)
337
    {
338
        $this->options['clientTimeout'] = (int) $ms;
339
340
        return $this;
341
    }
342
343
    /**
344
     * Server-side timeout for a query,
345
     * Specifies a cumulative time limit in milliseconds to be allowed
346
     * by the server for processing operations on the cursor.
347
     * @param type $ms
348
     * @return \Sokil\Mongo\Cursor
349
     */
350
    public function setServerTimeout($ms)
351
    {
352
        $this->options['serverTimeout'] = (int) $ms;
353
354
        return $this;
355
    }
356
357
    /**
358
     * Sort result by specified keys and directions
359
     *
360
     *  An array of fields by which to sort. Each element in the array has as key the field name, and as value either
361
     * 1 for ascending sort, or -1 for descending sort. Each result is first sorted on the first field in the array,
362
     * then (if it exists) on the second field in the array, etc. This means that the order of the fields in the
363
     * fields array is important. See also the examples section.
364
     *
365
     * @param array $sort
366
     * @return \Sokil\Mongo\Cursor
367
     */
368
    public function sort(array $sort)
369
    {
370
        $this->sort = $sort;
371
372
        return $this;
373
    }
374
375
    /**
376
     *
377
     * @return \MongoCursor
378
     */
379
    private function getCursor()
380
    {
381
        if($this->cursor) {
382
            return $this->cursor;
383
        }
384
385
        $this->cursor = $this->collection
386
            ->getMongoCollection()
387
            ->find($this->expression->toArray(), $this->fields);
388
389
        if($this->skip) {
390
            $this->cursor->skip($this->skip);
391
        }
392
393
        if($this->limit) {
394
            $this->cursor->limit($this->limit);
395
        }
396
397
        if($this->options['batchSize']) {
398
            $this->cursor->batchSize($this->options['batchSize']);
399
        }
400
401
        if($this->options['clientTimeout']) {
402
            $this->cursor->timeout($this->options['clientTimeout']);
403
        }
404
405
        if($this->options['serverTimeout']) {
406
            $this->cursor->maxTimeMS($this->options['clientTimeout']);
407
        }
408
409
        if($this->sort) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->sort of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
410
            $this->cursor->sort($this->sort);
411
        }
412
413
        if($this->hint) {
414
            $this->cursor->hint($this->hint);
415
        }
416
417
        // log request
418
        if($this->client->hasLogger()) {
419
            $this->client->getLogger()->debug(get_called_class() . ': ' . json_encode(array(
420
                'collection'    => $this->collection->getName(),
421
                'query'         => $this->expression->toArray(),
422
                'project'       => $this->fields,
423
                'sort'          => $this->sort,
424
            )));
425
        }
426
427
        $this->cursor->rewind();
428
429
        // define read preferences
430
        if($this->readPreference) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->readPreference of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
431
            $this->cursor->setReadPreference(
432
                $this->readPreference['type'],
433
                $this->readPreference['tagsets']
434
            );
435
        }
436
437
        return $this->cursor;
438
    }
439
440
    /**
441
     * Count documents in result without applying limit and offset
442
     * @return int count
443
     */
444
    public function count()
445
    {
446
        return (int) $this->collection
447
            ->getMongoCollection()
448
            ->count($this->expression->toArray());
449
    }
450
451
    public function explain()
452
    {
453
        return $this->getCursor()->explain();
454
    }
455
456
    /**
457
     * Count documents in result with applying limit and offset
458
     * @return int count
459
     */
460
    public function limitedCount()
461
    {
462
        return (int) $this->collection
463
            ->getMongoCollection()
464
            ->count($this->expression->toArray(), $this->limit, $this->skip);
465
    }
466
467
468
    /**
469
     * Gte list of \MongoId of current search query
470
     * @return array
471
     */
472
    public function getIdList()
473
    {
474
        return self::mixedToMongoIdList($this->findAll());
475
    }
476
477
    /**
478
     * Find one document which correspond to expression
479
     * 
480
     * @return \Sokil\Mongo\Document|array|null
481
     */
482
    public function findOne()
483
    {
484
        $mongoDocument = $this->collection
485
            ->getMongoCollection()
486
            ->findOne($this->expression->toArray(), $this->fields);
487
488
        if (null === $mongoDocument) {
489
            return null;
490
        }
491
492
        if (true === $this->resultAsArray) {
493
            return $mongoDocument;
494
        }
495
496
        return $this->collection->hydrate($mongoDocument, $this->isDocumentPoolUsed());
497
    }
498
499
    /**
500
     *
501
     * @return array result of searching
502
     */
503
    public function findAll()
504
    {
505
        return iterator_to_array($this);
506
    }
507
508
    /**
509
     * Get random document
510
     * @return
511
     */
512
    public function findRandom()
513
    {
514
        $count = $this->count();
515
516
        if(!$count) {
517
            return null;
518
        }
519
520
        if(1 === $count) {
521
            return $this->findOne();
522
        }
523
524
        return $this
525
            ->skip(mt_rand(0, $count - 1))
526
            ->limit(1)
527
            ->current();
528
    }
529
530
    /**
531
     * Get query builder's expression
532
     *
533
     * @return Expression
534
     */
535
    public function getExpression()
536
    {
537
        return $this->expression;
538
    }
539
540
    /**
541
     * Get MongoDB query array
542
     * 
543
     * @return array
544
     */
545
    public function getMongoQuery()
546
    {
547
        return $this->expression->toArray();
548
    }
549
    
550
    /**
551
     * Return the values from a single field in the result set of documents
552
     *
553
     * @param string $fieldName
554
     * @return array
555
     */
556
    public function pluck($fieldName)
557
    {
558
        // use native php function if field without subdocument
559
        if(false === strpos($fieldName, '.') && function_exists('array_column')) {
560 View Code Duplication
            if($this->isResultAsArray()) {
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...
561
                $result = $this->findAll();
562
            } else {
563
                $cursor = clone $this;
564
                $result = $cursor->asArray()->findAll();
565
                unset($cursor);
566
            }
567
568
            return array_column($result, $fieldName, '_id');
569
        }
570
571
        // if field with subdocument or native php function not exists
572
        return $this->pluckDotNoteted($fieldName);
573
    }
574
575
    /**
576
     * Pluck by dot-notated field name
577
     * 
578
     * @param string $fieldName field name
579
     * @return array
580
     */
581
    private function pluckDotNoteted($fieldName)
582
    {
583 View Code Duplication
        if($this->isResultAsArray()) {
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...
584
            $cursor = clone $this;
585
            $result = $cursor->asObject()->findAll();
586
            unset($cursor);
587
        } else {
588
            $result = $this->findAll();
589
        }
590
591
        $list = array();
592
        foreach($result as $key => $document) {
593
            $list[$key] = $document->get($fieldName);
594
        }
595
596
        return $list;
597
    }
598
599
    /**
600
     * Get document instance and remove it from collection
601
     *
602
     * @return \Sokil\Mongo\Document
603
     */
604
    public function findAndRemove()
605
    {
606
        $mongoDocument = $this->collection->getMongoCollection()->findAndModify(
607
            $this->expression->toArray(),
608
            null,
609
            $this->fields,
610
            array(
611
                'remove'    => true,
612
                'sort'      => $this->sort,
613
            )
614
        );
615
616
        if(!$mongoDocument) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mongoDocument of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
617
            return null;
618
        }
619
620
        return $this->collection->hydrate($mongoDocument, $this->isDocumentPoolUsed());
621
    }
622
623
    /**
624
     * Find first document and update it
625
     *
626
     * @param Operator $operator operations with document to update
627
     * @param bool $upsert if document not found - create
628
     * @param bool $returnUpdated if true - return updated document
629
     *
630
     * @return null|Document
631
     */
632
    public function findAndUpdate(Operator $operator, $upsert = false, $returnUpdated = true)
633
    {
634
        $mongoDocument = $this->collection
635
            ->getMongoCollection()
636
            ->findAndModify(
637
                $this->expression->toArray(),
638
                $operator ? $operator->toArray() : null,
639
                $this->fields,
640
                array(
641
                    'new'       => $returnUpdated,
642
                    'sort'      => $this->sort,
643
                    'upsert'    => $upsert,
644
                )
645
            );
646
647
        if(!$mongoDocument) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mongoDocument of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
648
            return null;
649
        }
650
651
        return $this->collection->hydrate($mongoDocument, $this->isDocumentPoolUsed());
652
    }
653
654 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...
655
    {
656
        $result = array();
657
658
        foreach($this as $id => $document) {
659
            $result[$id] = $handler($document);
660
        }
661
662
        return $result;
663
    }
664
665 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...
666
    {
667
        $result = array();
668
669
        foreach($this as $id => $document) {
670
            if(!$handler($document)) {
671
                continue;
672
            }
673
674
            $result[$id] = $document;
675
        }
676
677
        return $result;
678
    }
679
680
    /**
681
     * Get result set of documents.
682
     * 
683
     * @return \Sokil\Mongo\ResultSet
684
     */
685
    public function getResultSet()
686
    {
687
        return new ResultSet($this->findAll());
688
    }
689
690
    /**
691
     * Get paginator
692
     *
693
     * @param int $page page number
694
     * @param int $itemsOnPage number of items on page
695
     * @return \Sokil\Mongo\Paginator
696
     */
697
    public function paginate($page, $itemsOnPage = 30)
698
    {
699
        $paginator = new Paginator($this);
700
701
        return $paginator
702
            ->setCurrentPage($page)
703
            ->setItemsOnPage($itemsOnPage);
704
705
    }
706
707
    public function current()
708
    {
709
        $mongoDocument = $this->getCursor()->current();
710
        if(!$mongoDocument) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mongoDocument of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
711
            return null;
712
        }
713
714
        if($this->resultAsArray) {
715
            return $mongoDocument;
716
        }
717
718
        return $this->collection->hydrate($mongoDocument, $this->isDocumentPoolUsed());
719
    }
720
721
    public function key()
722
    {
723
        return $this->getCursor()->key();
724
    }
725
726
    public function next()
727
    {
728
        $this->getCursor()->next();
729
        return $this;
730
    }
731
732
    public function rewind()
733
    {
734
        $this->getCursor()->rewind();
735
        return $this;
736
    }
737
738
    public function valid()
739
    {
740
        return $this->getCursor()->valid();
741
    }
742
743
    public function readPrimaryOnly()
744
    {
745
        $this->readPreference = array(
746
            'type'      => \MongoClient::RP_PRIMARY,
747
            'tagsets'   => array(),
748
        );
749
750
        return $this;
751
    }
752
753
    public function readPrimaryPreferred(array $tags = null)
754
    {
755
        $this->readPreference = array(
756
            'type'      => \MongoClient::RP_PRIMARY_PREFERRED,
757
            'tagsets'   => $tags,
758
        );
759
760
        return $this;
761
    }
762
763
    public function readSecondaryOnly(array $tags = null)
764
    {
765
        $this->readPreference = array(
766
            'type'      => \MongoClient::RP_SECONDARY,
767
            'tagsets'   => $tags,
768
        );
769
770
        return $this;
771
    }
772
773
    public function readSecondaryPreferred(array $tags = null)
774
    {
775
        $this->readPreference = array(
776
            'type'      => \MongoClient::RP_SECONDARY_PREFERRED,
777
            'tagsets'   => $tags,
778
        );
779
780
        return $this;
781
    }
782
783
    public function readNearest(array $tags = null)
784
    {
785
        $this->readPreference = array(
786
            'type'      => \MongoClient::RP_NEAREST,
787
            'tagsets'   => $tags,
788
        );
789
790
        return $this;
791
    }
792
793
    public function getReadPreference()
794
    {
795
        if($this->cursor) {
796
            return $this->cursor->getReadPreference();
797
        }
798
799
        return $this->readPreference;
800
    }
801
802
    public function isDocumentPoolUsed()
803
    {
804
        return $this->isDocumentPoolUsed;
805
    }
806
807
    public function useDocumentPool()
808
    {
809
        $this->isDocumentPoolUsed = true;
810
        return $this;
811
    }
812
813
    public function skipDocumentPool()
814
    {
815
        $this->isDocumentPoolUsed = false;
816
        return $this;
817
    }
818
819
    /**
820
     * Specify index to use
821
     *
822
     * @link http://docs.mongodb.org/manual/reference/operator/meta/hint/
823
     * @param array|string $specification Specify the index either by the index name or by document
824
     * @return \Sokil\Mongo\Cursor
825
     */
826
    public function hint($specification)
827
    {
828
        $this->hint = $specification;
829
        return $this;
830
    }
831
832
    /**
833
     * Copy selected documents to another collection
834
     *
835
     * @param type $targetCollectionName
836
     * @param type $targetDatabaseName Target database name. If not specified - use current
837
     */
838
    public function copyToCollection($targetCollectionName, $targetDatabaseName = null)
839
    {
840
        // target database
841
        if(!$targetDatabaseName) {
842
            $database = $this->collection->getDatabase();
843
        } else {
844
            $database = $this->client->getDatabase($targetDatabaseName);
845
        }
846
847
        // target collection
848
        $targetMongoCollection = $database
849
            ->getCollection($targetCollectionName)
850
            ->getMongoCollection();
851
852
        // cursor
853
        $cursor = $this->getCursor();
854
855
        $batchLimit = 100;
856
        $inProgress = true;
857
858
        // copy data
859
        while($inProgress) {
860
            // get next pack of documents
861
            $documentList = array();
862
            for($i = 0; $i < $batchLimit; $i++) {
863
                if(!$cursor->valid()) {
864
                    $inProgress = false;
865
866
                    if($documentList) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $documentList of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
867
                        // still need batch insert
868
                        break;
869
                    } else {
870
                        // no documents to insert - just exit
871
                        break(2);
872
                    }
873
                }
874
875
                $documentList[] = $cursor->current();
876
                $cursor->next();
877
            }
878
879
            // insert
880
            $result = $targetMongoCollection->batchInsert($documentList);
881
882
            // check result
883 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...
884
                if($result['ok'] != 1) {
885
                    throw new Exception('Batch insert error: ' . $result['err']);
886
                }
887
            } elseif(!$result) {
888
                throw new Exception('Batch insert error');
889
            }
890
        }
891
892
        return $this;
893
    }
894
895
    /**
896
     * Move selected documents to another collection.
897
     * Dociuments will be removed from source collection only after
898
     * copying them to target collection.
899
     *
900
     * @param type $targetCollectionName
901
     * @param type $targetDatabaseName Target database name. If not specified - use current
902
     */
903
    public function moveToCollection($targetCollectionName, $targetDatabaseName = null)
904
    {
905
        // copy to target
906
        $this->copyToCollection($targetCollectionName, $targetDatabaseName);
907
908
        // remove from source
909
        $this->collection->deleteDocuments($this->expression);
0 ignored issues
show
Documentation introduced by
$this->expression is of type object<Sokil\Mongo\Expression>, but the function expects a array.

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...
Deprecated Code introduced by
The method Sokil\Mongo\Collection::deleteDocuments() has been deprecated with message: since 1.13. Use Collection::batchDelete();

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

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

Loading history...
910
    }
911
912
    /**
913
     * Used to get hash that uniquely identifies current query
914
     */
915
    public function getHash()
916
    {
917
        $hash = array();
918
919
        // expression
920
        $hash[] = json_encode($this->expression->toArray());
921
922
        // sorts
923 View Code Duplication
        if($this->sort) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->sort of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
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...
924
            $sort = $this->sort;
925
            ksort($sort);
926
            $hash[] = implode('', array_merge(array_keys($sort), array_values($sort)));
927
        }
928
929
        // fields
930 View Code Duplication
        if($this->fields) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
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...
931
            $fields = $this->fields;
932
            ksort($fields);
933
            $hash[] = implode('', array_merge(array_keys($fields), array_values($fields)));
934
        }
935
936
        // skip and limit
937
        $hash[] = $this->skip;
938
        $hash[] = $this->limit;
939
940
        // get hash
941
        return md5(implode(':', $hash));
942
    }
943
944
    /**
945
     * Get list of MongoId objects from array of strings, MongoId's and Document's
946
     *
947
     * @param array $list
948
     * @return array list of \MongoId
949
     */
950
    public static function mixedToMongoIdList(array $list)
951
    {
952
        return array_map(function($element) {
953
            // MongoId
954
            if($element instanceof \MongoId) {
955
                return $element;
956
            }
957
958
            // \Sokil\Mongo\Document
959
            if($element instanceof Document) {
960
                return $element->getId();
961
            }
962
963
            // array with id key
964
            if(is_array($element)) {
965
                if(!isset($element['_id'])) {
966
                    throw new \InvalidArgumentException('Array must have _id key');
967
                }
968
                return $element['_id'];
969
            }
970
971
            // string
972
            if(is_string($element)) {
973
                try {
974
                    return new \MongoId($element);
975
                } catch (\MongoException $e) {
976
                    return $element;
977
                }
978
            }
979
980
            // int
981
            if(is_int($element)) {
982
                return $element;
983
            }
984
985
            throw new \InvalidArgumentException('Must be \MongoId, \Sokil\Mongo\Document, array with _id key, string or integer');
986
987
        }, array_values($list));
988
    }
989
}
990