Completed
Pull Request — master (#1897)
by
unknown
15:49
created

Expr::requiresSwitchStatement()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.3906

Importance

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

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1669
1670 4
        return $this;
1671
    }
1672
}
1673