Issues (353)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/Doctrine/ODM/MongoDB/Aggregation/Expr.php (25 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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