Completed
Pull Request — master (#1956)
by Andreas
21:58
created

Builder::currentDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
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 function array_filter;
18
use function array_key_exists;
19
use function count;
20
use function func_get_args;
21
use function in_array;
22
use function is_array;
23
use function is_bool;
24
use function is_callable;
25
use function is_string;
26
use function strtolower;
27
28
/**
29
 * Query builder for ODM.
30
 */
31
class Builder
32
{
33
    /**
34
     * The DocumentManager instance for this query
35
     *
36
     * @var DocumentManager
37
     */
38
    private $dm;
39
40
    /**
41
     * The ClassMetadata instance.
42
     *
43
     * @var ClassMetadata
44
     */
45
    private $class;
46
47
    /**
48
     * The current field we are operating on.
49
     *
50
     * @todo Change this to private once ODM requires doctrine/mongodb 1.1+
51
     * @var string
52
     */
53
    protected $currentField;
54
55
    /**
56
     * Whether or not to hydrate the data to documents.
57
     *
58
     * @var bool
59
     */
60
    private $hydrate = true;
61
62
    /**
63
     * Whether or not to refresh the data for documents that are already in the identity map.
64
     *
65
     * @var bool
66
     */
67
    private $refresh = false;
68
69
    /**
70
     * Array of primer Closure instances.
71
     *
72
     * @var array
73
     */
74
    private $primers = [];
75
76
    /**
77
     * Whether or not to register documents in UnitOfWork.
78
     *
79
     * @var bool
80
     */
81
    private $readOnly = false;
82
83
    /**
84
     * The Collection instance.
85
     *
86
     * @var Collection
87
     */
88
    private $collection;
89
90
    /**
91
     * Array containing the query data.
92
     *
93
     * @var array
94
     */
95
    private $query = ['type' => Query::TYPE_FIND];
96
97
    /**
98
     * The Expr instance used for building this query.
99
     *
100
     * This object includes the query criteria and the "new object" used for
101
     * insert and update queries.
102
     *
103
     * @var Expr $expr
104
     */
105
    private $expr;
106
107
    /**
108
     * Construct a Builder
109
     *
110
     * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none
111
     */
112 281
    public function __construct(DocumentManager $dm, $documentName = null)
113
    {
114 281
        $this->dm   = $dm;
115 281
        $this->expr = new Expr($dm);
116 281
        if ($documentName === null) {
117 9
            return;
118
        }
119
120 273
        $this->setDocumentName($documentName);
121 272
    }
122
123 1
    public function __clone()
124
    {
125 1
        $this->expr = clone $this->expr;
126 1
    }
127
128
    /**
129
     * Add one or more $and clauses to the current query.
130
     *
131
     * You can create a new expression using the {@link Builder::expr()} method.
132
     *
133
     * @see Expr::addAnd()
134
     * @see http://docs.mongodb.org/manual/reference/operator/and/
135
     *
136
     * @param array|Expr $expression
137
     * @param array|Expr ...$expressions
138
     */
139 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...
140
    {
141 4
        $this->expr->addAnd(...func_get_args());
142 4
        return $this;
143
    }
144
145
    /**
146
     * Add one or more $nor clauses to the current query.
147
     *
148
     * You can create a new expression using the {@link Builder::expr()} method.
149
     *
150
     * @see Expr::addNor()
151
     * @see http://docs.mongodb.org/manual/reference/operator/nor/
152
     *
153
     * @param array|Expr $expression
154
     * @param array|Expr ...$expressions
155
     */
156 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...
157
    {
158 3
        $this->expr->addNor(...func_get_args());
159 3
        return $this;
160
    }
161
162
    /**
163
     * Add one or more $or clauses to the current query.
164
     *
165
     * You can create a new expression using the {@link Builder::expr()} method.
166
     *
167
     * @see Expr::addOr()
168
     * @see http://docs.mongodb.org/manual/reference/operator/or/
169
     *
170
     * @param array|Expr $expression
171
     * @param array|Expr ...$expressions
172
     */
173 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...
174
    {
175 6
        $this->expr->addOr(...func_get_args());
176 6
        return $this;
177
    }
178
179
    /**
180
     * Append one or more values to the current array field only if they do not
181
     * already exist in the array.
182
     *
183
     * If the field does not exist, it will be set to an array containing the
184
     * unique value(s) in the argument. If the field is not an array, the query
185
     * will yield an error.
186
     *
187
     * Multiple values may be specified by provided an Expr object and using
188
     * {@link Expr::each()}.
189
     *
190
     * @see Expr::addToSet()
191
     * @see http://docs.mongodb.org/manual/reference/operator/addToSet/
192
     * @see http://docs.mongodb.org/manual/reference/operator/each/
193
     *
194
     * @param mixed|Expr $valueOrExpression
195
     */
196 5
    public function addToSet($valueOrExpression) : self
197
    {
198 5
        $this->expr->addToSet($valueOrExpression);
199 5
        return $this;
200
    }
201
202
    /**
203
     * Specify $all criteria for the current field.
204
     *
205
     * @see Expr::all()
206
     * @see http://docs.mongodb.org/manual/reference/operator/all/
207
     */
208 3
    public function all(array $values) : self
209
    {
210 3
        $this->expr->all($values);
211 3
        return $this;
212
    }
213
214
    /**
215
     * Apply a bitwise and operation on the current field.
216
     *
217
     * @see Expr::bitAnd()
218
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
219
     *
220
     * @return $this
221
     */
222 1
    public function bitAnd(int $value) : self
223
    {
224 1
        $this->expr->bitAnd($value);
225 1
        return $this;
226
    }
227
228
    /**
229
     * Apply a bitwise or operation on the current field.
230
     *
231
     * @see Expr::bitOr()
232
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
233
     */
234 1
    public function bitOr(int $value) : self
235
    {
236 1
        $this->expr->bitOr($value);
237 1
        return $this;
238
    }
239
240
    /**
241
     * Matches documents where all of the bit positions given by the query are
242
     * clear.
243
     *
244
     * @see Expr::bitsAllClear()
245
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllClear/
246
     *
247
     * @param int|array|Binary $value
248
     */
249 1
    public function bitsAllClear($value) : self
250
    {
251 1
        $this->expr->bitsAllClear($value);
252 1
        return $this;
253
    }
254
255
    /**
256
     * Matches documents where all of the bit positions given by the query are
257
     * set.
258
     *
259
     * @see Expr::bitsAllSet()
260
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllSet/
261
     *
262
     * @param int|array|Binary $value
263
     */
264 1
    public function bitsAllSet($value) : self
265
    {
266 1
        $this->expr->bitsAllSet($value);
267 1
        return $this;
268
    }
269
270
    /**
271
     * Matches documents where any of the bit positions given by the query are
272
     * clear.
273
     *
274
     * @see Expr::bitsAnyClear()
275
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnyClear/
276
     *
277
     * @param int|array|Binary $value
278
     */
279 1
    public function bitsAnyClear($value) : self
280
    {
281 1
        $this->expr->bitsAnyClear($value);
282 1
        return $this;
283
    }
284
285
    /**
286
     * Matches documents where any of the bit positions given by the query are
287
     * set.
288
     *
289
     * @see Expr::bitsAnySet()
290
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnySet/
291
     *
292
     * @param int|array|Binary $value
293
     */
294 1
    public function bitsAnySet($value) : self
295
    {
296 1
        $this->expr->bitsAnySet($value);
297 1
        return $this;
298
    }
299
300
    /**
301
     * Apply a bitwise xor operation on the current field.
302
     *
303
     * @see Expr::bitXor()
304
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
305
     */
306 1
    public function bitXor(int $value) : self
307
    {
308 1
        $this->expr->bitXor($value);
309 1
        return $this;
310
    }
311
312
    /**
313
     * A boolean flag to enable or disable case sensitive search for $text
314
     * criteria.
315
     *
316
     * This method must be called after text().
317
     *
318
     * @see Expr::caseSensitive()
319
     * @see http://docs.mongodb.org/manual/reference/operator/text/
320
     *
321
     * @throws BadMethodCallException If the query does not already have $text criteria.
322
     */
323 1
    public function caseSensitive(bool $caseSensitive) : self
324
    {
325 1
        $this->expr->caseSensitive($caseSensitive);
326 1
        return $this;
327
    }
328
329
    /**
330
     * Associates a comment to any expression taking a query predicate.
331
     *
332
     * @see Expr::comment()
333
     * @see http://docs.mongodb.org/manual/reference/operator/query/comment/
334
     */
335 1
    public function comment(string $comment) : self
336
    {
337 1
        $this->expr->comment($comment);
338 1
        return $this;
339
    }
340
341
    /**
342
     * Change the query type to count.
343
     */
344
    public function count() : self
345
    {
346
        $this->query['type'] = Query::TYPE_COUNT;
347
        return $this;
348
    }
349
350
    /**
351
     * Sets the value of the current field to the current date, either as a date or a timestamp.
352
     *
353
     * @see Expr::currentDate()
354
     * @see http://docs.mongodb.org/manual/reference/operator/currentDate/
355
     */
356 3
    public function currentDate(string $type = 'date') : self
357
    {
358 3
        $this->expr->currentDate($type);
359 2
        return $this;
360
    }
361
362
    /**
363
     * Return an array of information about the Builder state for debugging.
364
     *
365
     * The $name parameter may be used to return a specific key from the
366
     * internal $query array property. If omitted, the entire array will be
367
     * returned.
368
     *
369
     * @return mixed
370
     */
371 26
    public function debug(?string $name = null)
372
    {
373 26
        return $name !== null ? $this->query[$name] : $this->query;
374
    }
375
376
    /**
377
     * A boolean flag to enable or disable diacritic sensitive search for $text
378
     * criteria.
379
     *
380
     * This method must be called after text().
381
     *
382
     * @see Builder::diacriticSensitive()
383
     * @see http://docs.mongodb.org/manual/reference/operator/text/
384
     *
385
     * @throws BadMethodCallException If the query does not already have $text criteria.
386
     */
387 1
    public function diacriticSensitive(bool $diacriticSensitive) : self
388
    {
389 1
        $this->expr->diacriticSensitive($diacriticSensitive);
390 1
        return $this;
391
    }
392
393
    /**
394
     * Change the query type to a distinct command.
395
     *
396
     * @see http://docs.mongodb.org/manual/reference/command/distinct/
397
     */
398 2
    public function distinct(string $field) : self
399
    {
400 2
        $this->query['type']     = Query::TYPE_DISTINCT;
401 2
        $this->query['distinct'] = $field;
402 2
        return $this;
403
    }
404
405
    /**
406
     * Specify $elemMatch criteria for the current field.
407
     *
408
     * You can create a new expression using the {@link Builder::expr()} method.
409
     *
410
     * @see Expr::elemMatch()
411
     * @see http://docs.mongodb.org/manual/reference/operator/elemMatch/
412
     *
413
     * @param array|Expr $expression
414
     */
415 6
    public function elemMatch($expression) : self
416
    {
417 6
        $this->expr->elemMatch($expression);
418 6
        return $this;
419
    }
420
421
    /**
422
     * Specify an equality match for the current field.
423
     *
424
     * @see Expr::equals()
425
     *
426
     * @param mixed $value
427
     */
428 78
    public function equals($value) : self
429
    {
430 78
        $this->expr->equals($value);
431 78
        return $this;
432
    }
433
434
    /**
435
     * Set one or more fields to be excluded from the query projection.
436
     *
437
     * If fields have been selected for inclusion, only the "_id" field may be
438
     * excluded.
439
     *
440
     * @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...
441
     */
442 6
    public function exclude($fieldName = null) : self
443
    {
444 6
        if (! isset($this->query['select'])) {
445 6
            $this->query['select'] = [];
446
        }
447
448 6
        $fieldNames = is_array($fieldName) ? $fieldName : func_get_args();
449
450 6
        foreach ($fieldNames as $fieldName) {
451 4
            $this->query['select'][$fieldName] = 0;
452
        }
453
454 6
        return $this;
455
    }
456
457
    /**
458
     * Specify $exists criteria for the current field.
459
     *
460
     * @see Expr::exists()
461
     * @see http://docs.mongodb.org/manual/reference/operator/exists/
462
     */
463 5
    public function exists(bool $bool) : self
464
    {
465 5
        $this->expr->exists($bool);
466 5
        return $this;
467
    }
468
469
    /**
470
     * Create a new Expr instance that can be used as an expression with the Builder
471
     */
472 26
    public function expr() : Expr
473
    {
474 26
        $expr = new Expr($this->dm);
475 26
        $expr->setClassMetadata($this->class);
476
477 26
        return $expr;
478
    }
479
480
    /**
481
     * Set the current field to operate on.
482
     */
483 144
    public function field(string $field) : self
484
    {
485 144
        $this->currentField = $field;
486 144
        $this->expr->field($field);
487
488 144
        return $this;
489
    }
490
491
    /**
492
     * Change the query type to find and optionally set and change the class being queried.
493
     */
494 13
    public function find(?string $documentName = null) : self
495
    {
496 13
        $this->setDocumentName($documentName);
497 13
        $this->query['type'] = Query::TYPE_FIND;
498
499 13
        return $this;
500
    }
501
502 1
    public function findAndRemove(?string $documentName = null) : self
503
    {
504 1
        $this->setDocumentName($documentName);
505 1
        $this->query['type'] = Query::TYPE_FIND_AND_REMOVE;
506
507 1
        return $this;
508
    }
509
510 13
    public function findAndUpdate(?string $documentName = null) : self
511
    {
512 13
        $this->setDocumentName($documentName);
513 13
        $this->query['type'] = Query::TYPE_FIND_AND_UPDATE;
514
515 13
        return $this;
516
    }
517
518
    /**
519
     * Add $geoIntersects criteria with a GeoJSON geometry to the query.
520
     *
521
     * The geometry parameter GeoJSON object or an array corresponding to the
522
     * geometry's JSON representation.
523
     *
524
     * @see Expr::geoIntersects()
525
     * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/
526
     *
527
     * @param array|Geometry $geometry
528
     */
529 1
    public function geoIntersects($geometry) : self
530
    {
531 1
        $this->expr->geoIntersects($geometry);
532 1
        return $this;
533
    }
534
535
    /**
536
     * Add $geoWithin criteria with a GeoJSON geometry to the query.
537
     *
538
     * The geometry parameter GeoJSON object or an array corresponding to the
539
     * geometry's JSON representation.
540
     *
541
     * @see Expr::geoWithin()
542
     * @see http://docs.mongodb.org/manual/reference/operator/geoWithin/
543
     *
544
     * @param array|Geometry $geometry
545
     */
546 1
    public function geoWithin($geometry) : self
547
    {
548 1
        $this->expr->geoWithin($geometry);
549 1
        return $this;
550
    }
551
552
    /**
553
     * Add $geoWithin criteria with a $box shape to the query.
554
     *
555
     * A rectangular polygon will be constructed from a pair of coordinates
556
     * corresponding to the bottom left and top right corners.
557
     *
558
     * Note: the $box operator only supports legacy coordinate pairs and 2d
559
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
560
     *
561
     * @see Expr::geoWithinBox()
562
     * @see http://docs.mongodb.org/manual/reference/operator/box/
563
     */
564 1
    public function geoWithinBox(float $x1, float $y1, float $x2, float $y2) : self
565
    {
566 1
        $this->expr->geoWithinBox($x1, $y1, $x2, $y2);
567 1
        return $this;
568
    }
569
570
    /**
571
     * Add $geoWithin criteria with a $center shape to the query.
572
     *
573
     * Note: the $center operator only supports legacy coordinate pairs and 2d
574
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
575
     *
576
     * @see Expr::geoWithinCenter()
577
     * @see http://docs.mongodb.org/manual/reference/operator/center/
578
     */
579 1
    public function geoWithinCenter(float $x, float $y, float $radius) : self
580
    {
581 1
        $this->expr->geoWithinCenter($x, $y, $radius);
582 1
        return $this;
583
    }
584
585
    /**
586
     * Add $geoWithin criteria with a $centerSphere shape to the query.
587
     *
588
     * Note: the $centerSphere operator supports both 2d and 2dsphere indexes.
589
     *
590
     * @see Expr::geoWithinCenterSphere()
591
     * @see http://docs.mongodb.org/manual/reference/operator/centerSphere/
592
     */
593 1
    public function geoWithinCenterSphere(float $x, float $y, float $radius) : self
594
    {
595 1
        $this->expr->geoWithinCenterSphere($x, $y, $radius);
596 1
        return $this;
597
    }
598
599
    /**
600
     * Add $geoWithin criteria with a $polygon shape to the query.
601
     *
602
     * Point coordinates are in x, y order (easting, northing for projected
603
     * coordinates, longitude, latitude for geographic coordinates).
604
     *
605
     * The last point coordinate is implicitly connected with the first.
606
     *
607
     * Note: the $polygon operator only supports legacy coordinate pairs and 2d
608
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
609
     *
610
     * @see Expr::geoWithinPolygon()
611
     * @see http://docs.mongodb.org/manual/reference/operator/polygon/
612
     *
613
     * @param array $point1    First point of the polygon
614
     * @param array $point2    Second point of the polygon
615
     * @param array $point3    Third point of the polygon
616
     * @param array ...$points Additional points of the polygon
617
     */
618 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...
619
    {
620 1
        $this->expr->geoWithinPolygon(...func_get_args());
621 1
        return $this;
622
    }
623
624
    /**
625
     * Return the expression's "new object".
626
     *
627
     * @see Expr::getNewObj()
628
     */
629 13
    public function getNewObj() : array
630
    {
631 13
        return $this->expr->getNewObj();
632
    }
633
634
    /**
635
     * Gets the Query executable.
636
     */
637 154
    public function getQuery(array $options = []) : Query
638
    {
639 154
        $documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name);
640
641 154
        $query = $this->query;
642
643 154
        $query['query'] = $this->expr->getQuery();
644 154
        $query['query'] = $documentPersister->addDiscriminatorToPreparedQuery($query['query']);
645 154
        $query['query'] = $documentPersister->addFilterToPreparedQuery($query['query']);
646
647 154
        $query['newObj'] = $this->expr->getNewObj();
648
649 154
        if (isset($query['distinct'])) {
650 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...
651
        }
652
653 154
        if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION && ! empty($query['upsert']) &&
654 154
            (empty($query['query'][$this->class->discriminatorField]) || is_array($query['query'][$this->class->discriminatorField]))) {
655 1
            throw new InvalidArgumentException('Upsert query that is to be performed on discriminated document does not have single ' .
656 1
                'discriminator. Either not use base class or set \'' . $this->class->discriminatorField . '\' field manually.');
657
        }
658
659 153
        if (! empty($query['select'])) {
660 15
            $query['select'] = $documentPersister->prepareProjection($query['select']);
661 15
            if ($this->hydrate && $this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION
662 15
                && ! isset($query['select'][$this->class->discriminatorField])) {
663
                $includeMode = 0 < count(array_filter($query['select'], static function ($mode) {
664 2
                    return $mode === 1;
665 2
                }));
666 2
                if ($includeMode && ! isset($query['select'][$this->class->discriminatorField])) {
667 1
                    $query['select'][$this->class->discriminatorField] = 1;
668
                }
669
            }
670
        }
671
672 153
        if (isset($query['sort'])) {
673 20
            $query['sort'] = $documentPersister->prepareSort($query['sort']);
674
        }
675
676 153
        if ($this->class->readPreference && ! array_key_exists('readPreference', $query)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->class->readPreference of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
677 1
            $query['readPreference'] = new ReadPreference($this->class->readPreference, $this->class->readPreferenceTags);
678
        }
679
680 153
        return new Query(
681 153
            $this->dm,
682 153
            $this->class,
683 153
            $this->collection,
684 153
            $query,
685 153
            $options,
686 153
            $this->hydrate,
687 153
            $this->refresh,
688 153
            $this->primers,
689 153
            $this->readOnly
690
        );
691
    }
692
693
    /**
694
     * Return the expression's query criteria.
695
     *
696
     * @see Expr::getQuery()
697
     */
698 32
    public function getQueryArray() : array
699
    {
700 32
        return $this->expr->getQuery();
701
    }
702
703
    /**
704
     * Get the type of this query.
705
     */
706
    public function getType() : int
707
    {
708
        return $this->query['type'];
709
    }
710
711
    /**
712
     * Specify $gt criteria for the current field.
713
     *
714
     * @see Expr::gt()
715
     * @see http://docs.mongodb.org/manual/reference/operator/gt/
716
     *
717
     * @param mixed $value
718
     */
719 2
    public function gt($value) : self
720
    {
721 2
        $this->expr->gt($value);
722 2
        return $this;
723
    }
724
725
    /**
726
     * Specify $gte criteria for the current field.
727
     *
728
     * @see Expr::gte()
729
     * @see http://docs.mongodb.org/manual/reference/operator/gte/
730
     *
731
     * @param mixed $value
732
     */
733 2
    public function gte($value) : self
734
    {
735 2
        $this->expr->gte($value);
736 2
        return $this;
737
    }
738
739
    /**
740
     * Set the index hint for the query.
741
     *
742
     * @param array|string $index
743
     */
744
    public function hint($index) : self
745
    {
746
        $this->query['hint'] = $index;
747
        return $this;
748
    }
749
750 17
    public function hydrate(bool $bool = true) : self
751
    {
752 17
        $this->hydrate = $bool;
753 17
        return $this;
754
    }
755
756
    /**
757
     * Set the immortal cursor flag.
758
     */
759
    public function immortal(bool $bool = true) : self
760
    {
761
        $this->query['immortal'] = $bool;
762
        return $this;
763
    }
764
765
    /**
766
     * Specify $in criteria for the current field.
767
     *
768
     * @see Expr::in()
769
     * @see http://docs.mongodb.org/manual/reference/operator/in/
770
     */
771 24
    public function in(array $values) : self
772
    {
773 24
        $this->expr->in($values);
774 24
        return $this;
775
    }
776
777
    /**
778
     * Increment the current field.
779
     *
780
     * If the field does not exist, it will be set to this value.
781
     *
782
     * @see Expr::inc()
783
     * @see http://docs.mongodb.org/manual/reference/operator/inc/
784
     *
785
     * @param float|int $value
786
     */
787 6
    public function inc($value) : self
788
    {
789 6
        $this->expr->inc($value);
790 6
        return $this;
791
    }
792
793 6
    public function includesReferenceTo(object $document) : self
794
    {
795 6
        $this->expr->includesReferenceTo($document);
796 4
        return $this;
797
    }
798
799 1
    public function insert(?string $documentName = null) : self
800
    {
801 1
        $this->setDocumentName($documentName);
802 1
        $this->query['type'] = Query::TYPE_INSERT;
803
804 1
        return $this;
805
    }
806
807
    /**
808
     * Set the $language option for $text criteria.
809
     *
810
     * This method must be called after text().
811
     *
812
     * @see Expr::language()
813
     * @see http://docs.mongodb.org/manual/reference/operator/text/
814
     */
815 1
    public function language(string $language) : self
816
    {
817 1
        $this->expr->language($language);
818 1
        return $this;
819
    }
820
821
    /**
822
     * Set the limit for the query.
823
     *
824
     * This is only relevant for find queries and count commands.
825
     *
826
     * @see Query::prepareCursor()
827
     */
828 2
    public function limit(int $limit) : self
829
    {
830 2
        $this->query['limit'] = $limit;
831 2
        return $this;
832
    }
833
834
    /**
835
     * Specify $lt criteria for the current field.
836
     *
837
     * @see Expr::lte()
838
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
839
     *
840
     * @param mixed $value
841
     */
842
    public function lt($value) : self
843
    {
844
        $this->expr->lt($value);
845
        return $this;
846
    }
847
848
    /**
849
     * Specify $lte criteria for the current field.
850
     *
851
     * @see Expr::lte()
852
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
853
     *
854
     * @param mixed $value
855
     */
856
    public function lte($value) : self
857
    {
858
        $this->expr->lte($value);
859
        return $this;
860
    }
861
862
    /**
863
     * Updates the value of the field to a specified value if the specified value is greater than the current value of the field.
864
     *
865
     * @see Expr::max()
866
     * @see http://docs.mongodb.org/manual/reference/operator/update/max/
867
     *
868
     * @param mixed $value
869
     */
870 1
    public function max($value) : self
871
    {
872 1
        $this->expr->max($value);
873 1
        return $this;
874
    }
875
876
    /**
877
     * Specifies a cumulative time limit in milliseconds for processing operations on a cursor.
878
     */
879
    public function maxTimeMS(int $ms) : self
880
    {
881
        $this->query['maxTimeMS'] = $ms;
882
        return $this;
883
    }
884
885
    /**
886
     * Updates the value of the field to a specified value if the specified value is less than the current value of the field.
887
     *
888
     * @see Expr::min()
889
     * @see http://docs.mongodb.org/manual/reference/operator/update/min/
890
     *
891
     * @param mixed $value
892
     */
893 1
    public function min($value) : self
894
    {
895 1
        $this->expr->min($value);
896 1
        return $this;
897
    }
898
899
    /**
900
     * Specify $mod criteria for the current field.
901
     *
902
     * @see Expr::mod()
903
     * @see http://docs.mongodb.org/manual/reference/operator/mod/
904
     *
905
     * @param float|int $divisor
906
     * @param float|int $remainder
907
     */
908 1
    public function mod($divisor, $remainder = 0) : self
909
    {
910 1
        $this->expr->mod($divisor, $remainder);
911 1
        return $this;
912
    }
913
914
    /**
915
     * Multiply the current field.
916
     *
917
     * If the field does not exist, it will be set to 0.
918
     *
919
     * @see Expr::mul()
920
     * @see http://docs.mongodb.org/manual/reference/operator/mul/
921
     *
922
     * @param float|int $value
923
     */
924 1
    public function mul($value) : self
925
    {
926 1
        $this->expr->mul($value);
927 1
        return $this;
928
    }
929
930
    /**
931
     * Add $near criteria to the query.
932
     *
933
     * A GeoJSON point may be provided as the first and only argument for
934
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
935
     * an array corresponding to the point's JSON representation.
936
     *
937
     * @see Expr::near()
938
     * @see http://docs.mongodb.org/manual/reference/operator/near/
939
     *
940
     * @param float|array|Point $x
941
     * @param float             $y
942
     */
943 1
    public function near($x, $y = null) : self
944
    {
945 1
        $this->expr->near($x, $y);
946 1
        return $this;
947
    }
948
949
    /**
950
     * Add $nearSphere criteria to the query.
951
     *
952
     * A GeoJSON point may be provided as the first and only argument for
953
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
954
     * an array corresponding to the point's JSON representation.
955
     *
956
     * @see Expr::nearSphere()
957
     * @see http://docs.mongodb.org/manual/reference/operator/nearSphere/
958
     *
959
     * @param float|array|Point $x
960
     * @param float             $y
961
     */
962 1
    public function nearSphere($x, $y = null) : self
963
    {
964 1
        $this->expr->nearSphere($x, $y);
965 1
        return $this;
966
    }
967
968
    /**
969
     * Negates an expression for the current field.
970
     *
971
     * You can create a new expression using the {@link Builder::expr()} method.
972
     *
973
     * @see Expr::not()
974
     * @see http://docs.mongodb.org/manual/reference/operator/not/
975
     *
976
     * @param array|Expr $expression
977
     */
978 3
    public function not($expression) : self
979
    {
980 3
        $this->expr->not($expression);
981 3
        return $this;
982
    }
983
984
    /**
985
     * Specify $ne criteria for the current field.
986
     *
987
     * @see Expr::notEqual()
988
     * @see http://docs.mongodb.org/manual/reference/operator/ne/
989
     *
990
     * @param mixed $value
991
     */
992 4
    public function notEqual($value) : self
993
    {
994 4
        $this->expr->notEqual($value);
995 4
        return $this;
996
    }
997
998
    /**
999
     * Specify $nin criteria for the current field.
1000
     *
1001
     * @see Expr::notIn()
1002
     * @see http://docs.mongodb.org/manual/reference/operator/nin/
1003
     *
1004
     * @param array $values
1005
     */
1006 4
    public function notIn(array $values) : self
1007
    {
1008 4
        $this->expr->notIn($values);
1009 4
        return $this;
1010
    }
1011
1012
    /**
1013
     * Remove the first element from the current array field.
1014
     *
1015
     * @see Expr::popFirst()
1016
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
1017
     */
1018 3
    public function popFirst() : self
1019
    {
1020 3
        $this->expr->popFirst();
1021 3
        return $this;
1022
    }
1023
1024
    /**
1025
     * Remove the last element from the current array field.
1026
     *
1027
     * @see Expr::popLast()
1028
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
1029
     */
1030 2
    public function popLast() : self
1031
    {
1032 2
        $this->expr->popLast();
1033 2
        return $this;
1034
    }
1035
1036
    /**
1037
     * Use a primer to eagerly load all references in the current field.
1038
     *
1039
     * If $primer is true or a callable is provided, referenced documents for
1040
     * this field will loaded into UnitOfWork immediately after the query is
1041
     * executed. This will avoid multiple queries due to lazy initialization of
1042
     * Proxy objects.
1043
     *
1044
     * If $primer is false, no priming will take place. That is also the default
1045
     * behavior.
1046
     *
1047
     * If a custom callable is used, its signature should conform to the default
1048
     * Closure defined in {@link ReferencePrimer::__construct()}.
1049
     *
1050
     * @param bool|callable $primer
1051
     *
1052
     * @throws InvalidArgumentException If $primer is not boolean or callable.
1053
     */
1054 22
    public function prime($primer = true) : self
1055
    {
1056 22
        if (! is_bool($primer) && ! is_callable($primer)) {
1057 1
            throw new InvalidArgumentException('$primer is not a boolean or callable');
1058
        }
1059
1060 21
        if ($primer === false) {
1061
            unset($this->primers[$this->currentField]);
1062
1063
            return $this;
1064
        }
1065
1066 21
        $this->primers[$this->currentField] = $primer;
1067 21
        return $this;
1068
    }
1069
1070
    /**
1071
     * Remove all elements matching the given value or expression from the
1072
     * current array field.
1073
     *
1074
     * @see Expr::pull()
1075
     * @see http://docs.mongodb.org/manual/reference/operator/pull/
1076
     *
1077
     * @param mixed|Expr $valueOrExpression
1078
     */
1079 1
    public function pull($valueOrExpression) : self
1080
    {
1081 1
        $this->expr->pull($valueOrExpression);
1082 1
        return $this;
1083
    }
1084
1085
    /**
1086
     * Remove all elements matching any of the given values from the current
1087
     * array field.
1088
     *
1089
     * @see Expr::pullAll()
1090
     * @see http://docs.mongodb.org/manual/reference/operator/pullAll/
1091
     */
1092 1
    public function pullAll(array $values) : self
1093
    {
1094 1
        $this->expr->pullAll($values);
1095 1
        return $this;
1096
    }
1097
1098
    /**
1099
     * Append one or more values to the current array field.
1100
     *
1101
     * If the field does not exist, it will be set to an array containing the
1102
     * value(s) in the argument. If the field is not an array, the query
1103
     * will yield an error.
1104
     *
1105
     * Multiple values may be specified by providing an Expr object and using
1106
     * {@link Expr::each()}. {@link Expr::slice()} and {@link Expr::sort()} may
1107
     * also be used to limit and order array elements, respectively.
1108
     *
1109
     * @see Expr::push()
1110
     * @see http://docs.mongodb.org/manual/reference/operator/push/
1111
     * @see http://docs.mongodb.org/manual/reference/operator/each/
1112
     * @see http://docs.mongodb.org/manual/reference/operator/slice/
1113
     * @see http://docs.mongodb.org/manual/reference/operator/sort/
1114
     *
1115
     * @param mixed|Expr $valueOrExpression
1116
     */
1117 6
    public function push($valueOrExpression) : self
1118
    {
1119 6
        $this->expr->push($valueOrExpression);
1120 6
        return $this;
1121
    }
1122
1123
    /**
1124
     * Specify $gte and $lt criteria for the current field.
1125
     *
1126
     * This method is shorthand for specifying $gte criteria on the lower bound
1127
     * and $lt criteria on the upper bound. The upper bound is not inclusive.
1128
     *
1129
     * @see Expr::range()
1130
     *
1131
     * @param mixed $start
1132
     * @param mixed $end
1133
     */
1134 3
    public function range($start, $end) : self
1135
    {
1136 3
        $this->expr->range($start, $end);
1137 3
        return $this;
1138
    }
1139
1140 2
    public function readOnly(bool $bool = true) : self
1141
    {
1142 2
        $this->readOnly = $bool;
1143 2
        return $this;
1144
    }
1145
1146 10
    public function references(object $document) : self
1147
    {
1148 10
        $this->expr->references($document);
1149 8
        return $this;
1150
    }
1151
1152 5
    public function refresh(bool $bool = true) : self
1153
    {
1154 5
        $this->refresh = $bool;
1155 5
        return $this;
1156
    }
1157
1158 1
    public function remove(?string $documentName = null) : self
1159
    {
1160 1
        $this->setDocumentName($documentName);
1161 1
        $this->query['type'] = Query::TYPE_REMOVE;
1162
1163 1
        return $this;
1164
    }
1165
1166
    /**
1167
     * Rename the current field.
1168
     *
1169
     * @see Expr::rename()
1170
     * @see http://docs.mongodb.org/manual/reference/operator/rename/
1171
     */
1172
    public function rename(string $name) : self
1173
    {
1174
        $this->expr->rename($name);
1175
        return $this;
1176
    }
1177
1178 4
    public function returnNew(bool $bool = true) : self
1179
    {
1180 4
        $this->refresh(true);
1181 4
        $this->query['new'] = $bool;
1182
1183 4
        return $this;
1184
    }
1185
1186
    /**
1187
     * Set one or more fields to be included in the query projection.
1188
     *
1189
     * @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...
1190
     */
1191 19
    public function select($fieldName = null) : self
1192
    {
1193 19
        if (! isset($this->query['select'])) {
1194 18
            $this->query['select'] = [];
1195
        }
1196
1197 19
        $fieldNames = is_array($fieldName) ? $fieldName : func_get_args();
1198
1199 19
        foreach ($fieldNames as $fieldName) {
1200 16
            $this->query['select'][$fieldName] = 1;
1201
        }
1202
1203 19
        return $this;
1204
    }
1205
1206
    /**
1207
     * Select only matching embedded documents in an array field for the query
1208
     * projection.
1209
     *
1210
     * @see http://docs.mongodb.org/manual/reference/projection/elemMatch/
1211
     *
1212
     * @param array|Expr $expression
1213
     */
1214 2
    public function selectElemMatch(string $fieldName, $expression) : self
1215
    {
1216 2
        if ($expression instanceof Expr) {
1217 1
            $expression = $expression->getQuery();
1218
        }
1219 2
        $this->query['select'][$fieldName] = ['$elemMatch' => $expression];
1220 2
        return $this;
1221
    }
1222
1223
    /**
1224
     * Select a metadata field for the query projection.
1225
     *
1226
     * @see http://docs.mongodb.org/master/reference/operator/projection/meta/
1227
     */
1228 3
    public function selectMeta(string $fieldName, string $metaDataKeyword) : self
1229
    {
1230 3
        $this->query['select'][$fieldName] = ['$meta' => $metaDataKeyword];
1231 3
        return $this;
1232
    }
1233
1234
    /**
1235
     * Select a slice of an array field for the query projection.
1236
     *
1237
     * The $countOrSkip parameter has two very different meanings, depending on
1238
     * whether or not $limit is provided. See the MongoDB documentation for more
1239
     * information.
1240
     *
1241
     * @see http://docs.mongodb.org/manual/reference/projection/slice/
1242
     */
1243 3
    public function selectSlice(string $fieldName, int $countOrSkip, ?int $limit = null) : self
1244
    {
1245 3
        $slice = $countOrSkip;
1246 3
        if ($limit !== null) {
1247 2
            $slice = [$slice, $limit];
1248
        }
1249 3
        $this->query['select'][$fieldName] = ['$slice' => $slice];
1250 3
        return $this;
1251
    }
1252
1253
    /**
1254
     * Set the current field to a value.
1255
     *
1256
     * This is only relevant for insert, update, or findAndUpdate queries. For
1257
     * update and findAndUpdate queries, the $atomic parameter will determine
1258
     * whether or not a $set operator is used.
1259
     *
1260
     * @see Expr::set()
1261
     * @see http://docs.mongodb.org/manual/reference/operator/set/
1262
     *
1263
     * @param mixed $value
1264
     */
1265 16
    public function set($value, bool $atomic = true) : self
1266
    {
1267 16
        $this->expr->set($value, $atomic && $this->query['type'] !== Query::TYPE_INSERT);
1268 16
        return $this;
1269
    }
1270
1271
    /**
1272
     * Set the expression's "new object".
1273
     *
1274
     * @see Expr::setNewObj()
1275
     */
1276
    public function setNewObj(array $newObj) : self
1277
    {
1278
        $this->expr->setNewObj($newObj);
1279
        return $this;
1280
    }
1281
1282
    /**
1283
     * Set the current field to the value if the document is inserted in an
1284
     * upsert operation.
1285
     *
1286
     * If an update operation with upsert: true results in an insert of a
1287
     * document, then $setOnInsert assigns the specified values to the fields in
1288
     * the document. If the update operation does not result in an insert,
1289
     * $setOnInsert does nothing.
1290
     *
1291
     * @see Expr::setOnInsert()
1292
     * @see https://docs.mongodb.org/manual/reference/operator/update/setOnInsert/
1293
     *
1294
     * @param mixed $value
1295
     */
1296 2
    public function setOnInsert($value) : self
1297
    {
1298 2
        $this->expr->setOnInsert($value);
1299 2
        return $this;
1300
    }
1301
1302
    /**
1303
     * Set the read preference for the query.
1304
     *
1305
     * This is only relevant for read-only queries and commands.
1306
     *
1307
     * @see http://docs.mongodb.org/manual/core/read-preference/
1308
     */
1309 6
    public function setReadPreference(ReadPreference $readPreference) : self
1310
    {
1311 6
        $this->query['readPreference'] = $readPreference;
1312 6
        return $this;
1313
    }
1314
1315
    /**
1316
     * Set the expression's query criteria.
1317
     *
1318
     * @see Expr::setQuery()
1319
     */
1320 18
    public function setQueryArray(array $query) : self
1321
    {
1322 18
        $this->expr->setQuery($query);
1323 18
        return $this;
1324
    }
1325
1326
    /**
1327
     * Specify $size criteria for the current field.
1328
     *
1329
     * @see Expr::size()
1330
     * @see http://docs.mongodb.org/manual/reference/operator/size/
1331
     */
1332 1
    public function size(int $size) : self
1333
    {
1334 1
        $this->expr->size($size);
1335 1
        return $this;
1336
    }
1337
1338
    /**
1339
     * Set the skip for the query cursor.
1340
     *
1341
     * This is only relevant for find queries, or mapReduce queries that store
1342
     * results in an output collection and return a cursor.
1343
     *
1344
     * @see Query::prepareCursor()
1345
     */
1346
    public function skip(int $skip) : self
1347
    {
1348
        $this->query['skip'] = $skip;
1349
        return $this;
1350
    }
1351
1352
    /**
1353
     * Set the snapshot cursor flag.
1354
     */
1355
    public function snapshot(bool $bool = true) : self
1356
    {
1357
        $this->query['snapshot'] = $bool;
1358
        return $this;
1359
    }
1360
1361
    /**
1362
     * Set one or more field/order pairs on which to sort the query.
1363
     *
1364
     * If sorting by multiple fields, the first argument should be an array of
1365
     * field name (key) and order (value) pairs.
1366
     *
1367
     * @param array|string $fieldName Field name or array of field/order pairs
1368
     * @param int|string   $order     Field order (if one field is specified)
1369
     */
1370 28
    public function sort($fieldName, $order = 1) : self
1371
    {
1372 28
        if (! isset($this->query['sort'])) {
1373 28
            $this->query['sort'] = [];
1374
        }
1375
1376 28
        $fields = is_array($fieldName) ? $fieldName : [$fieldName => $order];
1377
1378 28
        foreach ($fields as $fieldName => $order) {
1379 15
            if (is_string($order)) {
1380 9
                $order = strtolower($order) === 'asc' ? 1 : -1;
1381
            }
1382 15
            $this->query['sort'][$fieldName] = (int) $order;
1383
        }
1384
1385 28
        return $this;
1386
    }
1387
1388
    /**
1389
     * Specify a projected metadata field on which to sort the query.
1390
     *
1391
     * Sort order is not configurable for metadata fields. Sorting by a metadata
1392
     * field requires the same field and $meta expression to exist in the
1393
     * projection document. This method will call {@link Builder::selectMeta()}
1394
     * if the field is not already set in the projection.
1395
     *
1396
     * @see http://docs.mongodb.org/master/reference/operator/projection/meta/#sort
1397
     */
1398 3
    public function sortMeta(string $fieldName, string $metaDataKeyword) : self
1399
    {
1400
        /* It's possible that the field is already projected without the $meta
1401
         * operator. We'll assume that the user knows what they're doing in that
1402
         * case and will not attempt to override the projection.
1403
         */
1404 3
        if (! isset($this->query['select'][$fieldName])) {
1405 2
            $this->selectMeta($fieldName, $metaDataKeyword);
1406
        }
1407
1408 3
        $this->query['sort'][$fieldName] = ['$meta' => $metaDataKeyword];
1409
1410 3
        return $this;
1411
    }
1412
1413
    /**
1414
     * Specify $text criteria for the current field.
1415
     *
1416
     * The $language option may be set with {@link Builder::language()}.
1417
     *
1418
     * @see Expr::text()
1419
     * @see http://docs.mongodb.org/master/reference/operator/query/text/
1420
     */
1421 1
    public function text(string $search) : self
1422
    {
1423 1
        $this->expr->text($search);
1424 1
        return $this;
1425
    }
1426
1427
    /**
1428
     * Specify $type criteria for the current field.
1429
     *
1430
     * @see Expr::type()
1431
     * @see http://docs.mongodb.org/manual/reference/operator/type/
1432
     *
1433
     * @param int|string $type
1434
     */
1435 2
    public function type($type) : self
1436
    {
1437 2
        $this->expr->type($type);
1438 2
        return $this;
1439
    }
1440
1441
    /**
1442
     * Unset the current field.
1443
     *
1444
     * The field will be removed from the document (not set to null).
1445
     *
1446
     * @see Expr::unsetField()
1447
     * @see http://docs.mongodb.org/manual/reference/operator/unset/
1448
     */
1449 4
    public function unsetField() : self
1450
    {
1451 4
        $this->expr->unsetField();
1452 4
        return $this;
1453
    }
1454
1455 23
    public function updateOne(?string $documentName = null) : self
1456
    {
1457 23
        $this->setDocumentName($documentName);
1458 23
        $this->query['type']     = Query::TYPE_UPDATE;
1459 23
        $this->query['multiple'] = false;
1460
1461 23
        return $this;
1462
    }
1463
1464 3
    public function updateMany(?string $documentName = null) : self
1465
    {
1466 3
        $this->setDocumentName($documentName);
1467 3
        $this->query['type']     = Query::TYPE_UPDATE;
1468 3
        $this->query['multiple'] = true;
1469
1470 3
        return $this;
1471
    }
1472
1473
    /**
1474
     * Set the "upsert" option for an update or findAndUpdate query.
1475
     */
1476 7
    public function upsert(bool $bool = true) : self
1477
    {
1478 7
        $this->query['upsert'] = $bool;
1479 7
        return $this;
1480
    }
1481
1482
    /**
1483
     * Specify a JavaScript expression to use for matching documents.
1484
     *
1485
     * @see Expr::where()
1486
     * @see http://docs.mongodb.org/manual/reference/operator/where/
1487
     *
1488
     * @param string|Javascript $javascript
1489
     */
1490 3
    public function where($javascript) : self
1491
    {
1492 3
        $this->expr->where($javascript);
1493 3
        return $this;
1494
    }
1495
1496
    /**
1497
     * Get Discriminator Values
1498
     *
1499
     * @param string[] $classNames
1500
     *
1501
     * @throws InvalidArgumentException If the number of found collections > 1.
1502
     */
1503 2
    private function getDiscriminatorValues($classNames) : array
1504
    {
1505 2
        $discriminatorValues = [];
1506 2
        $collections         = [];
1507 2
        foreach ($classNames as $className) {
1508 2
            $class                 = $this->dm->getClassMetadata($className);
1509 2
            $discriminatorValues[] = $class->discriminatorValue;
1510 2
            $key                   = $this->dm->getDocumentDatabase($className)->getDatabaseName() . '.' . $class->getCollection();
1511 2
            $collections[$key]     = $key;
1512
        }
1513 2
        if (count($collections) > 1) {
1514 1
            throw new InvalidArgumentException('Documents involved are not all mapped to the same database collection.');
1515
        }
1516 1
        return $discriminatorValues;
1517
    }
1518
1519
    /**
1520
     * @param string[]|string|null $documentName an array of document names or just one.
1521
     */
1522 280
    private function setDocumentName($documentName)
1523
    {
1524 280
        if (is_array($documentName)) {
1525 2
            $documentNames = $documentName;
1526 2
            $documentName  = $documentNames[0];
1527
1528 2
            $metadata            = $this->dm->getClassMetadata($documentName);
1529 2
            $discriminatorField  = $metadata->discriminatorField ?? ClassMetadata::DEFAULT_DISCRIMINATOR_FIELD;
1530 2
            $discriminatorValues = $this->getDiscriminatorValues($documentNames);
1531
1532
            // If a defaultDiscriminatorValue is set and it is among the discriminators being queries, add NULL to the list
1533 1
            if ($metadata->defaultDiscriminatorValue && in_array($metadata->defaultDiscriminatorValue, $discriminatorValues)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $metadata->defaultDiscriminatorValue of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1534 1
                $discriminatorValues[] = null;
1535
            }
1536
1537 1
            $this->field($discriminatorField)->in($discriminatorValues);
1538
        }
1539
1540 279
        if ($documentName === null) {
1541 41
            return;
1542
        }
1543
1544 279
        $this->collection = $this->dm->getDocumentCollection($documentName);
1545 279
        $this->class      = $this->dm->getClassMetadata($documentName);
1546
1547
        // Expr also needs to know
1548 279
        $this->expr->setClassMetadata($this->class);
1549 279
    }
1550
}
1551