Completed
Pull Request — master (#1714)
by
unknown
10:42
created

Expr::bitOr()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Doctrine\ODM\MongoDB\Query;
4
5
use Doctrine\ODM\MongoDB\DocumentManager;
6
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
7
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
8
use Doctrine\ODM\MongoDB\Mapping\MappingException;
9
use GeoJson\Geometry\Geometry;
10
use GeoJson\Geometry\Point;
11
12
/**
13
 * Query expression builder for ODM.
14
 *
15
 * @since       1.0
16
 */
17
class Expr
18
{
19
    /**
20
     * The query criteria array.
21
     *
22
     * @var array
23
     */
24
    private $query = [];
25
26
    /**
27
     * The "new object" array containing either a full document or a number of
28
     * atomic update operators.
29
     *
30
     * @see docs.mongodb.org/manual/reference/method/db.collection.update/#update-parameter
31
     * @var array
32
     */
33
    private $newObj = [];
34
35
    /**
36
     * The current field we are operating on.
37
     *
38
     * @var string
39
     */
40
    private $currentField;
41
42
    /**
43
     * The DocumentManager instance for this query
44
     *
45
     * @var DocumentManager
46
     */
47
    private $dm;
48
49
    /**
50
     * The ClassMetadata instance for the document being queried
51
     *
52
     * @var ClassMetadata
53
     */
54
    private $class;
55
56
    /**
57
     * @param DocumentManager $dm
58
     */
59 391
    public function __construct(DocumentManager $dm)
60
    {
61 391
        $this->dm = $dm;
62 391
    }
63
64
    /**
65
     * Add one or more $and clauses to the current query.
66
     *
67
     * @see Builder::addAnd()
68
     * @see http://docs.mongodb.org/manual/reference/operator/and/
69
     * @param array|Expr $expression
70
     * @param array|Expr ...$expressions
71
     * @return $this
72
     */
73 3 View Code Duplication
    public function addAnd($expression, ...$expressions)
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...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
74
    {
75 3
        if (! isset($this->query['$and'])) {
76 3
            $this->query['$and'] = [];
77
        }
78
79 3
        $this->query['$and'] = array_merge(
80 3
            $this->query['$and'],
81 3
            array_map(
82 3
                function ($expression) {
83 3
                    return $expression instanceof Expr ? $expression->getQuery() : $expression;
84 3
                },
85 3
                func_get_args()
86
            )
87
        );
88
89 3
        return $this;
90
    }
91
92
    /**
93
     * Add one or more $nor clauses to the current query.
94
     *
95
     * @see Builder::addNor()
96
     * @see http://docs.mongodb.org/manual/reference/operator/nor/
97
     * @param array|Expr $expression
98
     * @param array|Expr ...$expressions
99
     * @return $this
100
     */
101 1 View Code Duplication
    public function addNor($expression, ...$expressions)
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...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
102
    {
103 1
        if (! isset($this->query['$nor'])) {
104 1
            $this->query['$nor'] = [];
105
        }
106
107 1
        $this->query['$nor'] = array_merge(
108 1
            $this->query['$nor'],
109
            array_map(function ($expression) { return $expression instanceof Expr ? $expression->getQuery() : $expression; }, func_get_args())
110
        );
111
112 1
        return $this;
113
    }
114
115
    /**
116
     * Add one or more $or clauses to the current query.
117
     *
118
     * @see Builder::addOr()
119
     * @see http://docs.mongodb.org/manual/reference/operator/or/
120
     * @param array|Expr $expression
121
     * @param array|Expr ...$expressions
122
     * @return $this
123
     */
124 5 View Code Duplication
    public function addOr($expression, ...$expressions)
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...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
125
    {
126 5
        if (! isset($this->query['$or'])) {
127 5
            $this->query['$or'] = [];
128
        }
129
130 5
        $this->query['$or'] = array_merge(
131 5
            $this->query['$or'],
132
            array_map(function ($expression) { return $expression instanceof Expr ? $expression->getQuery() : $expression; }, func_get_args())
133
        );
134
135 5
        return $this;
136
    }
137
138
    /**
139
     * Append one or more values to the current array field only if they do not
140
     * already exist in the array.
141
     *
142
     * If the field does not exist, it will be set to an array containing the
143
     * unique value(s) in the argument. If the field is not an array, the query
144
     * will yield an error.
145
     *
146
     * Multiple values may be specified by provided an Expr object and using
147
     * {@link Expr::each()}.
148
     *
149
     * @see Builder::addToSet()
150
     * @see http://docs.mongodb.org/manual/reference/operator/addToSet/
151
     * @see http://docs.mongodb.org/manual/reference/operator/each/
152
     * @param mixed|Expr $valueOrExpression
153
     * @return $this
154
     */
155 5 View Code Duplication
    public function addToSet($valueOrExpression)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
    {
157 5
        if ($valueOrExpression instanceof Expr) {
158 1
            $valueOrExpression = $valueOrExpression->getQuery();
159
        }
160
161 5
        $this->requiresCurrentField();
162 5
        $this->newObj['$addToSet'][$this->currentField] = $valueOrExpression;
163 5
        return $this;
164
    }
165
166
    /**
167
     * Specify $all criteria for the current field.
168
     *
169
     * @see Builder::all()
170
     * @see http://docs.mongodb.org/manual/reference/operator/all/
171
     * @param array $values
172
     * @return $this
173
     */
174 2
    public function all(array $values)
175
    {
176 2
        return $this->operator('$all', (array) $values);
177
    }
178
179
    /**
180
     * Apply a bitwise operation on the current field
181
     *
182
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
183
     * @param string $operator
184
     * @param int $value
185
     * @return $this
186
     */
187 3
    protected function bit($operator, $value)
188
    {
189 3
        $this->requiresCurrentField();
190 3
        $this->newObj['$bit'][$this->currentField][$operator] = $value;
191 3
        return $this;
192
    }
193
194
    /**
195
     * Apply a bitwise and operation on the current field.
196
     *
197
     * @see Builder::bitAnd()
198
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
199
     * @param int $value
200
     * @return $this
201
     */
202 1
    public function bitAnd($value)
203
    {
204 1
        return $this->bit('and', $value);
205
    }
206
207
    /**
208
     * Apply a bitwise or operation on the current field.
209
     *
210
     * @see Builder::bitOr()
211
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
212
     * @param int $value
213
     * @return $this
214
     */
215 1
    public function bitOr($value)
216
    {
217 1
        return $this->bit('or', $value);
218
    }
219
220
    /**
221
     * Matches documents where all of the bit positions given by the query are
222
     * clear.
223
     *
224
     * @see Builder::bitsAllClear()
225
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllClear/
226
     * @param int|array|\MongoDB\BSON\Binary $value
227
     * @return $this
228
     */
229
    public function bitsAllClear($value)
230
    {
231
        $this->requiresCurrentField();
232
        return $this->operator('$bitsAllClear', $value);
233
    }
234
235
    /**
236
     * Matches documents where all of the bit positions given by the query are
237
     * set.
238
     *
239
     * @see Builder::bitsAllSet()
240
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllSet/
241
     * @param int|array|\MongoDB\BSON\Binary $value
242
     * @return $this
243
     */
244
    public function bitsAllSet($value)
245
    {
246
        $this->requiresCurrentField();
247
        return $this->operator('$bitsAllSet', $value);
248
    }
249
250
    /**
251
     * Matches documents where any of the bit positions given by the query are
252
     * clear.
253
     *
254
     * @see Builder::bitsAnyClear()
255
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnyClear/
256
     * @param int|array|\MongoDB\BSON\Binary $value
257
     * @return $this
258
     */
259
    public function bitsAnyClear($value)
260
    {
261
        $this->requiresCurrentField();
262
        return $this->operator('$bitsAnyClear', $value);
263
    }
264
265
    /**
266
     * Matches documents where any of the bit positions given by the query are
267
     * set.
268
     *
269
     * @see Builder::bitsAnySet()
270
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnySet/
271
     * @param int|array|\MongoDB\BSON\Binary $value
272
     * @return $this
273
     */
274
    public function bitsAnySet($value)
275
    {
276
        $this->requiresCurrentField();
277
        return $this->operator('$bitsAnySet', $value);
278
    }
279
280
    /**
281
     * Apply a bitwise xor operation on the current field.
282
     *
283
     * @see Builder::bitXor()
284
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
285
     * @param int $value
286
     * @return $this
287
     */
288 1
    public function bitXor($value)
289
    {
290 1
        return $this->bit('xor', $value);
291
    }
292
293
    /**
294
     * A boolean flag to enable or disable case sensitive search for $text
295
     * criteria.
296
     *
297
     * This method must be called after text().
298
     *
299
     * @see Builder::caseSensitive()
300
     * @see http://docs.mongodb.org/manual/reference/operator/text/
301
     * @param bool $caseSensitive
302
     * @return $this
303
     * @throws \BadMethodCallException if the query does not already have $text criteria
304
     *
305
     * @since 1.3
306
     */
307 3 View Code Duplication
    public function caseSensitive($caseSensitive)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
308
    {
309 3
        if ( ! isset($this->query['$text'])) {
310 1
            throw new \BadMethodCallException('This method requires a $text operator (call text() first)');
311
        }
312
313
        // Remove caseSensitive option to keep support for older database versions
314 2
        if ($caseSensitive) {
315 2
            $this->query['$text']['$caseSensitive'] = true;
316 1
        } elseif (isset($this->query['$text']['$caseSensitive'])) {
317 1
            unset($this->query['$text']['$caseSensitive']);
318
        }
319
320 2
        return $this;
321
    }
322
323
    /**
324
     * Associates a comment to any expression taking a query predicate.
325
     *
326
     * @see Builder::comment()
327
     * @see http://docs.mongodb.org/manual/reference/operator/query/comment/
328
     * @param string $comment
329
     * @return $this
330
     */
331
    public function comment($comment)
332
    {
333
        $this->query['$comment'] = $comment;
334
        return $this;
335
    }
336
337
    /**
338
     * Sets the value of the current field to the current date, either as a date or a timestamp.
339
     *
340
     * @see Builder::currentDate()
341
     * @see http://docs.mongodb.org/manual/reference/operator/update/currentDate/
342
     * @param string $type
343
     * @return $this
344
     * @throws \InvalidArgumentException if an invalid type is given
345
     */
346 3
    public function currentDate($type = 'date')
347
    {
348 3
        if (! in_array($type, ['date', 'timestamp'])) {
349 1
            throw new \InvalidArgumentException('Type for currentDate operator must be date or timestamp.');
350
        }
351
352 2
        $this->requiresCurrentField();
353 2
        $this->newObj['$currentDate'][$this->currentField]['$type'] = $type;
354 2
        return $this;
355
    }
356
357
    /**
358
     * A boolean flag to enable or disable diacritic sensitive search for $text
359
     * criteria.
360
     *
361
     * This method must be called after text().
362
     *
363
     * @see Builder::diacriticSensitive()
364
     * @see http://docs.mongodb.org/manual/reference/operator/text/
365
     * @param bool $diacriticSensitive
366
     * @return $this
367
     * @throws \BadMethodCallException if the query does not already have $text criteria
368
     *
369
     * @since 1.3
370
     */
371 3 View Code Duplication
    public function diacriticSensitive($diacriticSensitive)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
372
    {
373 3
        if ( ! isset($this->query['$text'])) {
374 1
            throw new \BadMethodCallException('This method requires a $text operator (call text() first)');
375
        }
376
377
        // Remove diacriticSensitive option to keep support for older database versions
378 2
        if ($diacriticSensitive) {
379 2
            $this->query['$text']['$diacriticSensitive'] = true;
380 1
        } elseif (isset($this->query['$text']['$diacriticSensitive'])) {
381 1
            unset($this->query['$text']['$diacriticSensitive']);
382
        }
383
384 2
        return $this;
385
    }
386
387
    /**
388
     * Add $each criteria to the expression for a $push operation.
389
     *
390
     * @see Expr::push()
391
     * @see http://docs.mongodb.org/manual/reference/operator/each/
392
     * @param array $values
393
     * @return $this
394
     */
395 4
    public function each(array $values)
396
    {
397 4
        return $this->operator('$each', $values);
398
    }
399
400
    /**
401
     * Specify $elemMatch criteria for the current field.
402
     *
403
     * @see Builder::elemMatch()
404
     * @see http://docs.mongodb.org/manual/reference/operator/elemMatch/
405
     * @param array|Expr $expression
406
     * @return $this
407
     */
408 4
    public function elemMatch($expression)
409
    {
410 4
        return $this->operator('$elemMatch', $expression instanceof Expr ? $expression->getQuery() : $expression);
411
    }
412
413
    /**
414
     * Specify an equality match for the current field.
415
     *
416
     * @see Builder::equals()
417
     * @param mixed $value
418
     * @return $this
419
     */
420 100
    public function equals($value)
421
    {
422 100
        if ($this->currentField) {
423 99
            $this->query[$this->currentField] = $value;
424
        } else {
425 1
            $this->query = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type * is incompatible with the declared type array of property $query.

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...
426
        }
427 100
        return $this;
428
    }
429
430
    /**
431
     * Specify $exists criteria for the current field.
432
     *
433
     * @see Builder::exists()
434
     * @see http://docs.mongodb.org/manual/reference/operator/exists/
435
     * @param boolean $bool
436
     * @return $this
437
     */
438 5
    public function exists($bool)
439
    {
440 5
        return $this->operator('$exists', (boolean) $bool);
441
    }
442
443
    /**
444
     * Set the current field for building the expression.
445
     *
446
     * @see Builder::field()
447
     * @param string $field
448
     * @return $this
449
     */
450 191
    public function field($field)
451
    {
452 191
        $this->currentField = (string) $field;
453 191
        return $this;
454
    }
455
456
    /**
457
     * Add $geoIntersects criteria with a GeoJSON geometry to the expression.
458
     *
459
     * The geometry parameter GeoJSON object or an array corresponding to the
460
     * geometry's JSON representation.
461
     *
462
     * @see Builder::geoIntersects()
463
     * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/
464
     * @param array|Geometry $geometry
465
     * @return $this
466
     */
467 2 View Code Duplication
    public function geoIntersects($geometry)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
468
    {
469 2
        if ($geometry instanceof Geometry) {
0 ignored issues
show
Bug introduced by
The class GeoJson\Geometry\Geometry does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
470 1
            $geometry = $geometry->jsonSerialize();
471
        }
472
473 2
        return $this->operator('$geoIntersects', ['$geometry' => $geometry]);
474
    }
475
476
    /**
477
     * Add $geoWithin criteria with a GeoJSON geometry to the expression.
478
     *
479
     * The geometry parameter GeoJSON object or an array corresponding to the
480
     * geometry's JSON representation.
481
     *
482
     * @see Builder::geoWithin()
483
     * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/
484
     * @param array|Geometry $geometry
485
     * @return $this
486
     */
487 2 View Code Duplication
    public function geoWithin($geometry)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
488
    {
489 2
        if ($geometry instanceof Geometry) {
0 ignored issues
show
Bug introduced by
The class GeoJson\Geometry\Geometry does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
490 1
            $geometry = $geometry->jsonSerialize();
491
        }
492
493 2
        return $this->operator('$geoWithin', ['$geometry' => $geometry]);
494
    }
495
496
    /**
497
     * Add $geoWithin criteria with a $box shape to the expression.
498
     *
499
     * A rectangular polygon will be constructed from a pair of coordinates
500
     * corresponding to the bottom left and top right corners.
501
     *
502
     * Note: the $box operator only supports legacy coordinate pairs and 2d
503
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
504
     *
505
     * @see Builder::geoWithinBox()
506
     * @see http://docs.mongodb.org/manual/reference/operator/box/
507
     * @param float $x1
508
     * @param float $y1
509
     * @param float $x2
510
     * @param float $y2
511
     * @return $this
512
     */
513 1
    public function geoWithinBox($x1, $y1, $x2, $y2)
514
    {
515 1
        $shape = ['$box' => [[$x1, $y1], [$x2, $y2]]];
516
517 1
        return $this->operator('$geoWithin', $shape);
518
    }
519
520
    /**
521
     * Add $geoWithin criteria with a $center shape to the expression.
522
     *
523
     * Note: the $center operator only supports legacy coordinate pairs and 2d
524
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
525
     *
526
     * @see Builider::geoWithinCenter()
527
     * @see http://docs.mongodb.org/manual/reference/operator/center/
528
     * @param float $x
529
     * @param float $y
530
     * @param float $radius
531
     * @return $this
532
     */
533 1
    public function geoWithinCenter($x, $y, $radius)
534
    {
535 1
        $shape = ['$center' => [[$x, $y], $radius]];
536
537 1
        return $this->operator('$geoWithin', $shape);
538
    }
539
540
    /**
541
     * Add $geoWithin criteria with a $centerSphere shape to the expression.
542
     *
543
     * Note: the $centerSphere operator supports both 2d and 2dsphere indexes.
544
     *
545
     * @see Builder::geoWithinCenterSphere()
546
     * @see http://docs.mongodb.org/manual/reference/operator/centerSphere/
547
     * @param float $x
548
     * @param float $y
549
     * @param float $radius
550
     * @return $this
551
     */
552 1
    public function geoWithinCenterSphere($x, $y, $radius)
553
    {
554 1
        $shape = ['$centerSphere' => [[$x, $y], $radius]];
555
556 1
        return $this->operator('$geoWithin', $shape);
557
    }
558
559
    /**
560
     * Add $geoWithin criteria with a $polygon shape to the expression.
561
     *
562
     * Point coordinates are in x, y order (easting, northing for projected
563
     * coordinates, longitude, latitude for geographic coordinates).
564
     *
565
     * The last point coordinate is implicitly connected with the first.
566
     *
567
     * Note: the $polygon operator only supports legacy coordinate pairs and 2d
568
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
569
     *
570
     * @see Builder::geoWithinPolygon()
571
     * @see http://docs.mongodb.org/manual/reference/operator/polygon/
572
     * @param array $point1 First point of the polygon
573
     * @param array $point2 Second point of the polygon
574
     * @param array $point3 Third point of the polygon
575
     * @param array ...$points Additional points of the polygon
576
     * @return $this
577
     * @throws \InvalidArgumentException if less than three points are given
578
     */
579 1
    public function geoWithinPolygon($point1, $point2, $point3, ...$points)
0 ignored issues
show
Unused Code introduced by
The parameter $point1 is not used and could be removed.

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

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

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

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

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

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

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

Loading history...
580
    {
581 1
        $shape = ['$polygon' => func_get_args()];
582
583 1
        return $this->operator('$geoWithin', $shape);
584
    }
585
586
    /**
587
     * Return the current field.
588
     *
589
     * @return string
590
     */
591 2
    public function getCurrentField()
592
    {
593 2
        return $this->currentField;
594
    }
595
596
    /**
597
     * Gets prepared newObj part of expression.
598
     *
599
     * @return array
600
     */
601 174
    public function getNewObj()
602
    {
603 174
        return $this->dm->getUnitOfWork()
604 174
            ->getDocumentPersister($this->class->name)
605 174
            ->prepareQueryOrNewObj($this->newObj, true);
606
    }
607
608
    /**
609
     * Gets prepared query part of expression.
610
     *
611
     * @return array
612
     */
613 250
    public function getQuery()
614
    {
615 250
        return $this->dm->getUnitOfWork()
616 250
            ->getDocumentPersister($this->class->name)
617 250
            ->prepareQueryOrNewObj($this->query);
618
    }
619
620
    /**
621
     * Specify $gt criteria for the current field.
622
     *
623
     * @see Builder::gt()
624
     * @see http://docs.mongodb.org/manual/reference/operator/gt/
625
     * @param mixed $value
626
     * @return $this
627
     */
628 2
    public function gt($value)
629
    {
630 2
        return $this->operator('$gt', $value);
631
    }
632
633
    /**
634
     * Specify $gte criteria for the current field.
635
     *
636
     * @see Builder::gte()
637
     * @see http://docs.mongodb.org/manual/reference/operator/gte/
638
     * @param mixed $value
639
     * @return $this
640
     */
641 2
    public function gte($value)
642
    {
643 2
        return $this->operator('$gte', $value);
644
    }
645
646
    /**
647
     * Specify $in criteria for the current field.
648
     *
649
     * @see Builder::in()
650
     * @see http://docs.mongodb.org/manual/reference/operator/in/
651
     * @param array $values
652
     * @return $this
653
     */
654 31
    public function in(array $values)
655
    {
656 31
        return $this->operator('$in', array_values($values));
657
    }
658
659
    /**
660
     * Increment the current field.
661
     *
662
     * If the field does not exist, it will be set to this value.
663
     *
664
     * @see Builder::inc()
665
     * @see http://docs.mongodb.org/manual/reference/operator/inc/
666
     * @param float|integer $value
667
     * @return $this
668
     */
669 5
    public function inc($value)
670
    {
671 5
        $this->requiresCurrentField();
672 5
        $this->newObj['$inc'][$this->currentField] = $value;
673 5
        return $this;
674
    }
675
676
    /**
677
     * Checks that the current field includes a reference to the supplied document.
678
     *
679
     * @param object $document
680
     * @return Expr
681
     */
682 6 View Code Duplication
    public function includesReferenceTo($document)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
683
    {
684 6
        $this->requiresCurrentField();
685 6
        $mapping = $this->getReferenceMapping();
686 4
        $reference = $this->dm->createReference($document, $mapping);
687 4
        $storeAs = array_key_exists('storeAs', $mapping) ? $mapping['storeAs'] : null;
688 4
        $keys = [];
0 ignored issues
show
Unused Code introduced by
$keys is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
689
690
        switch ($storeAs) {
691 4
            case ClassMetadataInfo::REFERENCE_STORE_AS_ID:
692 2
                $this->query[$mapping['name']] = $reference;
693 2
                return $this;
694
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
695
696 3
            case ClassMetadataInfo::REFERENCE_STORE_AS_REF:
697
                $keys = ['id' => true];
698
                break;
699
700 3
            case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF:
701 1
            case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB:
702 3
                $keys = ['$ref' => true, '$id' => true, '$db' => true];
703
704 3
                if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) {
705 2
                    unset($keys['$db']);
706
                }
707
708 3
                if (isset($mapping['targetDocument'])) {
709 1
                    unset($keys['$ref'], $keys['$db']);
710
                }
711 3
                break;
712
713
            default:
714
                throw new \InvalidArgumentException("Reference type {$storeAs} is invalid.");
715
        }
716
717 3
        foreach ($keys as $key => $value) {
718 3
            $this->query[$mapping['name']]['$elemMatch'][$key] = $reference[$key];
719
        }
720
721 3
        return $this;
722
    }
723
724
    /**
725
     * Set the $language option for $text criteria.
726
     *
727
     * This method must be called after text().
728
     *
729
     * @see Builder::language()
730
     * @see http://docs.mongodb.org/manual/reference/operator/text/
731
     * @param string $language
732
     * @return $this
733
     * @throws \BadMethodCallException if the query does not already have $text criteria
734
     */
735 2
    public function language($language)
736
    {
737 2
        if ( ! isset($this->query['$text'])) {
738 1
            throw new \BadMethodCallException('This method requires a $text operator (call text() first)');
739
        }
740
741 1
        $this->query['$text']['$language'] = (string) $language;
742
743 1
        return $this;
744
    }
745
746
    /**
747
     * Specify $lt criteria for the current field.
748
     *
749
     * @see Builder::lte()
750
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
751
     * @param mixed $value
752
     * @return $this
753
     */
754 4
    public function lt($value)
755
    {
756 4
        return $this->operator('$lt', $value);
757
    }
758
759
    /**
760
     * Specify $lte criteria for the current field.
761
     *
762
     * @see Builder::lte()
763
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
764
     * @param mixed $value
765
     * @return $this
766
     */
767 2
    public function lte($value)
768
    {
769 2
        return $this->operator('$lte', $value);
770
    }
771
772
    /**
773
     * Updates the value of the field to a specified value if the specified value is greater than the current value of the field.
774
     *
775
     * @see Builder::max()
776
     * @see http://docs.mongodb.org/manual/reference/operator/update/max/
777
     * @param mixed $value
778
     * @return $this
779
     */
780
    public function max($value)
781
    {
782
        $this->requiresCurrentField();
783
        $this->newObj['$max'][$this->currentField] = $value;
784
        return $this;
785
    }
786
787
    /**
788
     * Updates the value of the field to a specified value if the specified value is less than the current value of the field.
789
     *
790
     * @see Builder::min()
791
     * @see http://docs.mongodb.org/manual/reference/operator/update/min/
792
     * @param mixed $value
793
     * @return $this
794
     */
795
    public function min($value)
796
    {
797
        $this->requiresCurrentField();
798
        $this->newObj['$min'][$this->currentField] = $value;
799
        return $this;
800
    }
801
802
    /**
803
     * Specify $mod criteria for the current field.
804
     *
805
     * @see Builder::mod()
806
     * @see http://docs.mongodb.org/manual/reference/operator/mod/
807
     * @param float|integer $divisor
808
     * @param float|integer $remainder
809
     * @return $this
810
     */
811
    public function mod($divisor, $remainder = 0)
812
    {
813
        return $this->operator('$mod', [$divisor, $remainder]);
814
    }
815
816
    /**
817
     * Multiply the current field.
818
     *
819
     * If the field does not exist, it will be set to 0.
820
     *
821
     * @see Builder::mul()
822
     * @see http://docs.mongodb.org/manual/reference/operator/mul/
823
     * @param float|integer $value
824
     * @return $this
825
     */
826
    public function mul($value)
827
    {
828
        $this->requiresCurrentField();
829
        $this->newObj['$mul'][$this->currentField] = $value;
830
        return $this;
831
    }
832
833
    /**
834
     * Add $near criteria to the expression.
835
     *
836
     * A GeoJSON point may be provided as the first and only argument for
837
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
838
     * an array corresponding to the point's JSON representation.
839
     *
840
     * @see Builder::near()
841
     * @see http://docs.mongodb.org/manual/reference/operator/near/
842
     * @param float|array|Point $x
843
     * @param float $y
844
     * @return $this
845
     */
846 3 View Code Duplication
    public function near($x, $y = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
847
    {
848 3
        if ($x instanceof Point) {
0 ignored issues
show
Bug introduced by
The class GeoJson\Geometry\Point does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
849 1
            $x = $x->jsonSerialize();
850
        }
851
852 3
        if (is_array($x)) {
853 2
            return $this->operator('$near', ['$geometry' => $x]);
854
        }
855
856 1
        return $this->operator('$near', [$x, $y]);
857
    }
858
859
    /**
860
     * Add $nearSphere criteria to the expression.
861
     *
862
     * A GeoJSON point may be provided as the first and only argument for
863
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
864
     * an array corresponding to the point's JSON representation.
865
     *
866
     * @see Builder::nearSphere()
867
     * @see http://docs.mongodb.org/manual/reference/operator/nearSphere/
868
     * @param float|array|Point $x
869
     * @param float $y
870
     * @return $this
871
     */
872 3 View Code Duplication
    public function nearSphere($x, $y = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
873
    {
874 3
        if ($x instanceof Point) {
0 ignored issues
show
Bug introduced by
The class GeoJson\Geometry\Point does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
875 1
            $x = $x->jsonSerialize();
876
        }
877
878 3
        if (is_array($x)) {
879 2
            return $this->operator('$nearSphere', ['$geometry' => $x]);
880
        }
881
882 1
        return $this->operator('$nearSphere', [$x, $y]);
883
    }
884
885
    /**
886
     * Negates an expression for the current field.
887
     *
888
     * @see Builder::not()
889
     * @see http://docs.mongodb.org/manual/reference/operator/not/
890
     * @param array|Expr $expression
891
     * @return $this
892
     */
893 2
    public function not($expression)
894
    {
895 2
        return $this->operator('$not', $expression instanceof Expr ? $expression->getQuery() : $expression);
896
    }
897
898
    /**
899
     * Specify $ne criteria for the current field.
900
     *
901
     * @see Builder::notEqual()
902
     * @see http://docs.mongodb.org/manual/reference/operator/ne/
903
     * @param mixed $value
904
     * @return $this
905
     */
906 6
    public function notEqual($value)
907
    {
908 6
        return $this->operator('$ne', $value);
909
    }
910
911
    /**
912
     * Specify $nin criteria for the current field.
913
     *
914
     * @see Builder::notIn()
915
     * @see http://docs.mongodb.org/manual/reference/operator/nin/
916
     * @param array $values
917
     * @return $this
918
     */
919 6
    public function notIn(array $values)
920
    {
921 6
        return $this->operator('$nin', array_values($values));
922
    }
923
924
    /**
925
     * Defines an operator and value on the expression.
926
     *
927
     * If there is a current field, the operator will be set on it; otherwise,
928
     * the operator is set at the top level of the query.
929
     *
930
     * @param string $operator
931
     * @param mixed $value
932
     * @return $this
933
     */
934 81
    public function operator($operator, $value)
935
    {
936 81
        $this->wrapEqualityCriteria();
937
938 81
        if ($this->currentField) {
939 56
            $this->query[$this->currentField][$operator] = $value;
940
        } else {
941 27
            $this->query[$operator] = $value;
942
        }
943 81
        return $this;
944
    }
945
946
    /**
947
     * Remove the first element from the current array field.
948
     *
949
     * @see Builder::popFirst()
950
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
951
     * @return $this
952
     */
953 1
    public function popFirst()
954
    {
955 1
        $this->requiresCurrentField();
956 1
        $this->newObj['$pop'][$this->currentField] = 1;
957 1
        return $this;
958
    }
959
960
    /**
961
     * Remove the last element from the current array field.
962
     *
963
     * @see Builder::popLast()
964
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
965
     * @return $this
966
     */
967
    public function popLast()
968
    {
969
        $this->requiresCurrentField();
970
        $this->newObj['$pop'][$this->currentField] = -1;
971
        return $this;
972
    }
973
974
    /**
975
     * Add $position criteria to the expression for a $push operation.
976
     *
977
     * This is useful in conjunction with {@link Expr::each()} for a
978
     * {@link Expr::push()} operation.
979
     *
980
     * @see http://docs.mongodb.org/manual/reference/operator/update/position/
981
     * @param integer $position
982
     * @return $this
983
     */
984 1
    public function position($position)
985
    {
986 1
        return $this->operator('$position', $position);
987
    }
988
989
    /**
990
     * Remove all elements matching the given value or expression from the
991
     * current array field.
992
     *
993
     * @see Builder::pull()
994
     * @see http://docs.mongodb.org/manual/reference/operator/pull/
995
     * @param mixed|Expr $valueOrExpression
996
     * @return $this
997
     */
998 2 View Code Duplication
    public function pull($valueOrExpression)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
999
    {
1000 2
        if ($valueOrExpression instanceof Expr) {
1001 1
            $valueOrExpression = $valueOrExpression->getQuery();
1002
        }
1003
1004 2
        $this->requiresCurrentField();
1005 2
        $this->newObj['$pull'][$this->currentField] = $valueOrExpression;
1006 2
        return $this;
1007
    }
1008
1009
    /**
1010
     * Remove all elements matching any of the given values from the current
1011
     * array field.
1012
     *
1013
     * @see Builder::pullAll()
1014
     * @see http://docs.mongodb.org/manual/reference/operator/pullAll/
1015
     * @param array $values
1016
     * @return $this
1017
     */
1018
    public function pullAll(array $values)
1019
    {
1020
        $this->requiresCurrentField();
1021
        $this->newObj['$pullAll'][$this->currentField] = $values;
1022
        return $this;
1023
    }
1024
1025
    /**
1026
     * Append one or more values to the current array field.
1027
     *
1028
     * If the field does not exist, it will be set to an array containing the
1029
     * value(s) in the argument. If the field is not an array, the query
1030
     * will yield an error.
1031
     *
1032
     * Multiple values may be specified by providing an Expr object and using
1033
     * {@link Expr::each()}. {@link Expr::slice()} and {@link Expr::sort()} may
1034
     * also be used to limit and order array elements, respectively.
1035
     *
1036
     * @see Builder::push()
1037
     * @see http://docs.mongodb.org/manual/reference/operator/push/
1038
     * @see http://docs.mongodb.org/manual/reference/operator/each/
1039
     * @see http://docs.mongodb.org/manual/reference/operator/slice/
1040
     * @see http://docs.mongodb.org/manual/reference/operator/sort/
1041
     * @param mixed|Expr $valueOrExpression
1042
     * @return $this
1043
     */
1044 8 View Code Duplication
    public function push($valueOrExpression)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1045
    {
1046 8
        if ($valueOrExpression instanceof Expr) {
1047 3
            $valueOrExpression = array_merge(
1048 3
                ['$each' => []],
1049 3
                $valueOrExpression->getQuery()
1050
            );
1051
        }
1052
1053 8
        $this->requiresCurrentField();
1054 8
        $this->newObj['$push'][$this->currentField] = $valueOrExpression;
1055 8
        return $this;
1056
    }
1057
1058
    /**
1059
     * Specify $gte and $lt criteria for the current field.
1060
     *
1061
     * This method is shorthand for specifying $gte criteria on the lower bound
1062
     * and $lt criteria on the upper bound. The upper bound is not inclusive.
1063
     *
1064
     * @see Builder::range()
1065
     * @param mixed $start
1066
     * @param mixed $end
1067
     * @return $this
1068
     */
1069 2
    public function range($start, $end)
1070
    {
1071 2
        return $this->operator('$gte', $start)->operator('$lt', $end);
1072
    }
1073
1074
    /**
1075
     * Checks that the value of the current field is a reference to the supplied document.
1076
     *
1077
     * @param object $document
1078
     * @return Expr
1079
     */
1080 13 View Code Duplication
    public function references($document)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1081
    {
1082 13
        $this->requiresCurrentField();
1083 13
        $mapping = $this->getReferenceMapping();
1084 11
        $reference = $this->dm->createReference($document, $mapping);
1085 11
        $storeAs = array_key_exists('storeAs', $mapping) ? $mapping['storeAs'] : null;
1086 11
        $keys = [];
0 ignored issues
show
Unused Code introduced by
$keys is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1087
1088
        switch ($storeAs) {
1089 11
            case ClassMetadataInfo::REFERENCE_STORE_AS_ID:
1090 4
                $this->query[$mapping['name']] = $reference;
1091 4
                return $this;
1092
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1093
1094 8
            case ClassMetadataInfo::REFERENCE_STORE_AS_REF:
1095
                $keys = ['id' => true];
1096
                break;
1097
1098 8
            case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF:
1099 3
            case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB:
1100 8
                $keys = ['$ref' => true, '$id' => true, '$db' => true];
1101
1102 8
                if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) {
1103 5
                    unset($keys['$db']);
1104
                }
1105
1106 8
                if (isset($mapping['targetDocument'])) {
1107 4
                    unset($keys['$ref'], $keys['$db']);
1108
                }
1109 8
                break;
1110
1111
            default:
1112
                throw new \InvalidArgumentException("Reference type {$storeAs} is invalid.");
1113
        }
1114
1115 8
        foreach ($keys as $key => $value) {
1116 8
            $this->query[$mapping['name'] . '.' . $key] = $reference[$key];
1117
        }
1118
1119 8
        return $this;
1120
    }
1121
1122
    /**
1123
     * Rename the current field.
1124
     *
1125
     * @see Builder::rename()
1126
     * @see http://docs.mongodb.org/manual/reference/operator/rename/
1127
     * @param string $name
1128
     * @return $this
1129
     */
1130
    public function rename($name)
1131
    {
1132
        $this->requiresCurrentField();
1133
        $this->newObj['$rename'][$this->currentField] = $name;
1134
        return $this;
1135
    }
1136
1137
    /**
1138
     * Set the current field to a value.
1139
     *
1140
     * This is only relevant for insert, update, or findAndUpdate queries. For
1141
     * update and findAndUpdate queries, the $atomic parameter will determine
1142
     * whether or not a $set operator is used.
1143
     *
1144
     * @see Builder::set()
1145
     * @see http://docs.mongodb.org/manual/reference/operator/set/
1146
     * @param mixed $value
1147
     * @param boolean $atomic
1148
     * @return $this
1149
     */
1150 19
    public function set($value, $atomic = true)
1151
    {
1152 19
        $this->requiresCurrentField();
1153
1154 19
        if ($atomic) {
1155 16
            $this->newObj['$set'][$this->currentField] = $value;
1156 16
            return $this;
1157
        }
1158
1159 3
        if (strpos($this->currentField, '.') === false) {
1160 2
            $this->newObj[$this->currentField] = $value;
1161 2
            return $this;
1162
        }
1163
1164 2
        $keys = explode('.', $this->currentField);
1165 2
        $current = &$this->newObj;
1166 2
        foreach ($keys as $key) {
1167 2
            $current = &$current[$key];
1168
        }
1169 2
        $current = $value;
1170
1171 2
        return $this;
1172
    }
1173
1174
    /**
1175
     * Sets ClassMetadata for document being queried.
1176
     *
1177
     * @param ClassMetadata $class
1178
     */
1179 389
    public function setClassMetadata(ClassMetadata $class)
1180
    {
1181 389
        $this->class = $class;
1182 389
    }
1183
1184
    /**
1185
     * Set the "new object".
1186
     *
1187
     * @see Builder::setNewObj()
1188
     * @param array $newObj
1189
     * @return $this
1190
     */
1191
    public function setNewObj(array $newObj)
1192
    {
1193
        $this->newObj = $newObj;
1194
        return $this;
1195
    }
1196
1197
    /**
1198
     * Set the current field to the value if the document is inserted in an
1199
     * upsert operation.
1200
     *
1201
     * If an update operation with upsert: true results in an insert of a
1202
     * document, then $setOnInsert assigns the specified values to the fields in
1203
     * the document. If the update operation does not result in an insert,
1204
     * $setOnInsert does nothing.
1205
     *
1206
     * @see Builder::setOnInsert()
1207
     * @see https://docs.mongodb.org/manual/reference/operator/update/setOnInsert/
1208
     * @param mixed $value
1209
     * @return $this
1210
     */
1211 1
    public function setOnInsert($value)
1212
    {
1213 1
        $this->requiresCurrentField();
1214 1
        $this->newObj['$setOnInsert'][$this->currentField] = $value;
1215
1216 1
        return $this;
1217
    }
1218
1219
    /**
1220
     * Set the query criteria.
1221
     *
1222
     * @see Builder::setQueryArray()
1223
     * @param array $query
1224
     * @return $this
1225
     */
1226 18
    public function setQuery(array $query)
1227
    {
1228 18
        $this->query = $query;
1229 18
        return $this;
1230
    }
1231
1232
    /**
1233
     * Specify $size criteria for the current field.
1234
     *
1235
     * @see Builder::size()
1236
     * @see http://docs.mongodb.org/manual/reference/operator/size/
1237
     * @param integer $size
1238
     * @return $this
1239
     */
1240
    public function size($size)
1241
    {
1242
        return $this->operator('$size', (integer) $size);
1243
    }
1244
1245
    /**
1246
     * Add $slice criteria to the expression for a $push operation.
1247
     *
1248
     * This is useful in conjunction with {@link Expr::each()} for a
1249
     * {@link Expr::push()} operation. {@link Builder::selectSlice()} should be
1250
     * used for specifying $slice for a query projection.
1251
     *
1252
     * @see http://docs.mongodb.org/manual/reference/operator/slice/
1253
     * @param integer $slice
1254
     * @return $this
1255
     */
1256 2
    public function slice($slice)
1257
    {
1258 2
        return $this->operator('$slice', $slice);
1259
    }
1260
1261
    /**
1262
     * Add $sort criteria to the expression for a $push operation.
1263
     *
1264
     * If sorting by multiple fields, the first argument should be an array of
1265
     * field name (key) and order (value) pairs.
1266
     *
1267
     * This is useful in conjunction with {@link Expr::each()} for a
1268
     * {@link Expr::push()} operation. {@link Builder::sort()} should be used to
1269
     * sort the results of a query.
1270
     *
1271
     * @see http://docs.mongodb.org/manual/reference/operator/sort/
1272
     * @param array|string $fieldName Field name or array of field/order pairs
1273
     * @param int|string $order       Field order (if one field is specified)
1274
     * @return $this
1275
     */
1276 2
    public function sort($fieldName, $order = null)
1277
    {
1278 2
        $fields = is_array($fieldName) ? $fieldName : [$fieldName => $order];
1279
1280 2
        return $this->operator('$sort', array_map([$this, 'normalizeSortOrder'], $fields));
1281
    }
1282
1283
    /**
1284
     * Specify $text criteria for the current query.
1285
     *
1286
     * The $language option may be set with {@link Expr::language()}.
1287
     *
1288
     * @see Builder::text()
1289
     * @see http://docs.mongodb.org/master/reference/operator/query/text/
1290
     * @param string $search
1291
     * @return $this
1292
     */
1293 6
    public function text($search)
1294
    {
1295 6
        $this->query['$text'] = ['$search' => (string) $search];
1296 6
        return $this;
1297
    }
1298
1299
    /**
1300
     * Specify $type criteria for the current field.
1301
     *
1302
     * @todo Remove support for string $type argument in 2.0
1303
     * @see Builder::type()
1304
     * @see http://docs.mongodb.org/manual/reference/operator/type/
1305
     * @param integer $type
1306
     * @return $this
1307
     */
1308 1
    public function type($type)
1309
    {
1310 1
        if (is_string($type)) {
1311
            $map = [
1312 1
                'double' => 1,
1313
                'string' => 2,
1314
                'object' => 3,
1315
                'array' => 4,
1316
                'binary' => 5,
1317
                'undefined' => 6,
1318
                'objectid' => 7,
1319
                'boolean' => 8,
1320
                'date' => 9,
1321
                'null' => 10,
1322
                'regex' => 11,
1323
                'jscode' => 13,
1324
                'symbol' => 14,
1325
                'jscodewithscope' => 15,
1326
                'integer32' => 16,
1327
                'timestamp' => 17,
1328
                'integer64' => 18,
1329
                'maxkey' => 127,
1330
                'minkey' => 255,
1331
            ];
1332
1333 1
            $type = $map[$type] ?? $type;
1334
        }
1335
1336 1
        return $this->operator('$type', $type);
1337
    }
1338
1339
    /**
1340
     * Unset the current field.
1341
     *
1342
     * The field will be removed from the document (not set to null).
1343
     *
1344
     * @see Builder::unsetField()
1345
     * @see http://docs.mongodb.org/manual/reference/operator/unset/
1346
     * @return $this
1347
     */
1348 3
    public function unsetField()
1349
    {
1350 3
        $this->requiresCurrentField();
1351 3
        $this->newObj['$unset'][$this->currentField] = 1;
1352 3
        return $this;
1353
    }
1354
1355
    /**
1356
     * Specify a JavaScript expression to use for matching documents.
1357
     *
1358
     * @see Builder::where()
1359
     * @see http://docs.mongodb.org/manual/reference/operator/where/
1360
     * @param string|\MongoDB\BSON\Javascript $javascript
1361
     * @return $this
1362
     */
1363 3
    public function where($javascript)
1364
    {
1365 3
        $this->query['$where'] = $javascript;
1366 3
        return $this;
1367
    }
1368
1369
    /**
1370
     * Gets reference mapping for current field from current class or its descendants.
1371
     *
1372
     * @return array
1373
     * @throws MappingException
1374
     */
1375 19
    private function getReferenceMapping()
1376
    {
1377 19
        $mapping = null;
1378
        try {
1379 19
            $mapping = $this->class->getFieldMapping($this->currentField);
1380 6
        } catch (MappingException $e) {
1381 6
            if (empty($this->class->discriminatorMap)) {
1382
                throw $e;
1383
            }
1384 6
            $foundIn = null;
1385 6
            foreach ($this->class->discriminatorMap as $child) {
1386 6
                $childClass = $this->dm->getClassMetadata($child);
1387 6
                if ($childClass->hasAssociation($this->currentField)) {
1388 4
                    if ($mapping !== null && $mapping !== $childClass->getFieldMapping($this->currentField)) {
1389 2
                        throw MappingException::referenceFieldConflict($this->currentField, $foundIn->name, $childClass->name);
1390
                    }
1391 4
                    $mapping = $childClass->getFieldMapping($this->currentField);
1392 6
                    $foundIn = $childClass;
1393
                }
1394
            }
1395 4
            if ($mapping === null) {
1396 2
                throw MappingException::mappingNotFoundInClassNorDescendants($this->class->name, $this->currentField);
1397
            }
1398
        }
1399 15
        return $mapping;
1400
    }
1401
1402
    /**
1403
     * @param int|string $order
1404
     *
1405
     * @return int
1406
     */
1407 2
    private function normalizeSortOrder($order): int
1408
    {
1409 2
        if (is_string($order)) {
1410
            $order = strtolower($order) === 'asc' ? 1 : -1;
1411
        }
1412
1413 2
        return (int) $order;
1414
    }
1415
1416
    /**
1417
     * Ensure that a current field has been set.
1418
     *
1419
     * @throws \LogicException if a current field has not been set
1420
     */
1421 67
    private function requiresCurrentField()
1422
    {
1423 67
        if ( ! $this->currentField) {
1424
            throw new \LogicException('This method requires you set a current field using field().');
1425
        }
1426 67
    }
1427
1428
    /**
1429
     * Wraps equality criteria with an operator.
1430
     *
1431
     * If equality criteria was previously specified for a field, it cannot be
1432
     * merged with other operators without first being wrapped in an operator of
1433
     * its own. Ideally, we would wrap it with $eq, but that is only available
1434
     * in MongoDB 2.8. Using a single-element $in is backwards compatible.
1435
     *
1436
     * @see Expr::operator()
1437
     */
1438 81
    private function wrapEqualityCriteria()
1439
    {
1440
        /* If the current field has no criteria yet, do nothing. This ensures
1441
         * that we do not inadvertently inject {"$in": null} into the query.
1442
         */
1443 81
        if ($this->currentField && ! isset($this->query[$this->currentField]) && ! array_key_exists($this->currentField, $this->query)) {
1444 55
            return;
1445
        }
1446
1447 31
        if ($this->currentField) {
1448 5
            $query = &$this->query[$this->currentField];
1449
        } else {
1450 27
            $query = &$this->query;
1451
        }
1452
1453
        /* If the query is an empty array, we'll assume that the user has not
1454
         * specified criteria. Otherwise, check if the array includes a query
1455
         * operator (checking the first key is sufficient). If neither of these
1456
         * conditions are met, we'll wrap the query value with $in.
1457
         */
1458 31
        if (is_array($query) && (empty($query) || strpos(key($query), '$') === 0)) {
1459 31
            return;
1460
        }
1461
1462 2
        $query = ['$in' => [$query]];
1463 2
    }
1464
}
1465