Completed
Pull Request — master (#1803)
by Andreas
16:48 queued 09:05
created

Expr::ln()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
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\Aggregation;
6
7
use BadMethodCallException;
8
use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
9
use Doctrine\ODM\MongoDB\DocumentManager;
10
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
11
use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
12
use Doctrine\ODM\MongoDB\Types\Type;
13
use LogicException;
14
use function array_map;
15
use function array_merge;
16
use function assert;
17
use function func_get_args;
18
use function is_array;
19
use function is_string;
20
use function substr;
21
22
/**
23
 * Fluent interface for building aggregation pipelines.
24
 */
25
class Expr
26
{
27
    /** @var DocumentManager */
28
    private $dm;
29
30
    /** @var ClassMetadata */
31
    private $class;
32
33
    /** @var array */
34
    private $expr = [];
35
36
    /**
37
     * The current field we are operating on.
38
     *
39
     * @var string
40
     */
41
    private $currentField;
42
43
    /** @var array|null */
44
    private $switchBranch;
45
46
    /**
47
     * @inheritDoc
48
     */
49 367
    public function __construct(DocumentManager $dm, ClassMetadataInterface $class)
50
    {
51 367
        assert($class instanceof ClassMetadata);
52 367
        $this->dm    = $dm;
53 367
        $this->class = $class;
54 367
    }
55
56
    /**
57
     * Returns the absolute value of a number.
58
     *
59
     * The <number> argument can be any valid expression as long as it resolves
60
     * to a number.
61
     *
62
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/abs/
63
     *
64
     * @param mixed|self $number
65
     */
66 3
    public function abs($number) : self
67
    {
68 3
        return $this->operator('$abs', $number);
69
    }
70
71
    /**
72
     * Adds numbers together or adds numbers and a date. If one of the arguments
73
     * is a date, $add treats the other arguments as milliseconds to add to the
74
     * date.
75
     *
76
     * The arguments can be any valid expression as long as they resolve to
77
     * either all numbers or to numbers and a date.
78
     *
79
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/add/
80
     *
81
     * @param mixed|self $expression1
82
     * @param mixed|self $expression2
83
     * @param mixed|self ...$expressions Additional expressions
84
     */
85 15
    public function add($expression1, $expression2, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression1 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 $expression2 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...
86
    {
87 15
        return $this->operator('$add', func_get_args());
88
    }
89
90
    /**
91
     * Adds one or more $and clauses to the current expression.
92
     *
93
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/and/
94
     *
95
     * @param array|self $expression
96
     * @param array|self ...$expressions
97
     */
98 1
    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...
99
    {
100 1
        if (! isset($this->expr['$and'])) {
101 1
            $this->expr['$and'] = [];
102
        }
103
104 1
        $this->expr['$and'] = array_merge($this->expr['$and'], array_map([$this, 'ensureArray'], func_get_args()));
105
106 1
        return $this;
107
    }
108
109
    /**
110
     * Adds one or more $or clause to the current expression.
111
     *
112
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/or/
113
     *
114
     * @param array|self $expression
115
     * @param array|self ...$expressions
116
     */
117
    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...
118
    {
119
        if (! isset($this->expr['$or'])) {
120
            $this->expr['$or'] = [];
121
        }
122
123
        $this->expr['$or'] = array_merge($this->expr['$or'], array_map([$this, 'ensureArray'], func_get_args()));
124
125
        return $this;
126
    }
127
128
    /**
129
     * Returns an array of all unique values that results from applying an
130
     * expression to each document in a group of documents that share the same
131
     * group by key. Order of the elements in the output array is unspecified.
132
     *
133
     * AddToSet is an accumulator operation only available in the group stage.
134
     *
135
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/addToSet/
136
     *
137
     * @param mixed|self $expression
138
     */
139 2
    public function addToSet($expression) : self
140
    {
141 2
        return $this->operator('$addToSet', $expression);
142
    }
143
144
    /**
145
     * Evaluates an array as a set and returns true if no element in the array
146
     * is false. Otherwise, returns false. An empty array returns true.
147
     *
148
     * The expression must resolve to an array.
149
     *
150
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/allElementsTrue/
151
     *
152
     * @param mixed|self $expression
153
     */
154 3
    public function allElementsTrue($expression) : self
155
    {
156 3
        return $this->operator('$allElementsTrue', $expression);
157
    }
158
159
    /**
160
     * Evaluates an array as a set and returns true if any of the elements are
161
     * true and false otherwise. An empty array returns false.
162
     *
163
     * The expression must resolve to an array.
164
     *
165
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/anyElementTrue/
166
     *
167
     * @param array|self $expression
168
     */
169 3
    public function anyElementTrue($expression) : self
170
    {
171 3
        return $this->operator('$anyElementTrue', $expression);
172
    }
173
174
    /**
175
     * Returns the element at the specified array index.
176
     *
177
     * The <array> expression can be any valid expression as long as it resolves
178
     * to an array.
179
     * The <idx> expression can be any valid expression as long as it resolves
180
     * to an integer.
181
     *
182
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/arrayElemAt/
183
     *
184
     * @param mixed|self $array
185
     * @param mixed|self $index
186
     */
187 3
    public function arrayElemAt($array, $index) : self
188
    {
189 3
        return $this->operator('$arrayElemAt', [$array, $index]);
190
    }
191
192
    /**
193
     * Returns the average value of the numeric values that result from applying
194
     * a specified expression to each document in a group of documents that
195
     * share the same group by key. Ignores nun-numeric values.
196
     *
197
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/avg/
198
     *
199
     * @param mixed|self $expression
200
     */
201 10
    public function avg($expression) : self
202
    {
203 10
        return $this->operator('$avg', $expression);
204
    }
205
206
    /**
207
     * Adds a case statement for a branch of the $switch operator.
208
     *
209
     * Requires {@link switch()} to be called first. The argument can be any
210
     * valid expression that resolves to a boolean. If the result is not a
211
     * boolean, it is coerced to a boolean value.
212
     *
213
     * @param mixed|self $expression
214
     */
215 6
    public function case($expression) : self
216
    {
217 6
        $this->requiresSwitchStatement(static::class . '::case');
218
219 4
        $this->switchBranch = ['case' => $expression];
220
221 4
        return $this;
222
    }
223
224
    /**
225
     * Returns the smallest integer greater than or equal to the specified number.
226
     *
227
     * The <number> expression can be any valid expression as long as it
228
     * resolves to a number.
229
     *
230
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/ceil/
231
     *
232
     * @param mixed|self $number
233
     */
234 3
    public function ceil($number) : self
235
    {
236 3
        return $this->operator('$ceil', $number);
237
    }
238
239
    /**
240
     * Compares two values and returns:
241
     * -1 if the first value is less than the second.
242
     * 1 if the first value is greater than the second.
243
     * 0 if the two values are equivalent.
244
     *
245
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/cmp/
246
     *
247
     * @param mixed|self $expression1
248
     * @param mixed|self $expression2
249
     */
250 3
    public function cmp($expression1, $expression2) : self
251
    {
252 3
        return $this->operator('$cmp', [$expression1, $expression2]);
253
    }
254
255
    /**
256
     * Concatenates strings and returns the concatenated string.
257
     *
258
     * The arguments can be any valid expression as long as they resolve to
259
     * strings. If the argument resolves to a value of null or refers to a field
260
     * that is missing, $concat returns null.
261
     *
262
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/concat/
263
     *
264
     * @param mixed|self $expression1
265
     * @param mixed|self $expression2
266
     * @param mixed|self ...$expressions Additional expressions
267
     */
268 9
    public function concat($expression1, $expression2, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression1 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 $expression2 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...
269
    {
270 9
        return $this->operator('$concat', func_get_args());
271
    }
272
273
    /**
274
     * Concatenates arrays to return the concatenated array.
275
     *
276
     * The <array> expressions can be any valid expression as long as they
277
     * resolve to an array.
278
     *
279
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/concatArrays/
280
     *
281
     * @param mixed|self $array1
282
     * @param mixed|self $array2
283
     * @param mixed|self ...$arrays Additional expressions
284
     */
285 6
    public function concatArrays($array1, $array2, ...$arrays) : self
0 ignored issues
show
Unused Code introduced by
The parameter $array1 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 $array2 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 $arrays 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...
286
    {
287 6
        return $this->operator('$concatArrays', func_get_args());
288
    }
289
290
    /**
291
     * Evaluates a boolean expression to return one of the two specified return
292
     * expressions.
293
     *
294
     * The arguments can be any valid expression.
295
     *
296
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/cond/
297
     *
298
     * @param mixed|self $if
299
     * @param mixed|self $then
300
     * @param mixed|self $else
301
     */
302 10
    public function cond($if, $then, $else) : self
303
    {
304 10
        return $this->operator('$cond', ['if' => $if, 'then' => $then, 'else' => $else]);
305
    }
306
307
    /**
308
     * Converts an expression object into an array, recursing into nested items
309
     *
310
     * For expression objects, it calls getExpression on the expression object.
311
     * For arrays, it recursively calls itself for each array item. Other values
312
     * are returned directly.
313
     *
314
     * @internal
315
     *
316
     * @param mixed|self $expression
317
     *
318
     * @return string|array
319
     */
320 1
    public static function convertExpression($expression)
321
    {
322 1
        if (is_array($expression)) {
323
            return array_map(static function ($expression) {
324
                return static::convertExpression($expression);
325
            }, $expression);
326 1
        } elseif ($expression instanceof self) {
327 1
            return $expression->getExpression();
328
        }
329
330
        return $expression;
331
    }
332
333
    /**
334
     * Converts a date object to a string according to a user-specified format.
335
     *
336
     * The format string can be any string literal, containing 0 or more format
337
     * specifiers.
338
     * The date argument can be any expression as long as it resolves to a date.
339
     *
340
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/dateToString/
341
     *
342
     * @param mixed|self $expression
343
     */
344 3
    public function dateToString(string $format, $expression) : self
345
    {
346 3
        return $this->operator('$dateToString', ['format' => $format, 'date' => $expression]);
347
    }
348
349
    /**
350
     * Returns the day of the month for a date as a number between 1 and 31.
351
     *
352
     * The argument can be any expression as long as it resolves to a date.
353
     *
354
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/dayOfMonth/
355
     *
356
     * @param mixed|self $expression
357
     */
358 7
    public function dayOfMonth($expression) : self
359
    {
360 7
        return $this->operator('$dayOfMonth', $expression);
361
    }
362
363
    /**
364
     * Returns the day of the week for a date as a number between 1 (Sunday) and
365
     * 7 (Saturday).
366
     *
367
     * The argument can be any expression as long as it resolves to a date.
368
     *
369
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/dayOfWeek/
370
     *
371
     * @param mixed|self $expression
372
     */
373 7
    public function dayOfWeek($expression) : self
374
    {
375 7
        return $this->operator('$dayOfWeek', $expression);
376
    }
377
378
    /**
379
     * Returns the day of the year for a date as a number between 1 and 366.
380
     *
381
     * The argument can be any expression as long as it resolves to a date.
382
     *
383
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/dayOfYear/
384
     *
385
     * @param mixed|self $expression
386
     */
387 3
    public function dayOfYear($expression) : self
388
    {
389 3
        return $this->operator('$dayOfYear', $expression);
390
    }
391
392
    /**
393
     * Adds a default statement for the current $switch operator.
394
     *
395
     * Requires {@link switch()} to be called first. The argument can be any
396
     * valid expression.
397
     *
398
     * Note: if no default is specified and no branch evaluates to true, the
399
     * $switch operator throws an error.
400
     *
401
     * @param mixed|self $expression
402
     */
403 4
    public function default($expression) : self
404
    {
405 4
        $this->requiresSwitchStatement(static::class . '::default');
406
407 2
        if ($this->currentField) {
408
            $this->expr[$this->currentField]['$switch']['default'] = $this->ensureArray($expression);
409
        } else {
410 2
            $this->expr['$switch']['default'] = $this->ensureArray($expression);
411
        }
412
413 2
        return $this;
414
    }
415
416
    /**
417
     * Divides one number by another and returns the result. The first argument
418
     * is divided by the second argument.
419
     *
420
     * The arguments can be any valid expression as long as the resolve to numbers.
421
     *
422
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/divide/
423
     *
424
     * @param mixed|self $expression1
425
     * @param mixed|self $expression2
426
     */
427 3
    public function divide($expression1, $expression2) : self
428
    {
429 3
        return $this->operator('$divide', [$expression1, $expression2]);
430
    }
431
432
    /**
433
     * Compares two values and returns whether the are equivalent.
434
     *
435
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/eq/
436
     *
437
     * @param mixed|self $expression1
438
     * @param mixed|self $expression2
439
     */
440 9
    public function eq($expression1, $expression2) : self
441
    {
442 9
        return $this->operator('$eq', [$expression1, $expression2]);
443
    }
444
445
    /**
446
     * Raises Euler’s number to the specified exponent and returns the result.
447
     *
448
     * The <exponent> expression can be any valid expression as long as it
449
     * resolves to a number.
450
     *
451
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/exp/
452
     *
453
     * @param mixed|self $exponent
454
     */
455 3
    public function exp($exponent) : self
456
    {
457 3
        return $this->operator('$exp', $exponent);
458
    }
459
460
    /**
461
     * Returns a new expression object
462
     */
463 4
    public function expr() : self
464
    {
465 4
        return new static($this->dm, $this->class);
466
    }
467
468
    /**
469
     * Allows any expression to be used as a field value.
470
     *
471
     * @see http://docs.mongodb.org/manual/meta/aggregation-quick-reference/#aggregation-expressions
472
     *
473
     * @param mixed|self $value
474
     */
475 12
    public function expression($value) : self
476
    {
477 12
        $this->requiresCurrentField(__METHOD__);
478 11
        $this->expr[$this->currentField] = $this->ensureArray($value);
479
480 11
        return $this;
481
    }
482
483
    /**
484
     * Set the current field for building the expression.
485
     */
486 139
    public function field(string $fieldName) : self
487
    {
488 139
        $fieldName          = $this->getDocumentPersister()->prepareFieldName($fieldName);
489 139
        $this->currentField = $fieldName;
490
491 139
        return $this;
492
    }
493
494
    /**
495
     * Selects a subset of the array to return based on the specified condition.
496
     *
497
     * Returns an array with only those elements that match the condition. The
498
     * returned elements are in the original order.
499
     *
500
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/filter/
501
     *
502
     * @param mixed|self $input
503
     * @param mixed|self $as
504
     * @param mixed|self $cond
505
     */
506 3
    public function filter($input, $as, $cond) : self
507
    {
508 3
        return $this->operator('$filter', ['input' => $input, 'as' => $as, 'cond' => $cond]);
509
    }
510
511
    /**
512
     * Returns the value that results from applying an expression to the first
513
     * document in a group of documents that share the same group by key. Only
514
     * meaningful when documents are in a defined order.
515
     *
516
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/first/
517
     *
518
     * @param mixed|self $expression
519
     */
520 2
    public function first($expression) : self
521
    {
522 2
        return $this->operator('$first', $expression);
523
    }
524
525
    /**
526
     * Returns the largest integer less than or equal to the specified number.
527
     *
528
     * The <number> expression can be any valid expression as long as it
529
     * resolves to a number.
530
     *
531
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/floor/
532
     *
533
     * @param mixed|self $number
534
     */
535 3
    public function floor($number) : self
536
    {
537 3
        return $this->operator('$floor', $number);
538
    }
539
540 339
    public function getExpression() : array
541
    {
542 339
        return $this->expr;
543
    }
544
545
    /**
546
     * Compares two values and returns:
547
     * true when the first value is greater than the second value.
548
     * false when the first value is less than or equivalent to the second
549
     * value.
550
     *
551
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/gt/
552
     *
553
     * @param mixed|self $expression1
554
     * @param mixed|self $expression2
555
     */
556 3
    public function gt($expression1, $expression2) : self
557
    {
558 3
        return $this->operator('$gt', [$expression1, $expression2]);
559
    }
560
561
    /**
562
     * Compares two values and returns:
563
     * true when the first value is greater than or equivalent to the second
564
     * value.
565
     * false when the first value is less than the second value.
566
     *
567
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/gte/
568
     *
569
     * @param mixed|self $expression1
570
     * @param mixed|self $expression2
571
     */
572 6
    public function gte($expression1, $expression2) : self
573
    {
574 6
        return $this->operator('$gte', [$expression1, $expression2]);
575
    }
576
577
    /**
578
     * Returns the hour portion of a date as a number between 0 and 23.
579
     *
580
     * The argument can be any expression as long as it resolves to a date.
581
     *
582
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/hour/
583
     *
584
     * @param mixed|self $expression
585
     */
586 3
    public function hour($expression) : self
587
    {
588 3
        return $this->operator('$hour', $expression);
589
    }
590
591
    /**
592
     * Evaluates an expression and returns the value of the expression if the
593
     * expression evaluates to a non-null value. If the expression evaluates to
594
     * a null value, including instances of undefined values or missing fields,
595
     * returns the value of the replacement expression.
596
     *
597
     * The arguments can be any valid expression.
598
     *
599
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/ifNull/
600
     *
601
     * @param mixed|self $expression
602
     * @param mixed|self $replacementExpression
603
     */
604 3
    public function ifNull($expression, $replacementExpression) : self
605
    {
606 3
        return $this->operator('$ifNull', [$expression, $replacementExpression]);
607
    }
608
609
    /**
610
     * Returns a boolean indicating whether a specified value is in an array.
611
     *
612
     * Unlike the $in query operator, the aggregation $in operator does not
613
     * support matching by regular expressions.
614
     *
615
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/in/
616
     *
617
     * @param mixed|self $expression
618
     * @param mixed|self $arrayExpression
619
     */
620 3
    public function in($expression, $arrayExpression) : self
621
    {
622 3
        return $this->operator('$in', [$expression, $arrayExpression]);
623
    }
624
625
    /**
626
     * Searches an array for an occurrence of a specified value and returns the
627
     * array index (zero-based) of the first occurrence. If the value is not
628
     * found, returns -1.
629
     *
630
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfArray/
631
     *
632
     * @param mixed|self $arrayExpression  Can be any valid expression as long as it resolves to an array.
633
     * @param mixed|self $searchExpression Can be any valid expression.
634
     * @param mixed|self $start            Optional. An integer, or a number that can be represented as integers (such as 2.0), that specifies the starting index position for the search. Can be any valid expression that resolves to a non-negative integral number.
635
     * @param mixed|self $end              An integer, or a number that can be represented as integers (such as 2.0), that specifies the ending index position for the search. Can be any valid expression that resolves to a non-negative integral number.
636
     */
637 12
    public function indexOfArray($arrayExpression, $searchExpression, $start = null, $end = null) : self
638
    {
639 12
        $args = [$arrayExpression, $searchExpression];
640 12
        if ($start !== null) {
641 6
            $args[] = $start;
642
643 6
            if ($end !== null) {
644 3
                $args[] = $end;
645
            }
646
        }
647
648 12
        return $this->operator('$indexOfArray', $args);
649
    }
650
651
    /**
652
     * Searches a string for an occurrence of a substring and returns the UTF-8
653
     * byte index (zero-based) of the first occurrence. If the substring is not
654
     * found, returns -1.
655
     *
656
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfBytes/
657
     *
658
     * @param mixed|self      $stringExpression    Can be any valid expression as long as it resolves to a string.
659
     * @param mixed|self      $substringExpression Can be any valid expression as long as it resolves to a string.
660
     * @param string|int|null $start               An integral number that specifies the starting index position for the search. Can be any valid expression that resolves to a non-negative integral number.
661
     * @param string|int|null $end                 An integral number that specifies the ending index position for the search. Can be any valid expression that resolves to a non-negative integral number.
662
     */
663 12
    public function indexOfBytes($stringExpression, $substringExpression, $start = null, $end = null) : self
664
    {
665 12
        $args = [$stringExpression, $substringExpression];
666 12
        if ($start !== null) {
667 6
            $args[] = $start;
668
669 6
            if ($end !== null) {
670 3
                $args[] = $end;
671
            }
672
        }
673
674 12
        return $this->operator('$indexOfBytes', $args);
675
    }
676
677
    /**
678
     * Searches a string for an occurrence of a substring and returns the UTF-8
679
     * code point index (zero-based) of the first occurrence. If the substring is
680
     * not found, returns -1.
681
     *
682
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfCP/
683
     *
684
     * @param mixed|self      $stringExpression    Can be any valid expression as long as it resolves to a string.
685
     * @param mixed|self      $substringExpression Can be any valid expression as long as it resolves to a string.
686
     * @param string|int|null $start               An integral number that specifies the starting index position for the search. Can be any valid expression that resolves to a non-negative integral number.
687
     * @param string|int|null $end                 An integral number that specifies the ending index position for the search. Can be any valid expression that resolves to a non-negative integral number.
688
     */
689 12
    public function indexOfCP($stringExpression, $substringExpression, $start = null, $end = null) : self
690
    {
691 12
        $args = [$stringExpression, $substringExpression];
692 12
        if ($start !== null) {
693 6
            $args[] = $start;
694
695 6
            if ($end !== null) {
696 3
                $args[] = $end;
697
            }
698
        }
699
700 12
        return $this->operator('$indexOfCP', $args);
701
    }
702
703
    /**
704
     * Determines if the operand is an array. Returns a boolean.
705
     *
706
     * The <expression> can be any valid expression.
707
     *
708
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/isArray/
709
     *
710
     * @param mixed|self $expression
711
     */
712 3
    public function isArray($expression) : self
713
    {
714 3
        return $this->operator('$isArray', $expression);
715
    }
716
717
    /**
718
     * Returns the weekday number in ISO 8601 format, ranging from 1 (for Monday)
719
     * to 7 (for Sunday).
720
     *
721
     * The argument can be any expression as long as it resolves to a date.
722
     *
723
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/isoDayOfWeek/
724
     *
725
     * @param mixed|self $expression
726
     */
727 3
    public function isoDayOfWeek($expression) : self
728
    {
729 3
        return $this->operator('$isoDayOfWeek', $expression);
730
    }
731
732
    /**
733
     * Returns the week number in ISO 8601 format, ranging from 1 to 53.
734
     *
735
     * Week numbers start at 1 with the week (Monday through Sunday) that
736
     * contains the year’s first Thursday.
737
     *
738
     * The argument can be any expression as long as it resolves to a date.
739
     *
740
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/isoWeek/
741
     *
742
     * @param mixed|self $expression
743
     */
744 3
    public function isoWeek($expression) : self
745
    {
746 3
        return $this->operator('$isoWeek', $expression);
747
    }
748
749
    /**
750
     * Returns the year number in ISO 8601 format.
751
     *
752
     * The year starts with the Monday of week 1 (ISO 8601) and ends with the
753
     * Sunday of the last week (ISO 8601).
754
     *
755
     * The argument can be any expression as long as it resolves to a date.
756
     *
757
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/isoWeek/
758
     *
759
     * @param mixed|self $expression
760
     */
761 3
    public function isoWeekYear($expression) : self
762
    {
763 3
        return $this->operator('$isoWeekYear', $expression);
764
    }
765
766
    /**
767
     * Returns the value that results from applying an expression to the last
768
     * document in a group of documents that share the same group by a field.
769
     * Only meaningful when documents are in a defined order.
770
     *
771
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/last/
772
     *
773
     * @param mixed|self $expression
774
     */
775 2
    public function last($expression) : self
776
    {
777 2
        return $this->operator('$last', $expression);
778
    }
779
780
    /**
781
     * Binds variables for use in the specified expression, and returns the
782
     * result of the expression.
783
     *
784
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/let/
785
     *
786
     * @param mixed|self $vars Assignment block for the variables accessible in the in expression. To assign a variable, specify a string for the variable name and assign a valid expression for the value.
787
     * @param mixed|self $in   The expression to evaluate.
788
     */
789 3
    public function let($vars, $in) : self
790
    {
791 3
        return $this->operator('$let', ['vars' => $vars, 'in' => $in]);
792
    }
793
794
    /**
795
     * Returns a value without parsing. Use for values that the aggregation
796
     * pipeline may interpret as an expression.
797
     *
798
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/literal/
799
     *
800
     * @param mixed|self $value
801
     */
802 3
    public function literal($value) : self
803
    {
804 3
        return $this->operator('$literal', $value);
805
    }
806
807
    /**
808
     * Calculates the natural logarithm ln (i.e loge) of a number and returns
809
     * the result as a double.
810
     *
811
     * The <number> expression can be any valid expression as long as it
812
     * resolves to a non-negative number.
813
     *
814
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/log/
815
     *
816
     * @param mixed|self $number
817
     */
818 3
    public function ln($number) : self
819
    {
820 3
        return $this->operator('$ln', $number);
821
    }
822
823
    /**
824
     * Calculates the log of a number in the specified base and returns the
825
     * result as a double.
826
     *
827
     * The <number> expression can be any valid expression as long as it
828
     * resolves to a non-negative number.
829
     * The <base> expression can be any valid expression as long as it resolves
830
     * to a positive number greater than 1.
831
     *
832
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/log/
833
     *
834
     * @param mixed|self $number
835
     * @param mixed|self $base
836
     */
837 3
    public function log($number, $base) : self
838
    {
839 3
        return $this->operator('$log', [$number, $base]);
840
    }
841
842
    /**
843
     * Calculates the log base 10 of a number and returns the result as a double.
844
     *
845
     * The <number> expression can be any valid expression as long as it
846
     * resolves to a non-negative number.
847
     *
848
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/log10/
849
     *
850
     * @param mixed|self $number
851
     */
852 3
    public function log10($number) : self
853
    {
854 3
        return $this->operator('$log10', $number);
855
    }
856
857
    /**
858
     * Compares two values and returns:
859
     * true when the first value is less than the second value.
860
     * false when the first value is greater than or equivalent to the second
861
     * value.
862
     *
863
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/lt/
864
     *
865
     * @param mixed|self $expression1
866
     * @param mixed|self $expression2
867
     */
868 4
    public function lt($expression1, $expression2) : self
869
    {
870 4
        return $this->operator('$lt', [$expression1, $expression2]);
871
    }
872
873
    /**
874
     * Compares two values and returns:
875
     * true when the first value is less than or equivalent to the second value.
876
     * false when the first value is greater than the second value.
877
     *
878
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/lte/
879
     *
880
     * @param mixed|self $expression1
881
     * @param mixed|self $expression2
882
     */
883 6
    public function lte($expression1, $expression2) : self
884
    {
885 6
        return $this->operator('$lte', [$expression1, $expression2]);
886
    }
887
888
    /**
889
     * Applies an expression to each item in an array and returns an array with
890
     * the applied results.
891
     *
892
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/map/
893
     *
894
     * @param mixed|self $input An expression that resolves to an array.
895
     * @param string     $as    The variable name for the items in the input array. The in expression accesses each item in the input array by this variable.
896
     * @param mixed|self $in    The expression to apply to each item in the input array. The expression accesses the item by its variable name.
897
     */
898 3
    public function map($input, $as, $in) : self
899
    {
900 3
        return $this->operator('$map', ['input' => $input, 'as' => $as, 'in' => $in]);
901
    }
902
903
    /**
904
     * Returns the highest value that results from applying an expression to
905
     * each document in a group of documents that share the same group by key.
906
     *
907
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/max/
908
     *
909
     * @param mixed|self $expression
910
     */
911 3
    public function max($expression) : self
912
    {
913 3
        return $this->operator('$max', $expression);
914
    }
915
916
    /**
917
     * Returns the metadata associated with a document in a pipeline operations.
918
     *
919
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/meta/
920
     *
921
     * @param mixed|self $metaDataKeyword
922
     */
923 3
    public function meta($metaDataKeyword) : self
924
    {
925 3
        return $this->operator('$meta', $metaDataKeyword);
926
    }
927
928
    /**
929
     * Returns the millisecond portion of a date as an integer between 0 and 999.
930
     *
931
     * The argument can be any expression as long as it resolves to a date.
932
     *
933
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/millisecond/
934
     *
935
     * @param mixed|self $expression
936
     */
937 3
    public function millisecond($expression) : self
938
    {
939 3
        return $this->operator('$millisecond', $expression);
940
    }
941
942
    /**
943
     * Returns the lowest value that results from applying an expression to each
944
     * document in a group of documents that share the same group by key.
945
     *
946
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/min/
947
     *
948
     * @param mixed|self $expression
949
     */
950 3
    public function min($expression) : self
951
    {
952 3
        return $this->operator('$min', $expression);
953
    }
954
955
    /**
956
     * Returns the minute portion of a date as a number between 0 and 59.
957
     *
958
     * The argument can be any expression as long as it resolves to a date.
959
     *
960
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/minute/
961
     *
962
     * @param mixed|self $expression
963
     */
964 3
    public function minute($expression) : self
965
    {
966 3
        return $this->operator('$minute', $expression);
967
    }
968
969
    /**
970
     * Divides one number by another and returns the remainder. The first
971
     * argument is divided by the second argument.
972
     *
973
     * The arguments can be any valid expression as long as they resolve to numbers.
974
     *
975
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/mod/
976
     *
977
     * @param mixed|self $expression1
978
     * @param mixed|self $expression2
979
     */
980 3
    public function mod($expression1, $expression2) : self
981
    {
982 3
        return $this->operator('$mod', [$expression1, $expression2]);
983
    }
984
985
    /**
986
     * Returns the month of a date as a number between 1 and 12.
987
     *
988
     * The argument can be any expression as long as it resolves to a date.
989
     *
990
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/month/
991
     *
992
     * @param mixed|self $expression
993
     */
994 3
    public function month($expression) : self
995
    {
996 3
        return $this->operator('$month', $expression);
997
    }
998
999
    /**
1000
     * Multiplies numbers together and returns the result.
1001
     *
1002
     * The arguments can be any valid expression as long as they resolve to numbers.
1003
     *
1004
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/multiply/
1005
     *
1006
     * @param mixed|self $expression1
1007
     * @param mixed|self $expression2
1008
     * @param mixed|self ...$expressions Additional expressions
1009
     */
1010 13
    public function multiply($expression1, $expression2, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression1 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 $expression2 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...
1011
    {
1012 13
        return $this->operator('$multiply', func_get_args());
1013
    }
1014
1015
    /**
1016
     * Compares two values and returns:
1017
     * true when the values are not equivalent.
1018
     * false when the values are equivalent.
1019
     *
1020
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/ne/
1021
     *
1022
     * @param mixed|self $expression1
1023
     * @param mixed|self $expression2
1024
     */
1025 4
    public function ne($expression1, $expression2) : self
1026
    {
1027 4
        return $this->operator('$ne', [$expression1, $expression2]);
1028
    }
1029
1030
    /**
1031
     * Evaluates a boolean and returns the opposite boolean value.
1032
     *
1033
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/not/
1034
     *
1035
     * @param mixed|self $expression
1036
     */
1037 3
    public function not($expression) : self
1038
    {
1039 3
        return $this->operator('$not', $expression);
1040
    }
1041
1042
    /**
1043
     * Raises a number to the specified exponent and returns the result.
1044
     *
1045
     * The <number> expression can be any valid expression as long as it
1046
     * resolves to a non-negative number.
1047
     * The <exponent> expression can be any valid expression as long as it
1048
     * resolves to a number.
1049
     *
1050
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/pow/
1051
     *
1052
     * @param mixed|self $number
1053
     * @param mixed|self $exponent
1054
     */
1055 3
    public function pow($number, $exponent) : self
1056
    {
1057 3
        return $this->operator('$pow', [$number, $exponent]);
1058
    }
1059
1060
    /**
1061
     * Returns an array of all values that result from applying an expression to
1062
     * each document in a group of documents that share the same group by key.
1063
     *
1064
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/push/
1065
     *
1066
     * @param mixed|self $expression
1067
     */
1068 2
    public function push($expression) : self
1069
    {
1070 2
        return $this->operator('$push', $expression);
1071
    }
1072
1073
    /**
1074
     * Returns an array whose elements are a generated sequence of numbers.
1075
     *
1076
     * $range generates the sequence from the specified starting number by successively incrementing the starting number by the specified step value up to but not including the end point.
1077
     *
1078
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/range/
1079
     *
1080
     * @param mixed|self $start An integer that specifies the start of the sequence. Can be any valid expression that resolves to an integer.
1081
     * @param mixed|self $end   An integer that specifies the exclusive upper limit of the sequence. Can be any valid expression that resolves to an integer.
1082
     * @param mixed|self $step  Optional. An integer that specifies the increment value. Can be any valid expression that resolves to a non-zero integer. Defaults to 1.
1083
     */
1084 6
    public function range($start, $end, $step = 1) : self
1085
    {
1086 6
        return $this->operator('$range', [$start, $end, $step]);
1087
    }
1088
1089
    /**
1090
     * Applies an expression to each element in an array and combines them into
1091
     * a single value.
1092
     *
1093
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/reduce/
1094
     *
1095
     * @param mixed|self $input        Can be any valid expression that resolves to an array.
1096
     * @param mixed|self $initialValue The initial cumulative value set before in is applied to the first element of the input array.
1097
     * @param mixed|self $in           A valid expression that $reduce applies to each element in the input array in left-to-right order. Wrap the input value with $reverseArray to yield the equivalent of applying the combining expression from right-to-left.
1098
     */
1099 3
    public function reduce($input, $initialValue, $in) : self
1100
    {
1101 3
        return $this->operator('$reduce', ['input' => $input, 'initialValue' => $initialValue, 'in' => $in]);
1102
    }
1103
1104
    /**
1105
     * Accepts an array expression as an argument and returns an array with the
1106
     * elements in reverse order.
1107
     *
1108
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/reverseArray/
1109
     *
1110
     * @param mixed|self $expression
1111
     */
1112 3
    public function reverseArray($expression) : self
1113
    {
1114 3
        return $this->operator('$reverseArray', $expression);
1115
    }
1116
1117
    /**
1118
     * Returns the second portion of a date as a number between 0 and 59, but
1119
     * can be 60 to account for leap seconds.
1120
     *
1121
     * The argument can be any expression as long as it resolves to a date.
1122
     *
1123
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/second/
1124
     *
1125
     * @param mixed|self $expression
1126
     */
1127 3
    public function second($expression) : self
1128
    {
1129 3
        return $this->operator('$second', $expression);
1130
    }
1131
1132
    /**
1133
     * Takes two sets and returns an array containing the elements that only
1134
     * exist in the first set.
1135
     *
1136
     * The arguments can be any valid expression as long as they each resolve to an array.
1137
     *
1138
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/setDifference/
1139
     *
1140
     * @param mixed|self $expression1
1141
     * @param mixed|self $expression2
1142
     */
1143 3
    public function setDifference($expression1, $expression2) : self
1144
    {
1145 3
        return $this->operator('$setDifference', [$expression1, $expression2]);
1146
    }
1147
1148
    /**
1149
     * Compares two or more arrays and returns true if they have the same
1150
     * distinct elements and false otherwise.
1151
     *
1152
     * The arguments can be any valid expression as long as they each resolve to an array.
1153
     *
1154
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/setEquals/
1155
     *
1156
     * @param mixed|self $expression1
1157
     * @param mixed|self $expression2
1158
     * @param mixed|self ...$expressions Additional sets
1159
     */
1160 6
    public function setEquals($expression1, $expression2, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression1 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 $expression2 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...
1161
    {
1162 6
        return $this->operator('$setEquals', func_get_args());
1163
    }
1164
1165
    /**
1166
     * Takes two or more arrays and returns an array that contains the elements
1167
     * that appear in every input array.
1168
     *
1169
     * The arguments can be any valid expression as long as they each resolve to an array.
1170
     *
1171
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/setIntersection/
1172
     *
1173
     * @param mixed|self $expression1
1174
     * @param mixed|self $expression2
1175
     * @param mixed|self ...$expressions Additional sets
1176
     */
1177 6
    public function setIntersection($expression1, $expression2, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression1 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 $expression2 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...
1178
    {
1179 6
        return $this->operator('$setIntersection', func_get_args());
1180
    }
1181
1182
    /**
1183
     * Takes two arrays and returns true when the first array is a subset of the
1184
     * second, including when the first array equals the second array, and false otherwise.
1185
     *
1186
     * The arguments can be any valid expression as long as they each resolve to an array.
1187
     *
1188
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/setIsSubset/
1189
     *
1190
     * @param mixed|self $expression1
1191
     * @param mixed|self $expression2
1192
     */
1193 3
    public function setIsSubset($expression1, $expression2) : self
1194
    {
1195 3
        return $this->operator('$setIsSubset', [$expression1, $expression2]);
1196
    }
1197
1198
    /**
1199
     * Takes two or more arrays and returns an array containing the elements
1200
     * that appear in any input array.
1201
     *
1202
     * The arguments can be any valid expression as long as they each resolve to an array.
1203
     *
1204
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/setUnion/
1205
     *
1206
     * @param mixed|self $expression1
1207
     * @param mixed|self $expression2
1208
     * @param mixed|self ...$expressions Additional sets
1209
     */
1210 6
    public function setUnion($expression1, $expression2, ...$expressions) : self
0 ignored issues
show
Unused Code introduced by
The parameter $expression1 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 $expression2 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...
1211
    {
1212 6
        return $this->operator('$setUnion', func_get_args());
1213
    }
1214
1215
    /**
1216
     * Counts and returns the total the number of items in an array.
1217
     *
1218
     * The argument can be any expression as long as it resolves to an array.
1219
     *
1220
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/size/
1221
     *
1222
     * @param mixed|self $expression
1223
     */
1224 3
    public function size($expression) : self
1225
    {
1226 3
        return $this->operator('$size', $expression);
1227
    }
1228
1229
    /**
1230
     * Returns a subset of an array.
1231
     *
1232
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/slice/
1233
     *
1234
     * @param mixed|self      $array
1235
     * @param mixed|self      $n
1236
     * @param mixed|self|null $position
1237
     */
1238 6
    public function slice($array, $n, $position = null) : self
1239
    {
1240 6
        if ($position === null) {
1241 3
            return $this->operator('$slice', [$array, $n]);
1242
        }
1243
1244 3
        return $this->operator('$slice', [$array, $position, $n]);
1245
    }
1246
1247
    /**
1248
     * Divides a string into an array of substrings based on a delimiter.
1249
     *
1250
     * $split removes the delimiter and returns the resulting substrings as
1251
     * elements of an array. If the delimiter is not found in the string, $split
1252
     * returns the original string as the only element of an array.
1253
     *
1254
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/split/
1255
     *
1256
     * @param mixed|self $string    The string to be split. Can be any valid expression as long as it resolves to a string.
1257
     * @param mixed|self $delimiter The delimiter to use when splitting the string expression. Can be any valid expression as long as it resolves to a string.
1258
     */
1259 3
    public function split($string, $delimiter) : self
1260
    {
1261 3
        return $this->operator('$split', [$string, $delimiter]);
1262
    }
1263
1264
    /**
1265
     * Calculates the square root of a positive number and returns the result as
1266
     * a double.
1267
     *
1268
     * The argument can be any valid expression as long as it resolves to a
1269
     * non-negative number.
1270
     *
1271
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/sqrt/
1272
     *
1273
     * @param mixed|self $expression
1274
     */
1275 3
    public function sqrt($expression) : self
1276
    {
1277 3
        return $this->operator('$sqrt', $expression);
1278
    }
1279
1280
    /**
1281
     * Calculates the population standard deviation of the input values.
1282
     *
1283
     * The arguments can be any expression as long as it resolves to an array.
1284
     *
1285
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/stdDevPop/
1286
     *
1287
     * @param mixed|self $expression1
1288
     * @param mixed|self ...$expressions Additional samples
1289
     */
1290 5
    public function stdDevPop($expression1, ...$expressions) : self
1291
    {
1292 5
        $expression = empty($expressions) ? $expression1 : func_get_args();
1293
1294 5
        return $this->operator('$stdDevPop', $expression);
1295
    }
1296
1297
    /**
1298
     * Calculates the sample standard deviation of the input values.
1299
     *
1300
     * The arguments can be any expression as long as it resolves to an array.
1301
     *
1302
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/stdDevSamp/
1303
     *
1304
     * @param mixed|self $expression1
1305
     * @param mixed|self ...$expressions Additional samples
1306
     */
1307 5
    public function stdDevSamp($expression1, ...$expressions) : self
1308
    {
1309 5
        $expression = empty($expressions) ? $expression1 : func_get_args();
1310
1311 5
        return $this->operator('$stdDevSamp', $expression);
1312
    }
1313
1314
    /**
1315
     * Performs case-insensitive comparison of two strings. Returns
1316
     * 1 if first string is “greater than” the second string.
1317
     * 0 if the two strings are equal.
1318
     * -1 if the first string is “less than” the second string.
1319
     *
1320
     * The arguments can be any valid expression as long as they resolve to strings.
1321
     *
1322
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/strcasecmp/
1323
     *
1324
     * @param mixed|self $expression1
1325
     * @param mixed|self $expression2
1326
     */
1327 3
    public function strcasecmp($expression1, $expression2) : self
1328
    {
1329 3
        return $this->operator('$strcasecmp', [$expression1, $expression2]);
1330
    }
1331
1332
    /**
1333
     * Returns the number of UTF-8 encoded bytes in the specified string.
1334
     *
1335
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/strLenBytes/
1336
     *
1337
     * @param mixed|self $string
1338
     */
1339 3
    public function strLenBytes($string) : self
1340
    {
1341 3
        return $this->operator('$strLenBytes', $string);
1342
    }
1343
1344
    /**
1345
     * Returns the number of UTF-8 code points in the specified string.
1346
     *
1347
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/strLenCP/
1348
     *
1349
     * @param mixed|self $string
1350
     */
1351 3
    public function strLenCP($string) : self
1352
    {
1353 3
        return $this->operator('$strLenCP', $string);
1354
    }
1355
1356
    /**
1357
     * Returns a substring of a string, starting at a specified index position
1358
     * and including the specified number of characters. The index is zero-based.
1359
     *
1360
     * The arguments can be any valid expression as long as long as the first argument resolves to a string, and the second and third arguments resolve to integers.
1361
     *
1362
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/substr/
1363
     *
1364
     * @param mixed|self $string
1365
     * @param mixed|self $start
1366
     * @param mixed|self $length
1367
     */
1368 3
    public function substr($string, $start, $length) : self
1369
    {
1370 3
        return $this->operator('$substr', [$string, $start, $length]);
1371
    }
1372
1373
    /**
1374
     * Returns the substring of a string.
1375
     *
1376
     * The substring starts with the character at the specified UTF-8 byte index
1377
     * (zero-based) in the string and continues for the number of bytes
1378
     * specified.
1379
     *
1380
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/substrBytes/
1381
     *
1382
     * @param mixed|self $string The string from which the substring will be extracted. Can be any valid expression as long as it resolves to a string.
1383
     * @param mixed|self $start  Indicates the starting point of the substring. Can be any valid expression as long as it resolves to a non-negative integer or number that can be represented as an integer.
1384
     * @param mixed|self $count  Can be any valid expression as long as it resolves to a non-negative integer or number that can be represented as an integer.
1385
     */
1386 3
    public function substrBytes($string, $start, $count) : self
1387
    {
1388 3
        return $this->operator('$substrBytes', [$string, $start, $count]);
1389
    }
1390
1391
    /**
1392
     * Returns the substring of a string.
1393
     *
1394
     * The substring starts with the character at the specified UTF-8 code point
1395
     * (CP) index (zero-based) in the string for the number of code points
1396
     * specified.
1397
     *
1398
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/substrBytes/
1399
     *
1400
     * @param mixed|self $string The string from which the substring will be extracted. Can be any valid expression as long as it resolves to a string.
1401
     * @param mixed|self $start  Indicates the starting point of the substring. Can be any valid expression as long as it resolves to a non-negative integer or number that can be represented as an integer.
1402
     * @param mixed|self $count  Can be any valid expression as long as it resolves to a non-negative integer or number that can be represented as an integer.
1403
     */
1404 3
    public function substrCP($string, $start, $count) : self
1405
    {
1406 3
        return $this->operator('$substrCP', [$string, $start, $count]);
1407
    }
1408
1409
    /**
1410
     * Subtracts two numbers to return the difference. The second argument is
1411
     * subtracted from the first argument.
1412
     *
1413
     * The arguments can be any valid expression as long as they resolve to numbers and/or dates.
1414
     *
1415
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/subtract/
1416
     *
1417
     * @param mixed|self $expression1
1418
     * @param mixed|self $expression2
1419
     */
1420 3
    public function subtract($expression1, $expression2) : self
1421
    {
1422 3
        return $this->operator('$subtract', [$expression1, $expression2]);
1423
    }
1424
1425
    /**
1426
     * Calculates and returns the sum of all the numeric values that result from
1427
     * applying a specified expression to each document in a group of documents
1428
     * that share the same group by key. Ignores nun-numeric values.
1429
     *
1430
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/sum/
1431
     *
1432
     * @param mixed|self $expression
1433
     */
1434 9
    public function sum($expression) : self
1435
    {
1436 9
        return $this->operator('$sum', $expression);
1437
    }
1438
1439
    /**
1440
     * Converts a string to lowercase, returning the result.
1441
     *
1442
     * The argument can be any expression as long as it resolves to a string.
1443
     *
1444
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/toLower/
1445
     *
1446
     * @param mixed|self $expression
1447
     */
1448 3
    public function toLower($expression) : self
1449
    {
1450 3
        return $this->operator('$toLower', $expression);
1451
    }
1452
1453
    /**
1454
     * Converts a string to uppercase, returning the result.
1455
     *
1456
     * The argument can be any expression as long as it resolves to a string.
1457
     *
1458
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/toUpper/
1459
     *
1460
     * @param mixed|self $expression
1461
     */
1462 3
    public function toUpper($expression) : self
1463
    {
1464 3
        return $this->operator('$toUpper', $expression);
1465
    }
1466
1467
    /**
1468
     * Truncates a number to its integer.
1469
     *
1470
     * The <number> expression can be any valid expression as long as it
1471
     * resolves to a number.
1472
     *
1473
     * @see https://docs.mongodb.org/manual/reference/operator/aggregation/trunc/
1474
     *
1475
     * @param mixed|self $number
1476
     */
1477 3
    public function trunc($number) : self
1478
    {
1479 3
        return $this->operator('$trunc', $number);
1480
    }
1481
1482
    /**
1483
     * Returns a string that specifies the BSON type of the argument.
1484
     *
1485
     * The argument can be any valid expression.
1486
     *
1487
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/type/
1488
     *
1489
     * @param mixed|self $expression
1490
     */
1491 3
    public function type($expression) : self
1492
    {
1493 3
        return $this->operator('$type', $expression);
1494
    }
1495
1496
    /**
1497
     * Returns the week of the year for a date as a number between 0 and 53.
1498
     *
1499
     * The argument can be any expression as long as it resolves to a date.
1500
     *
1501
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/week/
1502
     *
1503
     * @param mixed|self $expression
1504
     */
1505 3
    public function week($expression) : self
1506
    {
1507 3
        return $this->operator('$week', $expression);
1508
    }
1509
1510
    /**
1511
     * Returns the year portion of a date.
1512
     *
1513
     * The argument can be any expression as long as it resolves to a date.
1514
     *
1515
     * @see http://docs.mongodb.org/manual/reference/operator/aggregation/year/
1516
     *
1517
     * @param mixed|self $expression
1518
     */
1519 4
    public function year($expression) : self
1520
    {
1521 4
        return $this->operator('$year', $expression);
1522
    }
1523
1524
    /**
1525
     * Transposes an array of input arrays so that the first element of the
1526
     * output array would be an array containing, the first element of the first
1527
     * input array, the first element of the second input array, etc.
1528
     *
1529
     * @see https://docs.mongodb.com/manual/reference/operator/aggregation/zip/
1530
     *
1531
     * @param mixed|self      $inputs           An array of expressions that resolve to arrays. The elements of these input arrays combine to form the arrays of the output array.
1532
     * @param bool|null       $useLongestLength A boolean which specifies whether the length of the longest array determines the number of arrays in the output array.
1533
     * @param mixed|self|null $defaults         An array of default element values to use if the input arrays have different lengths. You must specify useLongestLength: true along with this field, or else $zip will return an error.
1534
     */
1535 9
    public function zip($inputs, ?bool $useLongestLength = null, $defaults = null) : self
1536
    {
1537 9
        $args = ['inputs' => $inputs];
1538 9
        if ($useLongestLength !== null) {
1539 6
            $args['useLongestLength'] = $useLongestLength;
1540
        }
1541 9
        if ($defaults !== null) {
1542 3
            $args['defaults'] = $defaults;
1543
        }
1544
1545 9
        return $this->operator('$zip', $args);
1546
    }
1547
1548
1549
    /**
1550
     * @param mixed|self $expression
1551
     *
1552
     * @return mixed
1553
     */
1554 343
    private function ensureArray($expression)
1555
    {
1556 343
        if (is_string($expression) && substr($expression, 0, 1) === '$') {
1557 341
            return '$' . $this->getDocumentPersister()->prepareFieldName(substr($expression, 1));
1558 217
        } elseif (is_array($expression)) {
1559 209
            return array_map([$this, 'ensureArray'], $expression);
1560 87
        } elseif ($expression instanceof self) {
1561 20
            return $expression->getExpression();
1562
        }
1563
1564
        // Convert PHP types to MongoDB types for everything else
1565 85
        return Type::convertPHPToDatabaseValue($expression);
1566
    }
1567
1568 343
    private function getDocumentPersister() : DocumentPersister
1569
    {
1570 343
        return $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name);
1571
    }
1572
1573
    /**
1574
     * Defines an operator and value on the expression.
1575
     *
1576
     * If there is a current field, the operator will be set on it; otherwise,
1577
     * the operator is set at the top level of the query.
1578
     *
1579
     * @param array|self $expression
1580
     */
1581 341
    private function operator(string $operator, $expression) : self
1582
    {
1583 341
        if ($this->currentField) {
1584 137
            $this->expr[$this->currentField][$operator] = $this->ensureArray($expression);
1585
        } else {
1586 212
            $this->expr[$operator] = $this->ensureArray($expression);
1587
        }
1588
1589 341
        return $this;
1590
    }
1591
1592
    /**
1593
     * Ensure that a current field has been set.
1594
     *
1595
     * @throws LogicException If a current field has not been set.
1596
     */
1597 12
    private function requiresCurrentField(?string $method = null) : void
1598
    {
1599 12
        if (! $this->currentField) {
1600 1
            throw new LogicException(($method ?: 'This method') . ' requires you set a current field using field().');
1601
        }
1602 11
    }
1603
1604
    /**
1605
     * @throws BadMethodCallException If there is no current switch operator.
1606
     */
1607 8
    private function requiresSwitchStatement(?string $method = null) : void
1608
    {
1609 8
        $message = ($method ?: 'This method') . ' requires a valid switch statement (call switch() first).';
1610
1611 8
        if ($this->currentField) {
1612
            if (! isset($this->expr[$this->currentField]['$switch'])) {
1613
                throw new BadMethodCallException($message);
1614
            }
1615 8
        } elseif (! isset($this->expr['$switch'])) {
1616 4
            throw new BadMethodCallException($message);
1617
        }
1618 4
    }
1619
1620
    /**
1621
     * Evaluates a series of case expressions. When it finds an expression which
1622
     * evaluates to true, $switch executes a specified expression and breaks out
1623
     * of the control flow.
1624
     *
1625
     * To add statements, use the {@link case()}, {@link then()} and
1626
     * {@link default()} methods.
1627
     */
1628 4
    public function switch() : self
1629
    {
1630 4
        $this->operator('$switch', []);
1631
1632 4
        return $this;
1633
    }
1634
1635
    /**
1636
     * Adds a case statement for the current branch of the $switch operator.
1637
     *
1638
     * Requires {@link case()} to be called first. The argument can be any valid
1639
     * expression.
1640
     *
1641
     * @param mixed|self $expression
1642
     */
1643 6
    public function then($expression) : self
1644
    {
1645 6
        if (! is_array($this->switchBranch)) {
1646 4
            throw new BadMethodCallException(static::class . '::then requires a valid case statement (call case() first).');
1647
        }
1648
1649 4
        $this->switchBranch['then'] = $expression;
1650
1651 4
        if ($this->currentField) {
1652
            $this->expr[$this->currentField]['$switch']['branches'][] = $this->ensureArray($this->switchBranch);
1653
        } else {
1654 4
            $this->expr['$switch']['branches'][] = $this->ensureArray($this->switchBranch);
1655
        }
1656
1657 4
        $this->switchBranch = null;
1658
1659 4
        return $this;
1660
    }
1661
}
1662