Completed
Push — master ( 951391...f65b87 )
by Maciej
17:14
created

Builder::mapReduceOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.2559

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 3
cts 5
cp 0.6
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2.2559
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Query;
6
7
use BadMethodCallException;
8
use Doctrine\ODM\MongoDB\DocumentManager;
9
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
10
use GeoJson\Geometry\Geometry;
11
use GeoJson\Geometry\Point;
12
use InvalidArgumentException;
13
use MongoDB\BSON\Binary;
14
use MongoDB\BSON\Javascript;
15
use MongoDB\Collection;
16
use MongoDB\Driver\ReadPreference;
17
use Traversable;
18
use function array_filter;
19
use function array_key_exists;
20
use function count;
21
use function func_get_args;
22
use function in_array;
23
use function is_array;
24
use function is_bool;
25
use function is_callable;
26
use function is_string;
27
use function strtolower;
28
29
/**
30
 * Query builder for ODM.
31
 */
32
class Builder
33
{
34
    /**
35
     * The DocumentManager instance for this query
36
     *
37
     * @var DocumentManager
38
     */
39
    private $dm;
40
41
    /**
42
     * The ClassMetadata instance.
43
     *
44
     * @var ClassMetadata
45
     */
46
    private $class;
47
48
    /**
49
     * The current field we are operating on.
50
     *
51
     * @todo Change this to private once ODM requires doctrine/mongodb 1.1+
52
     * @var string
53
     */
54
    protected $currentField;
55
56
    /**
57
     * Whether or not to hydrate the data to documents.
58
     *
59
     * @var bool
60
     */
61
    private $hydrate = true;
62
63
    /**
64
     * Whether or not to refresh the data for documents that are already in the identity map.
65
     *
66
     * @var bool
67
     */
68
    private $refresh = false;
69
70
    /**
71
     * Array of primer Closure instances.
72
     *
73
     * @var array
74
     */
75
    private $primers = [];
76
77
    /**
78
     * Whether or not to register documents in UnitOfWork.
79
     *
80
     * @var bool
81
     */
82
    private $readOnly = false;
83
84
    /**
85
     * The Collection instance.
86
     *
87
     * @var Collection
88
     */
89
    private $collection;
90
91
    /**
92
     * Array containing the query data.
93
     *
94
     * @var array
95
     */
96
    private $query = ['type' => Query::TYPE_FIND];
97
98
    /**
99
     * The Expr instance used for building this query.
100
     *
101
     * This object includes the query criteria and the "new object" used for
102
     * insert and update queries.
103
     *
104
     * @var Expr $expr
105
     */
106
    private $expr;
107
108
    /**
109
     * Construct a Builder
110
     *
111
     * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none
112
     */
113 286
    public function __construct(DocumentManager $dm, $documentName = null)
114
    {
115 286
        $this->dm   = $dm;
116 286
        $this->expr = new Expr($dm);
117 286
        if ($documentName === null) {
118 9
            return;
119
        }
120
121 278
        $this->setDocumentName($documentName);
122 277
    }
123
124 1
    public function __clone()
125
    {
126 1
        $this->expr = clone $this->expr;
127 1
    }
128
129
    /**
130
     * Add one or more $and clauses to the current query.
131
     *
132
     * You can create a new expression using the {@link Builder::expr()} method.
133
     *
134
     * @see Expr::addAnd()
135
     * @see http://docs.mongodb.org/manual/reference/operator/and/
136
     *
137
     * @param array|Expr $expression
138
     * @param array|Expr ...$expressions
139
     */
140 4
    public function addAnd($expression, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $expressions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
141
    {
142 4
        $this->expr->addAnd(...func_get_args());
143 4
        return $this;
144
    }
145
146
    /**
147
     * Add one or more $nor clauses to the current query.
148
     *
149
     * You can create a new expression using the {@link Builder::expr()} method.
150
     *
151
     * @see Expr::addNor()
152
     * @see http://docs.mongodb.org/manual/reference/operator/nor/
153
     *
154
     * @param array|Expr $expression
155
     * @param array|Expr ...$expressions
156
     */
157 3
    public function addNor($expression, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $expressions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
158
    {
159 3
        $this->expr->addNor(...func_get_args());
160 3
        return $this;
161
    }
162
163
    /**
164
     * Add one or more $or clauses to the current query.
165
     *
166
     * You can create a new expression using the {@link Builder::expr()} method.
167
     *
168
     * @see Expr::addOr()
169
     * @see http://docs.mongodb.org/manual/reference/operator/or/
170
     *
171
     * @param array|Expr $expression
172
     * @param array|Expr ...$expressions
173
     */
174 6
    public function addOr($expression, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $expressions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
175
    {
176 6
        $this->expr->addOr(...func_get_args());
177 6
        return $this;
178
    }
179
180
    /**
181
     * Append one or more values to the current array field only if they do not
182
     * already exist in the array.
183
     *
184
     * If the field does not exist, it will be set to an array containing the
185
     * unique value(s) in the argument. If the field is not an array, the query
186
     * will yield an error.
187
     *
188
     * Multiple values may be specified by provided an Expr object and using
189
     * {@link Expr::each()}.
190
     *
191
     * @see Expr::addToSet()
192
     * @see http://docs.mongodb.org/manual/reference/operator/addToSet/
193
     * @see http://docs.mongodb.org/manual/reference/operator/each/
194
     *
195
     * @param mixed|Expr $valueOrExpression
196
     */
197 5
    public function addToSet($valueOrExpression) : self
198
    {
199 5
        $this->expr->addToSet($valueOrExpression);
200 5
        return $this;
201
    }
202
203
    /**
204
     * Specify $all criteria for the current field.
205
     *
206
     * @see Expr::all()
207
     * @see http://docs.mongodb.org/manual/reference/operator/all/
208
     */
209 3
    public function all(array $values) : self
210
    {
211 3
        $this->expr->all($values);
212 3
        return $this;
213
    }
214
215
    /**
216
     * Apply a bitwise and operation on the current field.
217
     *
218
     * @see Expr::bitAnd()
219
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
220
     *
221
     * @return $this
222
     */
223 1
    public function bitAnd(int $value) : self
224
    {
225 1
        $this->expr->bitAnd($value);
226 1
        return $this;
227
    }
228
229
    /**
230
     * Apply a bitwise or operation on the current field.
231
     *
232
     * @see Expr::bitOr()
233
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
234
     */
235 1
    public function bitOr(int $value) : self
236
    {
237 1
        $this->expr->bitOr($value);
238 1
        return $this;
239
    }
240
241
    /**
242
     * Matches documents where all of the bit positions given by the query are
243
     * clear.
244
     *
245
     * @see Expr::bitsAllClear()
246
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllClear/
247
     *
248
     * @param int|array|Binary $value
249
     */
250 1
    public function bitsAllClear($value) : self
251
    {
252 1
        $this->expr->bitsAllClear($value);
253 1
        return $this;
254
    }
255
256
    /**
257
     * Matches documents where all of the bit positions given by the query are
258
     * set.
259
     *
260
     * @see Expr::bitsAllSet()
261
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllSet/
262
     *
263
     * @param int|array|Binary $value
264
     */
265 1
    public function bitsAllSet($value) : self
266
    {
267 1
        $this->expr->bitsAllSet($value);
268 1
        return $this;
269
    }
270
271
    /**
272
     * Matches documents where any of the bit positions given by the query are
273
     * clear.
274
     *
275
     * @see Expr::bitsAnyClear()
276
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnyClear/
277
     *
278
     * @param int|array|Binary $value
279
     */
280 1
    public function bitsAnyClear($value) : self
281
    {
282 1
        $this->expr->bitsAnyClear($value);
283 1
        return $this;
284
    }
285
286
    /**
287
     * Matches documents where any of the bit positions given by the query are
288
     * set.
289
     *
290
     * @see Expr::bitsAnySet()
291
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnySet/
292
     *
293
     * @param int|array|Binary $value
294
     */
295 1
    public function bitsAnySet($value) : self
296
    {
297 1
        $this->expr->bitsAnySet($value);
298 1
        return $this;
299
    }
300
301
    /**
302
     * Apply a bitwise xor operation on the current field.
303
     *
304
     * @see Expr::bitXor()
305
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
306
     */
307 1
    public function bitXor(int $value) : self
308
    {
309 1
        $this->expr->bitXor($value);
310 1
        return $this;
311
    }
312
313
    /**
314
     * A boolean flag to enable or disable case sensitive search for $text
315
     * criteria.
316
     *
317
     * This method must be called after text().
318
     *
319
     * @see Expr::caseSensitive()
320
     * @see http://docs.mongodb.org/manual/reference/operator/text/
321
     *
322
     * @throws BadMethodCallException If the query does not already have $text criteria.
323
     */
324 1
    public function caseSensitive(bool $caseSensitive) : self
325
    {
326 1
        $this->expr->caseSensitive($caseSensitive);
327 1
        return $this;
328
    }
329
330
    /**
331
     * Associates a comment to any expression taking a query predicate.
332
     *
333
     * @see Expr::comment()
334
     * @see http://docs.mongodb.org/manual/reference/operator/query/comment/
335
     */
336 1
    public function comment(string $comment) : self
337
    {
338 1
        $this->expr->comment($comment);
339 1
        return $this;
340
    }
341
342
    /**
343
     * Change the query type to count.
344
     */
345
    public function count() : self
346
    {
347
        $this->query['type'] = Query::TYPE_COUNT;
348
        return $this;
349
    }
350
351
    /**
352
     * Sets the value of the current field to the current date, either as a date or a timestamp.
353
     *
354
     * @see Expr::currentDate()
355
     * @see http://docs.mongodb.org/manual/reference/operator/currentDate/
356
     */
357 3
    public function currentDate(string $type = 'date') : self
358
    {
359 3
        $this->expr->currentDate($type);
360 2
        return $this;
361
    }
362
363
    /**
364
     * Return an array of information about the Builder state for debugging.
365
     *
366
     * The $name parameter may be used to return a specific key from the
367
     * internal $query array property. If omitted, the entire array will be
368
     * returned.
369
     *
370
     * @return mixed
371
     */
372 28
    public function debug(?string $name = null)
373
    {
374 28
        return $name !== null ? $this->query[$name] : $this->query;
375
    }
376
377
    /**
378
     * A boolean flag to enable or disable diacritic sensitive search for $text
379
     * criteria.
380
     *
381
     * This method must be called after text().
382
     *
383
     * @see Builder::diacriticSensitive()
384
     * @see http://docs.mongodb.org/manual/reference/operator/text/
385
     *
386
     * @throws BadMethodCallException If the query does not already have $text criteria.
387
     */
388 1
    public function diacriticSensitive(bool $diacriticSensitive) : self
389
    {
390 1
        $this->expr->diacriticSensitive($diacriticSensitive);
391 1
        return $this;
392
    }
393
394
    /**
395
     * Change the query type to a distinct command.
396
     *
397
     * @see http://docs.mongodb.org/manual/reference/command/distinct/
398
     */
399 2
    public function distinct(string $field) : self
400
    {
401 2
        $this->query['type']     = Query::TYPE_DISTINCT;
402 2
        $this->query['distinct'] = $field;
403 2
        return $this;
404
    }
405
406
    /**
407
     * Specify $elemMatch criteria for the current field.
408
     *
409
     * You can create a new expression using the {@link Builder::expr()} method.
410
     *
411
     * @see Expr::elemMatch()
412
     * @see http://docs.mongodb.org/manual/reference/operator/elemMatch/
413
     *
414
     * @param array|Expr $expression
415
     */
416 6
    public function elemMatch($expression) : self
417
    {
418 6
        $this->expr->elemMatch($expression);
419 6
        return $this;
420
    }
421
422
    /**
423
     * Specify an equality match for the current field.
424
     *
425
     * @see Expr::equals()
426
     *
427
     * @param mixed $value
428
     */
429 79
    public function equals($value) : self
430
    {
431 79
        $this->expr->equals($value);
432 79
        return $this;
433
    }
434
435
    /**
436
     * Set one or more fields to be excluded from the query projection.
437
     *
438
     * If fields have been selected for inclusion, only the "_id" field may be
439
     * excluded.
440
     *
441
     * @param array|string $fieldName,...
0 ignored issues
show
Documentation introduced by
There is no parameter named $fieldName,.... Did you maybe mean $fieldName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
442
     */
443 6
    public function exclude($fieldName = null) : self
444
    {
445 6
        if (! isset($this->query['select'])) {
446 6
            $this->query['select'] = [];
447
        }
448
449 6
        $fieldNames = is_array($fieldName) ? $fieldName : func_get_args();
450
451 6
        foreach ($fieldNames as $fieldName) {
452 4
            $this->query['select'][$fieldName] = 0;
453
        }
454
455 6
        return $this;
456
    }
457
458
    /**
459
     * Specify $exists criteria for the current field.
460
     *
461
     * @see Expr::exists()
462
     * @see http://docs.mongodb.org/manual/reference/operator/exists/
463
     */
464 5
    public function exists(bool $bool) : self
465
    {
466 5
        $this->expr->exists($bool);
467 5
        return $this;
468
    }
469
470
    /**
471
     * Create a new Expr instance that can be used as an expression with the Builder
472
     */
473 26
    public function expr() : Expr
474
    {
475 26
        $expr = new Expr($this->dm);
476 26
        $expr->setClassMetadata($this->class);
477
478 26
        return $expr;
479
    }
480
481
    /**
482
     * Set the current field to operate on.
483
     */
484 145
    public function field(string $field) : self
485
    {
486 145
        $this->currentField = $field;
487 145
        $this->expr->field($field);
488
489 145
        return $this;
490
    }
491
492
    /**
493
     * Set the "finalize" option for a mapReduce or group command.
494
     *
495
     * @param string|Javascript $finalize
496
     *
497
     * @throws BadMethodCallException If the query is not a mapReduce or group command.
498
     */
499 2
    public function finalize($finalize) : self
500
    {
501 2
        switch ($this->query['type']) {
502
            case Query::TYPE_MAP_REDUCE:
503 1
                $this->query['mapReduce']['options']['finalize'] = $finalize;
504 1
                break;
505
506
            case Query::TYPE_GROUP:
507
                $this->query['group']['options']['finalize'] = $finalize;
508
                break;
509
510
            default:
511 1
                throw new BadMethodCallException('mapReduce(), map() or group() must be called before finalize()');
512
        }
513
514 1
        return $this;
515
    }
516
517
    /**
518
     * Change the query type to find and optionally set and change the class being queried.
519
     */
520 13
    public function find(?string $documentName = null) : self
521
    {
522 13
        $this->setDocumentName($documentName);
523 13
        $this->query['type'] = Query::TYPE_FIND;
524
525 13
        return $this;
526
    }
527
528 1
    public function findAndRemove(?string $documentName = null) : self
529
    {
530 1
        $this->setDocumentName($documentName);
531 1
        $this->query['type'] = Query::TYPE_FIND_AND_REMOVE;
532
533 1
        return $this;
534
    }
535
536 13
    public function findAndUpdate(?string $documentName = null) : self
537
    {
538 13
        $this->setDocumentName($documentName);
539 13
        $this->query['type'] = Query::TYPE_FIND_AND_UPDATE;
540
541 13
        return $this;
542
    }
543
544
    /**
545
     * Add $geoIntersects criteria with a GeoJSON geometry to the query.
546
     *
547
     * The geometry parameter GeoJSON object or an array corresponding to the
548
     * geometry's JSON representation.
549
     *
550
     * @see Expr::geoIntersects()
551
     * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/
552
     *
553
     * @param array|Geometry $geometry
554
     */
555 1
    public function geoIntersects($geometry) : self
556
    {
557 1
        $this->expr->geoIntersects($geometry);
558 1
        return $this;
559
    }
560
561
    /**
562
     * Add $geoWithin criteria with a GeoJSON geometry to the query.
563
     *
564
     * The geometry parameter GeoJSON object or an array corresponding to the
565
     * geometry's JSON representation.
566
     *
567
     * @see Expr::geoWithin()
568
     * @see http://docs.mongodb.org/manual/reference/operator/geoWithin/
569
     *
570
     * @param array|Geometry $geometry
571
     */
572 1
    public function geoWithin($geometry) : self
573
    {
574 1
        $this->expr->geoWithin($geometry);
575 1
        return $this;
576
    }
577
578
    /**
579
     * Add $geoWithin criteria with a $box shape to the query.
580
     *
581
     * A rectangular polygon will be constructed from a pair of coordinates
582
     * corresponding to the bottom left and top right corners.
583
     *
584
     * Note: the $box operator only supports legacy coordinate pairs and 2d
585
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
586
     *
587
     * @see Expr::geoWithinBox()
588
     * @see http://docs.mongodb.org/manual/reference/operator/box/
589
     */
590 1
    public function geoWithinBox(float $x1, float $y1, float $x2, float $y2) : self
591
    {
592 1
        $this->expr->geoWithinBox($x1, $y1, $x2, $y2);
593 1
        return $this;
594
    }
595
596
    /**
597
     * Add $geoWithin criteria with a $center shape to the query.
598
     *
599
     * Note: the $center operator only supports legacy coordinate pairs and 2d
600
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
601
     *
602
     * @see Expr::geoWithinCenter()
603
     * @see http://docs.mongodb.org/manual/reference/operator/center/
604
     */
605 1
    public function geoWithinCenter(float $x, float $y, float $radius) : self
606
    {
607 1
        $this->expr->geoWithinCenter($x, $y, $radius);
608 1
        return $this;
609
    }
610
611
    /**
612
     * Add $geoWithin criteria with a $centerSphere shape to the query.
613
     *
614
     * Note: the $centerSphere operator supports both 2d and 2dsphere indexes.
615
     *
616
     * @see Expr::geoWithinCenterSphere()
617
     * @see http://docs.mongodb.org/manual/reference/operator/centerSphere/
618
     */
619 1
    public function geoWithinCenterSphere(float $x, float $y, float $radius) : self
620
    {
621 1
        $this->expr->geoWithinCenterSphere($x, $y, $radius);
622 1
        return $this;
623
    }
624
625
    /**
626
     * Add $geoWithin criteria with a $polygon shape to the query.
627
     *
628
     * Point coordinates are in x, y order (easting, northing for projected
629
     * coordinates, longitude, latitude for geographic coordinates).
630
     *
631
     * The last point coordinate is implicitly connected with the first.
632
     *
633
     * Note: the $polygon operator only supports legacy coordinate pairs and 2d
634
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
635
     *
636
     * @see Expr::geoWithinPolygon()
637
     * @see http://docs.mongodb.org/manual/reference/operator/polygon/
638
     *
639
     * @param array $point1    First point of the polygon
640
     * @param array $point2    Second point of the polygon
641
     * @param array $point3    Third point of the polygon
642
     * @param array ...$points Additional points of the polygon
643
     */
644 1
    public function geoWithinPolygon($point1, $point2, $point3, ...$points) : self
0 ignored issues
show
Unused Code introduced by
The parameter $point1 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $point2 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $point3 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $points is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
645
    {
646 1
        $this->expr->geoWithinPolygon(...func_get_args());
647 1
        return $this;
648
    }
649
650
    /**
651
     * Return the expression's "new object".
652
     *
653
     * @see Expr::getNewObj()
654
     */
655 13
    public function getNewObj() : array
656
    {
657 13
        return $this->expr->getNewObj();
658
    }
659
660
    /**
661
     * Gets the Query executable.
662
     */
663 153
    public function getQuery(array $options = []) : Query
664
    {
665 153
        if ($this->query['type'] === Query::TYPE_MAP_REDUCE) {
666
            $this->hydrate = false;
667
        }
668
669 153
        $documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name);
670
671 153
        $query = $this->query;
672
673 153
        $query['query'] = $this->expr->getQuery();
674 153
        $query['query'] = $documentPersister->addDiscriminatorToPreparedQuery($query['query']);
675 153
        $query['query'] = $documentPersister->addFilterToPreparedQuery($query['query']);
676
677 153
        $query['newObj'] = $this->expr->getNewObj();
678
679 153
        if (isset($query['distinct'])) {
680 2
            $query['distinct'] = $documentPersister->prepareFieldName($query['distinct']);
0 ignored issues
show
Documentation introduced by
$query['distinct'] is of type array, but the function expects a string.

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...
681
        }
682
683 153
        if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION && ! empty($query['upsert']) &&
684 153
            (empty($query['query'][$this->class->discriminatorField]) || is_array($query['query'][$this->class->discriminatorField]))) {
685 1
            throw new InvalidArgumentException('Upsert query that is to be performed on discriminated document does not have single ' .
686 1
                'discriminator. Either not use base class or set \'' . $this->class->discriminatorField . '\' field manually.');
687
        }
688
689 152
        if (! empty($query['select'])) {
690 14
            $query['select'] = $documentPersister->prepareProjection($query['select']);
691 14
            if ($this->hydrate && $this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION
692 14
                && ! isset($query['select'][$this->class->discriminatorField])) {
693
                $includeMode = 0 < count(array_filter($query['select'], static function ($mode) {
694 2
                    return $mode === 1;
695 2
                }));
696 2
                if ($includeMode && ! isset($query['select'][$this->class->discriminatorField])) {
697 1
                    $query['select'][$this->class->discriminatorField] = 1;
698
                }
699
            }
700
        }
701
702 152
        if (isset($query['sort'])) {
703 23
            $query['sort'] = $documentPersister->prepareSort($query['sort']);
704
        }
705
706 152
        if ($this->class->readPreference && ! array_key_exists('readPreference', $query)) {
707 1
            $query['readPreference'] = new ReadPreference($this->class->readPreference, $this->class->readPreferenceTags);
708
        }
709
710 152
        return new Query(
711 152
            $this->dm,
712 152
            $this->class,
713 152
            $this->collection,
714 152
            $query,
715 152
            $options,
716 152
            $this->hydrate,
717 152
            $this->refresh,
718 152
            $this->primers,
719 152
            $this->readOnly
720
        );
721
    }
722
723
    /**
724
     * Return the expression's query criteria.
725
     *
726
     * @see Expr::getQuery()
727
     */
728 33
    public function getQueryArray() : array
729
    {
730 33
        return $this->expr->getQuery();
731
    }
732
733
    /**
734
     * Get the type of this query.
735
     */
736 2
    public function getType() : int
737
    {
738 2
        return $this->query['type'];
739
    }
740
741
    /**
742
     * Specify $gt criteria for the current field.
743
     *
744
     * @see Expr::gt()
745
     * @see http://docs.mongodb.org/manual/reference/operator/gt/
746
     *
747
     * @param mixed $value
748
     */
749 2
    public function gt($value) : self
750
    {
751 2
        $this->expr->gt($value);
752 2
        return $this;
753
    }
754
755
    /**
756
     * Specify $gte criteria for the current field.
757
     *
758
     * @see Expr::gte()
759
     * @see http://docs.mongodb.org/manual/reference/operator/gte/
760
     *
761
     * @param mixed $value
762
     */
763 2
    public function gte($value) : self
764
    {
765 2
        $this->expr->gte($value);
766 2
        return $this;
767
    }
768
769
    /**
770
     * Set the index hint for the query.
771
     *
772
     * @param array|string $index
773
     */
774
    public function hint($index) : self
775
    {
776
        $this->query['hint'] = $index;
777
        return $this;
778
    }
779
780 17
    public function hydrate(bool $bool = true) : self
781
    {
782 17
        $this->hydrate = $bool;
783 17
        return $this;
784
    }
785
786
    /**
787
     * Set the immortal cursor flag.
788
     */
789
    public function immortal(bool $bool = true) : self
790
    {
791
        $this->query['immortal'] = $bool;
792
        return $this;
793
    }
794
795
    /**
796
     * Specify $in criteria for the current field.
797
     *
798
     * @see Expr::in()
799
     * @see http://docs.mongodb.org/manual/reference/operator/in/
800
     */
801 24
    public function in(array $values) : self
802
    {
803 24
        $this->expr->in($values);
804 24
        return $this;
805
    }
806
807
    /**
808
     * Increment the current field.
809
     *
810
     * If the field does not exist, it will be set to this value.
811
     *
812
     * @see Expr::inc()
813
     * @see http://docs.mongodb.org/manual/reference/operator/inc/
814
     *
815
     * @param float|int $value
816
     */
817 6
    public function inc($value) : self
818
    {
819 6
        $this->expr->inc($value);
820 6
        return $this;
821
    }
822
823 6
    public function includesReferenceTo(object $document) : self
824
    {
825 6
        $this->expr->includesReferenceTo($document);
826 4
        return $this;
827
    }
828
829 1
    public function insert(?string $documentName = null) : self
830
    {
831 1
        $this->setDocumentName($documentName);
832 1
        $this->query['type'] = Query::TYPE_INSERT;
833
834 1
        return $this;
835
    }
836
837
    /**
838
     * Set the $language option for $text criteria.
839
     *
840
     * This method must be called after text().
841
     *
842
     * @see Expr::language()
843
     * @see http://docs.mongodb.org/manual/reference/operator/text/
844
     */
845 1
    public function language(string $language) : self
846
    {
847 1
        $this->expr->language($language);
848 1
        return $this;
849
    }
850
851
    /**
852
     * Set the limit for the query.
853
     *
854
     * This is only relevant for find queries and geoNear and mapReduce
855
     * commands.
856
     *
857
     * @see Query::prepareCursor()
858
     */
859 2
    public function limit(int $limit) : self
860
    {
861 2
        $this->query['limit'] = $limit;
862 2
        return $this;
863
    }
864
865
    /**
866
     * Specify $lt criteria for the current field.
867
     *
868
     * @see Expr::lte()
869
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
870
     *
871
     * @param mixed $value
872
     */
873
    public function lt($value) : self
874
    {
875
        $this->expr->lt($value);
876
        return $this;
877
    }
878
879
    /**
880
     * Specify $lte criteria for the current field.
881
     *
882
     * @see Expr::lte()
883
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
884
     *
885
     * @param mixed $value
886
     */
887
    public function lte($value) : self
888
    {
889
        $this->expr->lte($value);
890
        return $this;
891
    }
892
893
    /**
894
     * Change the query type to a mapReduce command.
895
     *
896
     * The "reduce" option is not specified when calling this method; it must
897
     * be set with the {@link Builder::reduce()} method.
898
     *
899
     * The "out" option defaults to inline, like {@link Builder::mapReduce()}.
900
     *
901
     * @see http://docs.mongodb.org/manual/reference/command/mapReduce/
902
     *
903
     * @param string|Javascript $map
904
     */
905 1
    public function map($map) : self
906
    {
907 1
        $this->query['type']      = Query::TYPE_MAP_REDUCE;
908 1
        $this->query['mapReduce'] = [
909 1
            'map' => $map,
910
            'reduce' => null,
911
            'out' => ['inline' => true],
912
            'options' => [],
913
        ];
914 1
        return $this;
915
    }
916
917
    /**
918
     * Change the query type to a mapReduce command.
919
     *
920
     * @see http://docs.mongodb.org/manual/reference/command/mapReduce/
921
     *
922
     * @param string|Javascript $map
923
     * @param string|Javascript $reduce
924
     * @param array|string      $out
925
     * @param array             $options
926
     *
927
     * @return $this
928
     */
929 1
    public function mapReduce($map, $reduce, $out = ['inline' => true], array $options = []) : self
930
    {
931 1
        $this->query['type']      = Query::TYPE_MAP_REDUCE;
932 1
        $this->query['mapReduce'] = [
933 1
            'map' => $map,
934 1
            'reduce' => $reduce,
935 1
            'out' => $out,
936 1
            'options' => $options,
937
        ];
938 1
        return $this;
939
    }
940
941
    /**
942
     * Set additional options for a mapReduce command.
943
     *
944
     * @throws BadMethodCallException If the query is not a mapReduce command.
945
     */
946 1
    public function mapReduceOptions(array $options) : self
947
    {
948 1
        if ($this->query['type'] !== Query::TYPE_MAP_REDUCE) {
949 1
            throw new BadMethodCallException('This method requires a mapReduce command (call map() or mapReduce() first)');
950
        }
951
952
        $this->query['mapReduce']['options'] = $options;
953
        return $this;
954
    }
955
956
    /**
957
     * Updates the value of the field to a specified value if the specified value is greater than the current value of the field.
958
     *
959
     * @see Expr::max()
960
     * @see http://docs.mongodb.org/manual/reference/operator/update/max/
961
     *
962
     * @param mixed $value
963
     */
964 1
    public function max($value) : self
965
    {
966 1
        $this->expr->max($value);
967 1
        return $this;
968
    }
969
970
    /**
971
     * Specifies a cumulative time limit in milliseconds for processing operations on a cursor.
972
     */
973
    public function maxTimeMS(int $ms) : self
974
    {
975
        $this->query['maxTimeMS'] = $ms;
976
        return $this;
977
    }
978
979
    /**
980
     * Updates the value of the field to a specified value if the specified value is less than the current value of the field.
981
     *
982
     * @see Expr::min()
983
     * @see http://docs.mongodb.org/manual/reference/operator/update/min/
984
     *
985
     * @param mixed $value
986
     */
987 1
    public function min($value) : self
988
    {
989 1
        $this->expr->min($value);
990 1
        return $this;
991
    }
992
993
    /**
994
     * Specify $mod criteria for the current field.
995
     *
996
     * @see Expr::mod()
997
     * @see http://docs.mongodb.org/manual/reference/operator/mod/
998
     *
999
     * @param float|int $divisor
1000
     * @param float|int $remainder
1001
     */
1002 1
    public function mod($divisor, $remainder = 0) : self
1003
    {
1004 1
        $this->expr->mod($divisor, $remainder);
1005 1
        return $this;
1006
    }
1007
1008
    /**
1009
     * Multiply the current field.
1010
     *
1011
     * If the field does not exist, it will be set to 0.
1012
     *
1013
     * @see Expr::mul()
1014
     * @see http://docs.mongodb.org/manual/reference/operator/mul/
1015
     *
1016
     * @param float|int $value
1017
     */
1018 1
    public function mul($value) : self
1019
    {
1020 1
        $this->expr->mul($value);
1021 1
        return $this;
1022
    }
1023
1024
    /**
1025
     * Add $near criteria to the query.
1026
     *
1027
     * A GeoJSON point may be provided as the first and only argument for
1028
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
1029
     * an array corresponding to the point's JSON representation.
1030
     *
1031
     * @see Expr::near()
1032
     * @see http://docs.mongodb.org/manual/reference/operator/near/
1033
     *
1034
     * @param float|array|Point $x
1035
     * @param float             $y
1036
     */
1037 1
    public function near($x, $y = null) : self
1038
    {
1039 1
        $this->expr->near($x, $y);
1040 1
        return $this;
1041
    }
1042
1043
    /**
1044
     * Add $nearSphere criteria to the query.
1045
     *
1046
     * A GeoJSON point may be provided as the first and only argument for
1047
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
1048
     * an array corresponding to the point's JSON representation.
1049
     *
1050
     * @see Expr::nearSphere()
1051
     * @see http://docs.mongodb.org/manual/reference/operator/nearSphere/
1052
     *
1053
     * @param float|array|Point $x
1054
     * @param float             $y
1055
     */
1056 1
    public function nearSphere($x, $y = null) : self
1057
    {
1058 1
        $this->expr->nearSphere($x, $y);
1059 1
        return $this;
1060
    }
1061
1062
    /**
1063
     * Negates an expression for the current field.
1064
     *
1065
     * You can create a new expression using the {@link Builder::expr()} method.
1066
     *
1067
     * @see Expr::not()
1068
     * @see http://docs.mongodb.org/manual/reference/operator/not/
1069
     *
1070
     * @param array|Expr $expression
1071
     */
1072 3
    public function not($expression) : self
1073
    {
1074 3
        $this->expr->not($expression);
1075 3
        return $this;
1076
    }
1077
1078
    /**
1079
     * Specify $ne criteria for the current field.
1080
     *
1081
     * @see Expr::notEqual()
1082
     * @see http://docs.mongodb.org/manual/reference/operator/ne/
1083
     *
1084
     * @param mixed $value
1085
     */
1086 4
    public function notEqual($value) : self
1087
    {
1088 4
        $this->expr->notEqual($value);
1089 4
        return $this;
1090
    }
1091
1092
    /**
1093
     * Specify $nin criteria for the current field.
1094
     *
1095
     * @see Expr::notIn()
1096
     * @see http://docs.mongodb.org/manual/reference/operator/nin/
1097
     *
1098
     * @param array $values
1099
     */
1100 4
    public function notIn(array $values) : self
1101
    {
1102 4
        $this->expr->notIn($values);
1103 4
        return $this;
1104
    }
1105
1106
    /**
1107
     * Set the "out" option for a mapReduce command.
1108
     *
1109
     * @param array|string $out
1110
     *
1111
     * @throws BadMethodCallException If the query is not a mapReduce command.
1112
     */
1113 1
    public function out($out) : self
1114
    {
1115 1
        if ($this->query['type'] !== Query::TYPE_MAP_REDUCE) {
1116 1
            throw new BadMethodCallException('This method requires a mapReduce command (call map() or mapReduce() first)');
1117
        }
1118
1119
        $this->query['mapReduce']['out'] = $out;
1120
        return $this;
1121
    }
1122
1123
    /**
1124
     * Remove the first element from the current array field.
1125
     *
1126
     * @see Expr::popFirst()
1127
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
1128
     */
1129 3
    public function popFirst() : self
1130
    {
1131 3
        $this->expr->popFirst();
1132 3
        return $this;
1133
    }
1134
1135
    /**
1136
     * Remove the last element from the current array field.
1137
     *
1138
     * @see Expr::popLast()
1139
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
1140
     */
1141 2
    public function popLast() : self
1142
    {
1143 2
        $this->expr->popLast();
1144 2
        return $this;
1145
    }
1146
1147
    /**
1148
     * Use a primer to eagerly load all references in the current field.
1149
     *
1150
     * If $primer is true or a callable is provided, referenced documents for
1151
     * this field will loaded into UnitOfWork immediately after the query is
1152
     * executed. This will avoid multiple queries due to lazy initialization of
1153
     * Proxy objects.
1154
     *
1155
     * If $primer is false, no priming will take place. That is also the default
1156
     * behavior.
1157
     *
1158
     * If a custom callable is used, its signature should conform to the default
1159
     * Closure defined in {@link ReferencePrimer::__construct()}.
1160
     *
1161
     * @param bool|callable $primer
1162
     *
1163
     * @throws InvalidArgumentException If $primer is not boolean or callable.
1164
     */
1165 22
    public function prime($primer = true) : self
1166
    {
1167 22
        if (! is_bool($primer) && ! is_callable($primer)) {
1168 1
            throw new InvalidArgumentException('$primer is not a boolean or callable');
1169
        }
1170
1171 21
        if ($primer === false) {
1172
            unset($this->primers[$this->currentField]);
1173
1174
            return $this;
1175
        }
1176
1177 21
        $this->primers[$this->currentField] = $primer;
1178 21
        return $this;
1179
    }
1180
1181
    /**
1182
     * Remove all elements matching the given value or expression from the
1183
     * current array field.
1184
     *
1185
     * @see Expr::pull()
1186
     * @see http://docs.mongodb.org/manual/reference/operator/pull/
1187
     *
1188
     * @param mixed|Expr $valueOrExpression
1189
     */
1190 1
    public function pull($valueOrExpression) : self
1191
    {
1192 1
        $this->expr->pull($valueOrExpression);
1193 1
        return $this;
1194
    }
1195
1196
    /**
1197
     * Remove all elements matching any of the given values from the current
1198
     * array field.
1199
     *
1200
     * @see Expr::pullAll()
1201
     * @see http://docs.mongodb.org/manual/reference/operator/pullAll/
1202
     */
1203 1
    public function pullAll(array $values) : self
1204
    {
1205 1
        $this->expr->pullAll($values);
1206 1
        return $this;
1207
    }
1208
1209
    /**
1210
     * Append one or more values to the current array field.
1211
     *
1212
     * If the field does not exist, it will be set to an array containing the
1213
     * value(s) in the argument. If the field is not an array, the query
1214
     * will yield an error.
1215
     *
1216
     * Multiple values may be specified by providing an Expr object and using
1217
     * {@link Expr::each()}. {@link Expr::slice()} and {@link Expr::sort()} may
1218
     * also be used to limit and order array elements, respectively.
1219
     *
1220
     * @see Expr::push()
1221
     * @see http://docs.mongodb.org/manual/reference/operator/push/
1222
     * @see http://docs.mongodb.org/manual/reference/operator/each/
1223
     * @see http://docs.mongodb.org/manual/reference/operator/slice/
1224
     * @see http://docs.mongodb.org/manual/reference/operator/sort/
1225
     *
1226
     * @param mixed|Expr $valueOrExpression
1227
     */
1228 6
    public function push($valueOrExpression) : self
1229
    {
1230 6
        $this->expr->push($valueOrExpression);
1231 6
        return $this;
1232
    }
1233
1234
    /**
1235
     * Specify $gte and $lt criteria for the current field.
1236
     *
1237
     * This method is shorthand for specifying $gte criteria on the lower bound
1238
     * and $lt criteria on the upper bound. The upper bound is not inclusive.
1239
     *
1240
     * @see Expr::range()
1241
     *
1242
     * @param mixed $start
1243
     * @param mixed $end
1244
     */
1245 3
    public function range($start, $end) : self
1246
    {
1247 3
        $this->expr->range($start, $end);
1248 3
        return $this;
1249
    }
1250
1251 2
    public function readOnly(bool $bool = true) : self
1252
    {
1253 2
        $this->readOnly = $bool;
1254 2
        return $this;
1255
    }
1256
1257
    /**
1258
     * Set the "reduce" option for a mapReduce or group command.
1259
     *
1260
     * @param string|Javascript $reduce
1261
     *
1262
     * @throws BadMethodCallException If the query is not a mapReduce or group command.
1263
     */
1264 2
    public function reduce($reduce) : self
1265
    {
1266 2
        switch ($this->query['type']) {
1267
            case Query::TYPE_MAP_REDUCE:
1268 1
                $this->query['mapReduce']['reduce'] = $reduce;
1269 1
                break;
1270
1271
            case Query::TYPE_GROUP:
1272
                $this->query['group']['reduce'] = $reduce;
1273
                break;
1274
1275
            default:
1276 1
                throw new BadMethodCallException('mapReduce(), map() or group() must be called before reduce()');
1277
        }
1278
1279 1
        return $this;
1280
    }
1281
1282 10
    public function references(object $document) : self
1283
    {
1284 10
        $this->expr->references($document);
1285 8
        return $this;
1286
    }
1287
1288 5
    public function refresh(bool $bool = true) : self
1289
    {
1290 5
        $this->refresh = $bool;
1291 5
        return $this;
1292
    }
1293
1294 1
    public function remove(?string $documentName = null) : self
1295
    {
1296 1
        $this->setDocumentName($documentName);
1297 1
        $this->query['type'] = Query::TYPE_REMOVE;
1298
1299 1
        return $this;
1300
    }
1301
1302
    /**
1303
     * Rename the current field.
1304
     *
1305
     * @see Expr::rename()
1306
     * @see http://docs.mongodb.org/manual/reference/operator/rename/
1307
     */
1308
    public function rename(string $name) : self
1309
    {
1310
        $this->expr->rename($name);
1311
        return $this;
1312
    }
1313
1314 4
    public function returnNew(bool $bool = true) : self
1315
    {
1316 4
        $this->refresh(true);
1317 4
        $this->query['new'] = $bool;
1318
1319 4
        return $this;
1320
    }
1321
1322
    /**
1323
     * Set one or more fields to be included in the query projection.
1324
     *
1325
     * @param array|string $fieldName,...
0 ignored issues
show
Documentation introduced by
There is no parameter named $fieldName,.... Did you maybe mean $fieldName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1326
     */
1327 19
    public function select($fieldName = null) : self
1328
    {
1329 19
        if (! isset($this->query['select'])) {
1330 18
            $this->query['select'] = [];
1331
        }
1332
1333 19
        $fieldNames = is_array($fieldName) ? $fieldName : func_get_args();
1334
1335 19
        foreach ($fieldNames as $fieldName) {
1336 16
            $this->query['select'][$fieldName] = 1;
1337
        }
1338
1339 19
        return $this;
1340
    }
1341
1342
    /**
1343
     * Select only matching embedded documents in an array field for the query
1344
     * projection.
1345
     *
1346
     * @see http://docs.mongodb.org/manual/reference/projection/elemMatch/
1347
     *
1348
     * @param array|Expr $expression
1349
     */
1350 2
    public function selectElemMatch(string $fieldName, $expression) : self
1351
    {
1352 2
        if ($expression instanceof Expr) {
1353 1
            $expression = $expression->getQuery();
1354
        }
1355 2
        $this->query['select'][$fieldName] = ['$elemMatch' => $expression];
1356 2
        return $this;
1357
    }
1358
1359
    /**
1360
     * Select a metadata field for the query projection.
1361
     *
1362
     * @see http://docs.mongodb.org/master/reference/operator/projection/meta/
1363
     */
1364 2
    public function selectMeta(string $fieldName, string $metaDataKeyword) : self
1365
    {
1366 2
        $this->query['select'][$fieldName] = ['$meta' => $metaDataKeyword];
1367 2
        return $this;
1368
    }
1369
1370
    /**
1371
     * Select a slice of an array field for the query projection.
1372
     *
1373
     * The $countOrSkip parameter has two very different meanings, depending on
1374
     * whether or not $limit is provided. See the MongoDB documentation for more
1375
     * information.
1376
     *
1377
     * @see http://docs.mongodb.org/manual/reference/projection/slice/
1378
     */
1379 3
    public function selectSlice(string $fieldName, int $countOrSkip, ?int $limit = null) : self
1380
    {
1381 3
        $slice = $countOrSkip;
1382 3
        if ($limit !== null) {
1383 2
            $slice = [$slice, $limit];
1384
        }
1385 3
        $this->query['select'][$fieldName] = ['$slice' => $slice];
1386 3
        return $this;
1387
    }
1388
1389
    /**
1390
     * Set the current field to a value.
1391
     *
1392
     * This is only relevant for insert, update, or findAndUpdate queries. For
1393
     * update and findAndUpdate queries, the $atomic parameter will determine
1394
     * whether or not a $set operator is used.
1395
     *
1396
     * @see Expr::set()
1397
     * @see http://docs.mongodb.org/manual/reference/operator/set/
1398
     *
1399
     * @param mixed $value
1400
     */
1401 16
    public function set($value, bool $atomic = true) : self
1402
    {
1403 16
        $this->expr->set($value, $atomic && $this->query['type'] !== Query::TYPE_INSERT);
1404 16
        return $this;
1405
    }
1406
1407
    /**
1408
     * Set the expression's "new object".
1409
     *
1410
     * @see Expr::setNewObj()
1411
     */
1412
    public function setNewObj(array $newObj) : self
1413
    {
1414
        $this->expr->setNewObj($newObj);
1415
        return $this;
1416
    }
1417
1418
    /**
1419
     * Set the current field to the value if the document is inserted in an
1420
     * upsert operation.
1421
     *
1422
     * If an update operation with upsert: true results in an insert of a
1423
     * document, then $setOnInsert assigns the specified values to the fields in
1424
     * the document. If the update operation does not result in an insert,
1425
     * $setOnInsert does nothing.
1426
     *
1427
     * @see Expr::setOnInsert()
1428
     * @see https://docs.mongodb.org/manual/reference/operator/update/setOnInsert/
1429
     *
1430
     * @param mixed $value
1431
     */
1432 2
    public function setOnInsert($value) : self
1433
    {
1434 2
        $this->expr->setOnInsert($value);
1435 2
        return $this;
1436
    }
1437
1438
    /**
1439
     * Set the read preference for the query.
1440
     *
1441
     * This is only relevant for read-only queries and commands.
1442
     *
1443
     * @see http://docs.mongodb.org/manual/core/read-preference/
1444
     */
1445 6
    public function setReadPreference(ReadPreference $readPreference) : self
1446
    {
1447 6
        $this->query['readPreference'] = $readPreference;
1448 6
        return $this;
1449
    }
1450
1451
    /**
1452
     * Set the expression's query criteria.
1453
     *
1454
     * @see Expr::setQuery()
1455
     */
1456 18
    public function setQueryArray(array $query) : self
1457
    {
1458 18
        $this->expr->setQuery($query);
1459 18
        return $this;
1460
    }
1461
1462
    /**
1463
     * Specify $size criteria for the current field.
1464
     *
1465
     * @see Expr::size()
1466
     * @see http://docs.mongodb.org/manual/reference/operator/size/
1467
     */
1468 1
    public function size(int $size) : self
1469
    {
1470 1
        $this->expr->size($size);
1471 1
        return $this;
1472
    }
1473
1474
    /**
1475
     * Set the skip for the query cursor.
1476
     *
1477
     * This is only relevant for find queries, or mapReduce queries that store
1478
     * results in an output collecton and return a cursor.
1479
     *
1480
     * @see Query::prepareCursor()
1481
     */
1482
    public function skip(int $skip) : self
1483
    {
1484
        $this->query['skip'] = $skip;
1485
        return $this;
1486
    }
1487
1488
    /**
1489
     * Set the snapshot cursor flag.
1490
     */
1491
    public function snapshot(bool $bool = true) : self
1492
    {
1493
        $this->query['snapshot'] = $bool;
1494
        return $this;
1495
    }
1496
1497
    /**
1498
     * Set one or more field/order pairs on which to sort the query.
1499
     *
1500
     * If sorting by multiple fields, the first argument should be an array of
1501
     * field name (key) and order (value) pairs.
1502
     *
1503
     * @param array|string $fieldName Field name or array of field/order pairs
1504
     * @param int|string   $order     Field order (if one field is specified)
1505
     */
1506 31
    public function sort($fieldName, $order = 1) : self
1507
    {
1508 31
        if (! isset($this->query['sort'])) {
1509 31
            $this->query['sort'] = [];
1510
        }
1511
1512 31
        $fields = is_array($fieldName) ? $fieldName : [$fieldName => $order];
1513
1514 31
        foreach ($fields as $fieldName => $order) {
1515 14
            if (is_string($order)) {
1516 9
                $order = strtolower($order) === 'asc' ? 1 : -1;
1517
            }
1518 14
            $this->query['sort'][$fieldName] = (int) $order;
1519
        }
1520
1521 31
        return $this;
1522
    }
1523
1524
    /**
1525
     * Specify a projected metadata field on which to sort the query.
1526
     *
1527
     * Sort order is not configurable for metadata fields. Sorting by a metadata
1528
     * field requires the same field and $meta expression to exist in the
1529
     * projection document. This method will call {@link Builder::selectMeta()}
1530
     * if the field is not already set in the projection.
1531
     *
1532
     * @see http://docs.mongodb.org/master/reference/operator/projection/meta/#sort
1533
     */
1534 2
    public function sortMeta(string $fieldName, string $metaDataKeyword) : self
1535
    {
1536
        /* It's possible that the field is already projected without the $meta
1537
         * operator. We'll assume that the user knows what they're doing in that
1538
         * case and will not attempt to override the projection.
1539
         */
1540 2
        if (! isset($this->query['select'][$fieldName])) {
1541 1
            $this->selectMeta($fieldName, $metaDataKeyword);
1542
        }
1543
1544 2
        $this->query['sort'][$fieldName] = ['$meta' => $metaDataKeyword];
1545
1546 2
        return $this;
1547
    }
1548
1549
    /**
1550
     * Specify $text criteria for the current field.
1551
     *
1552
     * The $language option may be set with {@link Builder::language()}.
1553
     *
1554
     * @see Expr::text()
1555
     * @see http://docs.mongodb.org/master/reference/operator/query/text/
1556
     */
1557 1
    public function text(string $search) : self
1558
    {
1559 1
        $this->expr->text($search);
1560 1
        return $this;
1561
    }
1562
1563
    /**
1564
     * Specify $type criteria for the current field.
1565
     *
1566
     * @see Expr::type()
1567
     * @see http://docs.mongodb.org/manual/reference/operator/type/
1568
     *
1569
     * @param int|string $type
1570
     */
1571 2
    public function type($type) : self
1572
    {
1573 2
        $this->expr->type($type);
1574 2
        return $this;
1575
    }
1576
1577
    /**
1578
     * Unset the current field.
1579
     *
1580
     * The field will be removed from the document (not set to null).
1581
     *
1582
     * @see Expr::unsetField()
1583
     * @see http://docs.mongodb.org/manual/reference/operator/unset/
1584
     */
1585 4
    public function unsetField() : self
1586
    {
1587 4
        $this->expr->unsetField();
1588 4
        return $this;
1589
    }
1590
1591 23
    public function updateOne(?string $documentName = null) : self
1592
    {
1593 23
        $this->setDocumentName($documentName);
1594 23
        $this->query['type']     = Query::TYPE_UPDATE;
1595 23
        $this->query['multiple'] = false;
1596
1597 23
        return $this;
1598
    }
1599
1600 3
    public function updateMany(?string $documentName = null) : self
1601
    {
1602 3
        $this->setDocumentName($documentName);
1603 3
        $this->query['type']     = Query::TYPE_UPDATE;
1604 3
        $this->query['multiple'] = true;
1605
1606 3
        return $this;
1607
    }
1608
1609
    /**
1610
     * Set the "upsert" option for an update or findAndUpdate query.
1611
     */
1612 7
    public function upsert(bool $bool = true) : self
1613
    {
1614 7
        $this->query['upsert'] = $bool;
1615 7
        return $this;
1616
    }
1617
1618
    /**
1619
     * Specify a JavaScript expression to use for matching documents.
1620
     *
1621
     * @see Expr::where()
1622
     * @see http://docs.mongodb.org/manual/reference/operator/where/
1623
     *
1624
     * @param string|Javascript $javascript
1625
     */
1626 3
    public function where($javascript) : self
1627
    {
1628 3
        $this->expr->where($javascript);
1629 3
        return $this;
1630
    }
1631
1632
    /**
1633
     * Get Discriminator Values
1634
     *
1635
     * @param Traversable $classNames
1636
     *
1637
     * @throws InvalidArgumentException If the number of found collections > 1.
1638
     */
1639 2
    private function getDiscriminatorValues($classNames) : array
1640
    {
1641 2
        $discriminatorValues = [];
1642 2
        $collections         = [];
1643 2
        foreach ($classNames as $className) {
1644 2
            $class                 = $this->dm->getClassMetadata($className);
1645 2
            $discriminatorValues[] = $class->discriminatorValue;
1646 2
            $key                   = $this->dm->getDocumentDatabase($className)->getDatabaseName() . '.' . $class->getCollection();
1647 2
            $collections[$key]     = $key;
1648
        }
1649 2
        if (count($collections) > 1) {
1650 1
            throw new InvalidArgumentException('Documents involved are not all mapped to the same database collection.');
1651
        }
1652 1
        return $discriminatorValues;
1653
    }
1654
1655
    /**
1656
     * @param string[]|string $documentName an array of document names or just one.
1657
     */
1658 285
    private function setDocumentName($documentName)
1659
    {
1660 285
        if (is_array($documentName)) {
1661 2
            $documentNames = $documentName;
1662 2
            $documentName  = $documentNames[0];
1663
1664 2
            $metadata            = $this->dm->getClassMetadata($documentName);
1665 2
            $discriminatorField  = $metadata->discriminatorField;
1666 2
            $discriminatorValues = $this->getDiscriminatorValues($documentNames);
0 ignored issues
show
Documentation introduced by
$documentNames is of type array, but the function expects a object<Traversable>.

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...
1667
1668
            // If a defaultDiscriminatorValue is set and it is among the discriminators being queries, add NULL to the list
1669 1
            if ($metadata->defaultDiscriminatorValue && in_array($metadata->defaultDiscriminatorValue, $discriminatorValues)) {
1670 1
                $discriminatorValues[] = null;
1671
            }
1672
1673 1
            $this->field($discriminatorField)->in($discriminatorValues);
1674
        }
1675
1676 284
        if ($documentName === null) {
1677 41
            return;
1678
        }
1679
1680 284
        $this->collection = $this->dm->getDocumentCollection($documentName);
1681 284
        $this->class      = $this->dm->getClassMetadata($documentName);
1682
1683
        // Expr also needs to know
1684 284
        $this->expr->setClassMetadata($this->class);
1685 284
    }
1686
}
1687