Completed
Pull Request — master (#1709)
by Andreas
16:45 queued 14:38
created

Builder::reduce()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 11

Duplication

Lines 17
Ratio 100 %

Code Coverage

Tests 6
CRAP Score 3.1406

Importance

Changes 0
Metric Value
dl 17
loc 17
ccs 6
cts 8
cp 0.75
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
nop 1
crap 3.1406
1
<?php
2
3
namespace Doctrine\ODM\MongoDB\Query;
4
5
use Doctrine\ODM\MongoDB\DocumentManager;
6
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
7
use GeoJson\Geometry\Geometry;
8
use GeoJson\Geometry\Point;
9
use MongoDB\Collection;
10
use MongoDB\Driver\ReadPreference;
11
12
/**
13
 * Query builder for ODM.
14
 *
15
 * @since       1.0
16
 */
17
class Builder
18
{
19
    /**
20
     * The DocumentManager instance for this query
21
     *
22
     * @var DocumentManager
23
     */
24
    private $dm;
25
26
    /**
27
     * The ClassMetadata instance.
28
     *
29
     * @var \Doctrine\ODM\MongoDB\Mapping\ClassMetadata
30
     */
31
    private $class;
32
33
    /**
34
     * The current field we are operating on.
35
     *
36
     * @todo Change this to private once ODM requires doctrine/mongodb 1.1+
37
     * @var string
38
     */
39
    protected $currentField;
40
41
    /**
42
     * Whether or not to hydrate the data to documents.
43
     *
44
     * @var boolean
45
     */
46
    private $hydrate = true;
47
48
    /**
49
     * Whether or not to refresh the data for documents that are already in the identity map.
50
     *
51
     * @var boolean
52
     */
53
    private $refresh = false;
54
55
    /**
56
     * Array of primer Closure instances.
57
     *
58
     * @var array
59
     */
60
    private $primers = array();
61
62
    /**
63
     * Whether or not to register documents in UnitOfWork.
64
     *
65
     * @var bool
66
     */
67
    private $readOnly;
68
69
    /**
70
     * The Collection instance.
71
     *
72
     * @var Collection
73
     */
74
    private $collection;
75
76
    /**
77
     * Array containing the query data.
78
     *
79
     * @var array
80
     */
81
    private $query = ['type' => Query::TYPE_FIND];
82
83
    /**
84
     * The Expr instance used for building this query.
85
     *
86
     * This object includes the query criteria and the "new object" used for
87
     * insert and update queries.
88
     *
89
     * @var Expr $expr
90
     */
91
    private $expr;
92
93
    /**
94
     * Construct a Builder
95
     *
96
     * @param DocumentManager $dm
97
     * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none
98
     */
99 291
    public function __construct(DocumentManager $dm, $documentName = null)
100
    {
101 291
        $this->dm = $dm;
102 291
        $this->expr = new Expr($dm);
103 291
        if ($documentName !== null) {
104 283
            $this->setDocumentName($documentName);
105
        }
106 290
    }
107
108 1
    public function __clone()
109
    {
110 1
        $this->expr = clone $this->expr;
111 1
    }
112
113
    /**
114
     * Add one or more $and clauses to the current query.
115
     *
116
     * You can create a new expression using the {@link Builder::expr()} method.
117
     *
118
     * @see Expr::addAnd()
119
     * @see http://docs.mongodb.org/manual/reference/operator/and/
120
     * @param array|Expr $expression
121
     * @return $this
122
     */
123 4
    public function addAnd($expression /* , $expression2, ... */)
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...
124
    {
125 4
        $this->expr->addAnd(...func_get_args());
126 4
        return $this;
127
    }
128
129
    /**
130
     * Append multiple values to the current array field only if they do not
131
     * already exist in the array.
132
     *
133
     * If the field does not exist, it will be set to an array containing the
134
     * unique values in the argument. If the field is not an array, the query
135
     * will yield an error.
136
     *
137
     * @deprecated 1.1 Use {@link Builder::addToSet()} with {@link Expr::each()}; Will be removed in 2.0
138
     * @see Expr::addManyToSet()
139
     * @see http://docs.mongodb.org/manual/reference/operator/addToSet/
140
     * @see http://docs.mongodb.org/manual/reference/operator/each/
141
     * @param array $values
142
     * @return $this
143
     */
144 1
    public function addManyToSet(array $values)
145
    {
146 1
        $this->expr->addManyToSet($values);
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Query\Expr::addManyToSet() has been deprecated with message: 1.1 Use {@link Expr::addToSet()} with {@link Expr::each()}; Will be removed in 2.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
147 1
        return $this;
148
    }
149
150
    /**
151
     * Add one or more $nor clauses to the current query.
152
     *
153
     * You can create a new expression using the {@link Builder::expr()} method.
154
     *
155
     * @see Expr::addNor()
156
     * @see http://docs.mongodb.org/manual/reference/operator/nor/
157
     * @param array|Expr $expression
158
     * @return $this
159
     */
160 3
    public function addNor($expression /* , $expression2, ... */)
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...
161
    {
162 3
        $this->expr->addNor(...func_get_args());
163 3
        return $this;
164
    }
165
166
    /**
167
     * Add one or more $or clauses to the current query.
168
     *
169
     * You can create a new expression using the {@link Builder::expr()} method.
170
     *
171
     * @see Expr::addOr()
172
     * @see http://docs.mongodb.org/manual/reference/operator/or/
173
     * @param array|Expr $expression
174
     * @return $this
175
     */
176 6
    public function addOr($expression /* , $expression2, ... */)
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...
177
    {
178 6
        $this->expr->addOr(...func_get_args());
179 6
        return $this;
180
    }
181
182
    /**
183
     * Append one or more values to the current array field only if they do not
184
     * already exist in the array.
185
     *
186
     * If the field does not exist, it will be set to an array containing the
187
     * unique value(s) in the argument. If the field is not an array, the query
188
     * will yield an error.
189
     *
190
     * Multiple values may be specified by provided an Expr object and using
191
     * {@link Expr::each()}.
192
     *
193
     * @see Expr::addToSet()
194
     * @see http://docs.mongodb.org/manual/reference/operator/addToSet/
195
     * @see http://docs.mongodb.org/manual/reference/operator/each/
196
     * @param mixed|Expr $valueOrExpression
197
     * @return $this
198
     */
199 5
    public function addToSet($valueOrExpression)
200
    {
201 5
        $this->expr->addToSet($valueOrExpression);
202 5
        return $this;
203
    }
204
205
    /**
206
     * Specify $all criteria for the current field.
207
     *
208
     * @see Expr::all()
209
     * @see http://docs.mongodb.org/manual/reference/operator/all/
210
     * @param array $values
211
     * @return $this
212
     */
213 3
    public function all(array $values)
214
    {
215 3
        $this->expr->all($values);
216 3
        return $this;
217
    }
218
219
    /**
220
     * Apply a bitwise and operation on the current field.
221
     *
222
     * @see Expr::bitAnd()
223
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
224
     * @param int $value
225
     * @return $this
226
     */
227 1
    public function bitAnd($value)
228
    {
229 1
        $this->expr->bitAnd($value);
230 1
        return $this;
231
    }
232
233
    /**
234
     * Apply a bitwise or operation on the current field.
235
     *
236
     * @see Expr::bitOr()
237
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
238
     * @param int $value
239
     * @return $this
240
     */
241 1
    public function bitOr($value)
242
    {
243 1
        $this->expr->bitOr($value);
244 1
        return $this;
245
    }
246
247
    /**
248
     * Matches documents where all of the bit positions given by the query are
249
     * clear.
250
     *
251
     * @see Expr::bitsAllClear()
252
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllClear/
253
     * @param int|array|\MongoBinData $value
254
     * @return $this
255
     */
256 1
    public function bitsAllClear($value)
257
    {
258 1
        $this->expr->bitsAllClear($value);
259 1
        return $this;
260
    }
261
262
    /**
263
     * Matches documents where all of the bit positions given by the query are
264
     * set.
265
     *
266
     * @see Expr::bitsAllSet()
267
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllSet/
268
     * @param int|array|\MongoBinData $value
269
     * @return $this
270
     */
271 1
    public function bitsAllSet($value)
272
    {
273 1
        $this->expr->bitsAllSet($value);
274 1
        return $this;
275
    }
276
277
    /**
278
     * Matches documents where any of the bit positions given by the query are
279
     * clear.
280
     *
281
     * @see Expr::bitsAnyClear()
282
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnyClear/
283
     * @param int|array|\MongoBinData $value
284
     * @return $this
285
     */
286 1
    public function bitsAnyClear($value)
287
    {
288 1
        $this->expr->bitsAnyClear($value);
289 1
        return $this;
290
    }
291
292
    /**
293
     * Matches documents where any of the bit positions given by the query are
294
     * set.
295
     *
296
     * @see Expr::bitsAnySet()
297
     * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnySet/
298
     * @param int|array|\MongoBinData $value
299
     * @return $this
300
     */
301 1
    public function bitsAnySet($value)
302
    {
303 1
        $this->expr->bitsAnySet($value);
304 1
        return $this;
305
    }
306
307
    /**
308
     * Apply a bitwise xor operation on the current field.
309
     *
310
     * @see Expr::bitXor()
311
     * @see http://docs.mongodb.org/manual/reference/operator/update/bit/
312
     * @param int $value
313
     * @return $this
314
     */
315 1
    public function bitXor($value)
316
    {
317 1
        $this->expr->bitXor($value);
318 1
        return $this;
319
    }
320
321
    /**
322
     * A boolean flag to enable or disable case sensitive search for $text
323
     * criteria.
324
     *
325
     * This method must be called after text().
326
     *
327
     * @see Expr::caseSensitive()
328
     * @see http://docs.mongodb.org/manual/reference/operator/text/
329
     * @param bool $caseSensitive
330
     * @return $this
331
     * @throws \BadMethodCallException if the query does not already have $text criteria
332
     *
333
     * @since 1.3
334
     */
335 1
    public function caseSensitive($caseSensitive)
336
    {
337 1
        $this->expr->caseSensitive($caseSensitive);
338 1
        return $this;
339
    }
340
341
    /**
342
     * Associates a comment to any expression taking a query predicate.
343
     *
344
     * @see Expr::comment()
345
     * @see http://docs.mongodb.org/manual/reference/operator/query/comment/
346
     * @param string $comment
347
     * @return $this
348
     */
349 1
    public function comment($comment)
350
    {
351 1
        $this->expr->comment($comment);
352 1
        return $this;
353
    }
354
355
    /**
356
     * Change the query type to count.
357
     *
358
     * @return $this
359
     */
360
    public function count()
361
    {
362
        $this->query['type'] = Query::TYPE_COUNT;
363
        return $this;
364
    }
365
366
    /**
367
     * Sets the value of the current field to the current date, either as a date or a timestamp.
368
     *
369
     * @see Expr::currentDate()
370
     * @see http://docs.mongodb.org/manual/reference/operator/currentDate/
371
     * @param string $type
372
     * @return $this
373
     */
374 3
    public function currentDate($type = 'date')
375
    {
376 3
        $this->expr->currentDate($type);
377 2
        return $this;
378
    }
379
380
    /**
381
     * Return an array of information about the Builder state for debugging.
382
     *
383
     * The $name parameter may be used to return a specific key from the
384
     * internal $query array property. If omitted, the entire array will be
385
     * returned.
386
     *
387
     * @param string $name
388
     * @return mixed
389
     */
390 28
    public function debug($name = null)
391
    {
392 28
        return $name !== null ? $this->query[$name] : $this->query;
393
    }
394
395
    /**
396
     * A boolean flag to enable or disable diacritic sensitive search for $text
397
     * criteria.
398
     *
399
     * This method must be called after text().
400
     *
401
     * @see Builder::diacriticSensitive()
402
     * @see http://docs.mongodb.org/manual/reference/operator/text/
403
     * @param bool $diacriticSensitive
404
     * @return $this
405
     * @throws \BadMethodCallException if the query does not already have $text criteria
406
     *
407
     * @since 1.3
408
     */
409 1
    public function diacriticSensitive($diacriticSensitive)
410
    {
411 1
        $this->expr->diacriticSensitive($diacriticSensitive);
412 1
        return $this;
413
    }
414
415
    /**
416
     * Change the query type to a distinct command.
417
     *
418
     * @see http://docs.mongodb.org/manual/reference/command/distinct/
419
     * @param string $field
420
     * @return $this
421
     */
422 2
    public function distinct($field)
423
    {
424 2
        $this->query['type'] = Query::TYPE_DISTINCT;
425 2
        $this->query['distinct'] = $field;
426 2
        return $this;
427
    }
428
429
    /**
430
     * Set whether the query should return its result as an EagerCursor.
431
     *
432
     * @param boolean $bool
433
     * @return $this
434
     */
435 5
    public function eagerCursor($bool = true)
436
    {
437 5
        if ( ! $bool && ! empty($this->primers)) {
438 1
            throw new \BadMethodCallException("Can't set eagerCursor to false when using reference primers");
439
        }
440
441 4
        $this->query['eagerCursor'] = (boolean) $bool;
442 4
        return $this;
443
    }
444
445
    /**
446
     * Specify $elemMatch criteria for the current field.
447
     *
448
     * You can create a new expression using the {@link Builder::expr()} method.
449
     *
450
     * @see Expr::elemMatch()
451
     * @see http://docs.mongodb.org/manual/reference/operator/elemMatch/
452
     * @param array|Expr $expression
453
     * @return $this
454
     */
455 6
    public function elemMatch($expression)
456
    {
457 6
        $this->expr->elemMatch($expression);
458 6
        return $this;
459
    }
460
461
    /**
462
     * Specify an equality match for the current field.
463
     *
464
     * @see Expr::equals()
465
     * @param mixed $value
466
     * @return $this
467
     */
468 75
    public function equals($value)
469
    {
470 75
        $this->expr->equals($value);
471 75
        return $this;
472
    }
473
474
    /**
475
     * Set one or more fields to be excluded from the query projection.
476
     *
477
     * If fields have been selected for inclusion, only the "_id" field may be
478
     * excluded.
479
     *
480
     * @param array|string $fieldName,...
0 ignored issues
show
Documentation introduced by
There is no parameter named $fieldName,.... Did you maybe mean $fieldName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
481
     * @return $this
482
     */
483 6 View Code Duplication
    public function exclude($fieldName = 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...
484
    {
485 6
        if ( ! isset($this->query['select'])) {
486 6
            $this->query['select'] = [];
487
        }
488
489 6
        $fieldNames = is_array($fieldName) ? $fieldName : func_get_args();
490
491 6
        foreach ($fieldNames as $fieldName) {
492 4
            $this->query['select'][$fieldName] = 0;
493
        }
494
495 6
        return $this;
496
    }
497
498
    /**
499
     * Specify $exists criteria for the current field.
500
     *
501
     * @see Expr::exists()
502
     * @see http://docs.mongodb.org/manual/reference/operator/exists/
503
     * @param boolean $bool
504
     * @return $this
505
     */
506 5
    public function exists($bool)
507
    {
508 5
        $this->expr->exists((boolean) $bool);
509 5
        return $this;
510
    }
511
512
    /**
513
     * Create a new Expr instance that can be used as an expression with the Builder
514
     *
515
     * @return Expr $expr
516
     */
517 26
    public function expr()
518
    {
519 26
        $expr = new Expr($this->dm);
520 26
        $expr->setClassMetadata($this->class);
521
522 26
        return $expr;
523
    }
524
525
    /**
526
     * Set the current field to operate on.
527
     *
528
     * @param string $field
529
     * @return $this
530
     */
531 144
    public function field($field)
532
    {
533 144
        $this->currentField = $field;
534 144
        $this->expr->field((string) $field);
535
536 144
        return $this;
537
    }
538
539
    /**
540
     * Set the "finalize" option for a mapReduce or group command.
541
     *
542
     * @param string|\MongoCode $finalize
543
     * @return $this
544
     * @throws \BadMethodCallException if the query is not a mapReduce or group command
545
     */
546 2 View Code Duplication
    public function finalize($finalize)
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...
547
    {
548 2
        switch ($this->query['type']) {
549
            case Query::TYPE_MAP_REDUCE:
550 1
                $this->query['mapReduce']['options']['finalize'] = $finalize;
551 1
                break;
552
553
            case Query::TYPE_GROUP:
554
                $this->query['group']['options']['finalize'] = $finalize;
555
                break;
556
557
            default:
558 1
                throw new \BadMethodCallException('mapReduce(), map() or group() must be called before finalize()');
559
        }
560
561 1
        return $this;
562
    }
563
564
    /**
565
     * Change the query type to find and optionally set and change the class being queried.
566
     *
567
     * @param string $documentName
568
     * @return $this
569
     */
570 12
    public function find($documentName = null)
571
    {
572 12
        $this->setDocumentName($documentName);
573 12
        $this->query['type'] = Query::TYPE_FIND;
574
575 12
        return $this;
576
    }
577
578
    /**
579
     * @param string $documentName
580
     * @return $this
581
     */
582 1
    public function findAndRemove($documentName = null)
583
    {
584 1
        $this->setDocumentName($documentName);
585 1
        $this->query['type'] = Query::TYPE_FIND_AND_REMOVE;
586
587 1
        return $this;
588
    }
589
590
    /**
591
     * @param string $documentName
592
     * @return $this
593
     */
594 13
    public function findAndUpdate($documentName = null)
595
    {
596 13
        $this->setDocumentName($documentName);
597 13
        $this->query['type'] = Query::TYPE_FIND_AND_UPDATE;
598
599 13
        return $this;
600
    }
601
602
    /**
603
     * Add $geoIntersects criteria with a GeoJSON geometry to the query.
604
     *
605
     * The geometry parameter GeoJSON object or an array corresponding to the
606
     * geometry's JSON representation.
607
     *
608
     * @see Expr::geoIntersects()
609
     * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/
610
     * @param array|Geometry $geometry
611
     * @return $this
612
     */
613 1
    public function geoIntersects($geometry)
614
    {
615 1
        $this->expr->geoIntersects($geometry);
616 1
        return $this;
617
    }
618
619
    /**
620
     * Add $geoWithin criteria with a GeoJSON geometry to the query.
621
     *
622
     * The geometry parameter GeoJSON object or an array corresponding to the
623
     * geometry's JSON representation.
624
     *
625
     * @see Expr::geoWithin()
626
     * @see http://docs.mongodb.org/manual/reference/operator/geoWithin/
627
     * @param array|Geometry $geometry
628
     * @return $this
629
     */
630 1
    public function geoWithin($geometry)
631
    {
632 1
        $this->expr->geoWithin($geometry);
633 1
        return $this;
634
    }
635
636
    /**
637
     * Add $geoWithin criteria with a $box shape to the query.
638
     *
639
     * A rectangular polygon will be constructed from a pair of coordinates
640
     * corresponding to the bottom left and top right corners.
641
     *
642
     * Note: the $box operator only supports legacy coordinate pairs and 2d
643
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
644
     *
645
     * @see Expr::geoWithinBox()
646
     * @see http://docs.mongodb.org/manual/reference/operator/box/
647
     * @param float $x1
648
     * @param float $y1
649
     * @param float $x2
650
     * @param float $y2
651
     * @return $this
652
     */
653 1
    public function geoWithinBox($x1, $y1, $x2, $y2)
654
    {
655 1
        $this->expr->geoWithinBox($x1, $y1, $x2, $y2);
656 1
        return $this;
657
    }
658
659
    /**
660
     * Add $geoWithin criteria with a $center shape to the query.
661
     *
662
     * Note: the $center operator only supports legacy coordinate pairs and 2d
663
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
664
     *
665
     * @see Expr::geoWithinCenter()
666
     * @see http://docs.mongodb.org/manual/reference/operator/center/
667
     * @param float $x
668
     * @param float $y
669
     * @param float $radius
670
     * @return $this
671
     */
672 1
    public function geoWithinCenter($x, $y, $radius)
673
    {
674 1
        $this->expr->geoWithinCenter($x, $y, $radius);
675 1
        return $this;
676
    }
677
678
    /**
679
     * Add $geoWithin criteria with a $centerSphere shape to the query.
680
     *
681
     * Note: the $centerSphere operator supports both 2d and 2dsphere indexes.
682
     *
683
     * @see Expr::geoWithinCenterSphere()
684
     * @see http://docs.mongodb.org/manual/reference/operator/centerSphere/
685
     * @param float $x
686
     * @param float $y
687
     * @param float $radius
688
     * @return $this
689
     */
690 1
    public function geoWithinCenterSphere($x, $y, $radius)
691
    {
692 1
        $this->expr->geoWithinCenterSphere($x, $y, $radius);
693 1
        return $this;
694
    }
695
696
    /**
697
     * Add $geoWithin criteria with a $polygon shape to the query.
698
     *
699
     * Point coordinates are in x, y order (easting, northing for projected
700
     * coordinates, longitude, latitude for geographic coordinates).
701
     *
702
     * The last point coordinate is implicitly connected with the first.
703
     *
704
     * Note: the $polygon operator only supports legacy coordinate pairs and 2d
705
     * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes.
706
     *
707
     * @see Expr::geoWithinPolygon()
708
     * @see http://docs.mongodb.org/manual/reference/operator/polygon/
709
     * @param array $point,... Three or more point coordinate tuples
0 ignored issues
show
Bug introduced by
There is no parameter named $point,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
710
     * @return $this
711
     */
712 1
    public function geoWithinPolygon(/* array($x1, $y1), ... */)
713
    {
714 1
        $this->expr->geoWithinPolygon(...func_get_args());
715 1
        return $this;
716
    }
717
718
    /**
719
     * Return the expression's "new object".
720
     *
721
     * @see Expr::getNewObj()
722
     * @return array
723
     */
724 13
    public function getNewObj()
725
    {
726 13
        return $this->expr->getNewObj();
727
    }
728
729
    /**
730
     * Gets the Query executable.
731
     *
732
     * @param array $options
733
     * @return Query $query
734
     */
735 150
    public function getQuery(array $options = array())
736
    {
737 150
        if ($this->query['type'] === Query::TYPE_MAP_REDUCE) {
738
            $this->hydrate = false;
739
        }
740
741 150
        $documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name);
742
743 150
        $query = $this->query;
744
745 150
        $query['query'] = $this->expr->getQuery();
746 150
        $query['query'] = $documentPersister->addDiscriminatorToPreparedQuery($query['query']);
747 150
        $query['query'] = $documentPersister->addFilterToPreparedQuery($query['query']);
748
749 150
        $query['newObj'] = $this->expr->getNewObj();
750
751 150
        if (isset($query['distinct'])) {
752 2
            $query['distinct'] = $documentPersister->prepareFieldName($query['distinct']);
0 ignored issues
show
Documentation introduced by
$query['distinct'] is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
753
        }
754
755 150
        if ($this->class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION && ! empty($query['upsert']) &&
756 150
            (empty($query['query'][$this->class->discriminatorField]) || is_array($query['query'][$this->class->discriminatorField]))) {
757 1
            throw new \InvalidArgumentException('Upsert query that is to be performed on discriminated document does not have single ' .
758 1
                'discriminator. Either not use base class or set \'' . $this->class->discriminatorField . '\' field manually.');
759
        }
760
761 149
        if ( ! empty($query['select'])) {
762 14
            $query['select'] = $documentPersister->prepareProjection($query['select']);
763 14
            if ($this->hydrate && $this->class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION
764 14
                && ! isset($query['select'][$this->class->discriminatorField])) {
765
                $includeMode = 0 < count(array_filter($query['select'], function($mode) { return $mode == 1; }));
766 2
                if ($includeMode && ! isset($query['select'][$this->class->discriminatorField])) {
767 1
                    $query['select'][$this->class->discriminatorField] = 1;
768
                }
769
            }
770
        }
771
772 149
        if (isset($query['sort'])) {
773 23
            $query['sort'] = $documentPersister->prepareSort($query['sort']);
774
        }
775
776 149
        if ($this->class->slaveOkay) {
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...etadataInfo::$slaveOkay has been deprecated with message: in version 1.2 and will be removed in 2.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
777
            $query['slaveOkay'] = $this->class->slaveOkay;
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...etadataInfo::$slaveOkay has been deprecated with message: in version 1.2 and will be removed in 2.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
778
        }
779
780 149
        if ($this->class->readPreference && ! array_key_exists('readPreference', $query)) {
781 1
            $query['readPreference'] = new ReadPreference($this->class->readPreference, $this->class->readPreferenceTags);
782
        }
783
784 149
        return new Query(
785 149
            $this->dm,
786 149
            $this->class,
787 149
            $this->collection,
788 149
            $query,
789 149
            $options,
790 149
            $this->hydrate,
791 149
            $this->refresh,
792 149
            $this->primers,
793 149
            $this->readOnly
794
        );
795
    }
796
797
    /**
798
     * Return the expression's query criteria.
799
     *
800
     * @see Expr::getQuery()
801
     * @return array
802
     */
803 33
    public function getQueryArray()
804
    {
805 33
        return $this->expr->getQuery();
806
    }
807
808
    /**
809
     * Get the type of this query.
810
     *
811
     * @return integer $type
812
     */
813 2
    public function getType()
814
    {
815 2
        return $this->query['type'];
816
    }
817
818
    /**
819
     * Specify $gt criteria for the current field.
820
     *
821
     * @see Expr::gt()
822
     * @see http://docs.mongodb.org/manual/reference/operator/gt/
823
     * @param mixed $value
824
     * @return $this
825
     */
826 2
    public function gt($value)
827
    {
828 2
        $this->expr->gt($value);
829 2
        return $this;
830
    }
831
832
    /**
833
     * Specify $gte criteria for the current field.
834
     *
835
     * @see Expr::gte()
836
     * @see http://docs.mongodb.org/manual/reference/operator/gte/
837
     * @param mixed $value
838
     * @return $this
839
     */
840 2
    public function gte($value)
841
    {
842 2
        $this->expr->gte($value);
843 2
        return $this;
844
    }
845
846
    /**
847
     * Set the index hint for the query.
848
     *
849
     * @param array|string $index
850
     * @return $this
851
     */
852
    public function hint($index)
853
    {
854
        $this->query['hint'] = $index;
855
        return $this;
856
    }
857
858
    /**
859
     * @param bool $bool
860
     * @return $this
861
     */
862 17
    public function hydrate($bool = true)
863
    {
864 17
        $this->hydrate = $bool;
865 17
        return $this;
866
    }
867
868
    /**
869
     * Set the immortal cursor flag.
870
     *
871
     * @param boolean $bool
872
     * @return $this
873
     */
874
    public function immortal($bool = true)
875
    {
876
        $this->query['immortal'] = (boolean) $bool;
877
        return $this;
878
    }
879
880
    /**
881
     * Specify $in criteria for the current field.
882
     *
883
     * @see Expr::in()
884
     * @see http://docs.mongodb.org/manual/reference/operator/in/
885
     * @param array $values
886
     * @return $this
887
     */
888 24
    public function in(array $values)
889
    {
890 24
        $this->expr->in($values);
891 24
        return $this;
892
    }
893
894
    /**
895
     * Increment the current field.
896
     *
897
     * If the field does not exist, it will be set to this value.
898
     *
899
     * @see Expr::inc()
900
     * @see http://docs.mongodb.org/manual/reference/operator/inc/
901
     * @param float|integer $value
902
     * @return $this
903
     */
904 6
    public function inc($value)
905
    {
906 6
        $this->expr->inc($value);
907 6
        return $this;
908
    }
909
910
    /**
911
     * @param object $document
912
     * @return $this
913
     */
914 6
    public function includesReferenceTo($document)
915
    {
916 6
        $this->expr->includesReferenceTo($document);
917 4
        return $this;
918
    }
919
920
    /**
921
     * @param string $documentName
922
     * @return $this
923
     */
924 1
    public function insert($documentName = null)
925
    {
926 1
        $this->setDocumentName($documentName);
927 1
        $this->query['type'] = Query::TYPE_INSERT;
928
929 1
        return $this;
930
    }
931
932
    /**
933
     * Set the $language option for $text criteria.
934
     *
935
     * This method must be called after text().
936
     *
937
     * @see Expr::language()
938
     * @see http://docs.mongodb.org/manual/reference/operator/text/
939
     * @param string $language
940
     * @return $this
941
     */
942 1
    public function language($language)
943
    {
944 1
        $this->expr->language($language);
945 1
        return $this;
946
    }
947
948
    /**
949
     * Set the limit for the query.
950
     *
951
     * This is only relevant for find queries and geoNear and mapReduce
952
     * commands.
953
     *
954
     * @see Query::prepareCursor()
955
     * @param integer $limit
956
     * @return $this
957
     */
958 2
    public function limit($limit)
959
    {
960 2
        $this->query['limit'] = (integer) $limit;
961 2
        return $this;
962
    }
963
964
    /**
965
     * Specify $lt criteria for the current field.
966
     *
967
     * @see Expr::lte()
968
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
969
     * @param mixed $value
970
     * @return $this
971
     */
972
    public function lt($value)
973
    {
974
        $this->expr->lt($value);
975
        return $this;
976
    }
977
978
    /**
979
     * Specify $lte criteria for the current field.
980
     *
981
     * @see Expr::lte()
982
     * @see http://docs.mongodb.org/manual/reference/operator/lte/
983
     * @param mixed $value
984
     * @return $this
985
     */
986
    public function lte($value)
987
    {
988
        $this->expr->lte($value);
989
        return $this;
990
    }
991
992
    /**
993
     * Change the query type to a mapReduce command.
994
     *
995
     * The "reduce" option is not specified when calling this method; it must
996
     * be set with the {@link Builder::reduce()} method.
997
     *
998
     * The "out" option defaults to inline, like {@link Builder::mapReduce()}.
999
     *
1000
     * @see http://docs.mongodb.org/manual/reference/command/mapReduce/
1001
     * @param string|\MongoCode $map
1002
     * @return $this
1003
     */
1004 1
    public function map($map)
1005
    {
1006 1
        $this->query['type'] = Query::TYPE_MAP_REDUCE;
1007 1
        $this->query['mapReduce'] = [
1008 1
            'map' => $map,
1009
            'reduce' => null,
1010
            'out' => ['inline' => true],
1011
            'options' => [],
1012
        ];
1013 1
        return $this;
1014
    }
1015
1016
    /**
1017
     * Change the query type to a mapReduce command.
1018
     *
1019
     * @see http://docs.mongodb.org/manual/reference/command/mapReduce/
1020
     * @param string|\MongoCode $map
1021
     * @param string|\MongoCode $reduce
1022
     * @param array|string $out
1023
     * @param array $options
1024
     * @return $this
1025
     */
1026 1
    public function mapReduce($map, $reduce, $out = ['inline' => true], array $options = [])
1027
    {
1028 1
        $this->query['type'] = Query::TYPE_MAP_REDUCE;
1029 1
        $this->query['mapReduce'] = [
1030 1
            'map' => $map,
1031 1
            'reduce' => $reduce,
1032 1
            'out' => $out,
1033 1
            'options' => $options
1034
        ];
1035 1
        return $this;
1036
    }
1037
1038
    /**
1039
     * Set additional options for a mapReduce command.
1040
     *
1041
     * @param array $options
1042
     * @return $this
1043
     * @throws \BadMethodCallException if the query is not a mapReduce command
1044
     */
1045 1 View Code Duplication
    public function mapReduceOptions(array $options)
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...
1046
    {
1047 1
        if ($this->query['type'] !== Query::TYPE_MAP_REDUCE) {
1048 1
            throw new \BadMethodCallException('This method requires a mapReduce command (call map() or mapReduce() first)');
1049
        }
1050
1051
        $this->query['mapReduce']['options'] = $options;
1052
        return $this;
1053
    }
1054
1055
    /**
1056
     * Updates the value of the field to a specified value if the specified value is greater than the current value of the field.
1057
     *
1058
     * @see Expr::max()
1059
     * @see http://docs.mongodb.org/manual/reference/operator/update/max/
1060
     * @param mixed $value
1061
     * @return $this
1062
     */
1063 1
    public function max($value)
1064
    {
1065 1
        $this->expr->max($value);
1066 1
        return $this;
1067
    }
1068
1069
    /**
1070
     * Specifies a cumulative time limit in milliseconds for processing operations on a cursor.
1071
     *
1072
     * @param int $ms
1073
     * @return $this
1074
     */
1075
    public function maxTimeMS($ms)
1076
    {
1077
        $this->query['maxTimeMS'] = $ms;
1078
        return $this;
1079
    }
1080
1081
    /**
1082
     * Updates the value of the field to a specified value if the specified value is less than the current value of the field.
1083
     *
1084
     * @see Expr::min()
1085
     * @see http://docs.mongodb.org/manual/reference/operator/update/min/
1086
     * @param mixed $value
1087
     * @return $this
1088
     */
1089 1
    public function min($value)
1090
    {
1091 1
        $this->expr->min($value);
1092 1
        return $this;
1093
    }
1094
1095
    /**
1096
     * Specify $mod criteria for the current field.
1097
     *
1098
     * @see Expr::mod()
1099
     * @see http://docs.mongodb.org/manual/reference/operator/mod/
1100
     * @param float|integer $divisor
1101
     * @param float|integer $remainder
1102
     * @return $this
1103
     */
1104 1
    public function mod($divisor, $remainder = 0)
1105
    {
1106 1
        $this->expr->mod($divisor, $remainder);
1107 1
        return $this;
1108
    }
1109
1110
    /**
1111
     * Multiply the current field.
1112
     *
1113
     * If the field does not exist, it will be set to 0.
1114
     *
1115
     * @see Expr::mul()
1116
     * @see http://docs.mongodb.org/manual/reference/operator/mul/
1117
     * @param float|integer $value
1118
     * @return $this
1119
     */
1120 1
    public function mul($value)
1121
    {
1122 1
        $this->expr->mul($value);
1123 1
        return $this;
1124
    }
1125
1126
    /**
1127
     * Set the "multiple" option for an update query.
1128
     *
1129
     * @param boolean $bool
1130
     * @return $this
1131
     *
1132
     * @deprecated Deprecated in version 1.4 - use updateOne or updateMany instead
1133
     */
1134
    public function multiple($bool = true)
1135
    {
1136
        $this->query['multiple'] = (boolean) $bool;
1137
        return $this;
1138
    }
1139
1140
    /**
1141
     * Add $near criteria to the query.
1142
     *
1143
     * A GeoJSON point may be provided as the first and only argument for
1144
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
1145
     * an array corresponding to the point's JSON representation.
1146
     *
1147
     * @see Expr::near()
1148
     * @see http://docs.mongodb.org/manual/reference/operator/near/
1149
     * @param float|array|Point $x
1150
     * @param float $y
1151
     * @return $this
1152
     */
1153 1
    public function near($x, $y = null)
1154
    {
1155 1
        $this->expr->near($x, $y);
1156 1
        return $this;
1157
    }
1158
1159
    /**
1160
     * Add $nearSphere criteria to the query.
1161
     *
1162
     * A GeoJSON point may be provided as the first and only argument for
1163
     * 2dsphere queries. This single parameter may be a GeoJSON point object or
1164
     * an array corresponding to the point's JSON representation.
1165
     *
1166
     * @see Expr::nearSphere()
1167
     * @see http://docs.mongodb.org/manual/reference/operator/nearSphere/
1168
     * @param float|array|Point $x
1169
     * @param float $y
1170
     * @return $this
1171
     */
1172 1
    public function nearSphere($x, $y = null)
1173
    {
1174 1
        $this->expr->nearSphere($x, $y);
1175 1
        return $this;
1176
    }
1177
1178
    /**
1179
     * Negates an expression for the current field.
1180
     *
1181
     * You can create a new expression using the {@link Builder::expr()} method.
1182
     *
1183
     * @see Expr::not()
1184
     * @see http://docs.mongodb.org/manual/reference/operator/not/
1185
     * @param array|Expr $expression
1186
     * @return $this
1187
     */
1188 3
    public function not($expression)
1189
    {
1190 3
        $this->expr->not($expression);
1191 3
        return $this;
1192
    }
1193
1194
    /**
1195
     * Specify $ne criteria for the current field.
1196
     *
1197
     * @see Expr::notEqual()
1198
     * @see http://docs.mongodb.org/manual/reference/operator/ne/
1199
     * @param mixed $value
1200
     * @return $this
1201
     */
1202 4
    public function notEqual($value)
1203
    {
1204 4
        $this->expr->notEqual($value);
1205 4
        return $this;
1206
    }
1207
1208
    /**
1209
     * Specify $nin criteria for the current field.
1210
     *
1211
     * @see Expr::notIn()
1212
     * @see http://docs.mongodb.org/manual/reference/operator/nin/
1213
     * @param array $values
1214
     * @return $this
1215
     */
1216 4
    public function notIn(array $values)
1217
    {
1218 4
        $this->expr->notIn($values);
1219 4
        return $this;
1220
    }
1221
1222
    /**
1223
     * Set the "out" option for a mapReduce command.
1224
     *
1225
     * @param array|string $out
1226
     * @return $this
1227
     * @throws \BadMethodCallException if the query is not a mapReduce command
1228
     */
1229 1 View Code Duplication
    public function out($out)
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...
1230
    {
1231 1
        if ($this->query['type'] !== Query::TYPE_MAP_REDUCE) {
1232 1
            throw new \BadMethodCallException('This method requires a mapReduce command (call map() or mapReduce() first)');
1233
        }
1234
1235
        $this->query['mapReduce']['out'] = $out;
1236
        return $this;
1237
    }
1238
1239
    /**
1240
     * Remove the first element from the current array field.
1241
     *
1242
     * @see Expr::popFirst()
1243
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
1244
     * @return $this
1245
     */
1246 2
    public function popFirst()
1247
    {
1248 2
        $this->expr->popFirst();
1249 2
        return $this;
1250
    }
1251
1252
    /**
1253
     * Remove the last element from the current array field.
1254
     *
1255
     * @see Expr::popLast()
1256
     * @see http://docs.mongodb.org/manual/reference/operator/pop/
1257
     * @return $this
1258
     */
1259 1
    public function popLast()
1260
    {
1261 1
        $this->expr->popLast();
1262 1
        return $this;
1263
    }
1264
1265
    /**
1266
     * Use a primer to eagerly load all references in the current field.
1267
     *
1268
     * If $primer is true or a callable is provided, referenced documents for
1269
     * this field will loaded into UnitOfWork immediately after the query is
1270
     * executed. This will avoid multiple queries due to lazy initialization of
1271
     * Proxy objects.
1272
     *
1273
     * If $primer is false, no priming will take place. That is also the default
1274
     * behavior.
1275
     *
1276
     * If a custom callable is used, its signature should conform to the default
1277
     * Closure defined in {@link ReferencePrimer::__construct()}.
1278
     *
1279
     * @param boolean|callable $primer
1280
     * @return $this
1281
     * @throws \InvalidArgumentException If $primer is not boolean or callable
1282
     */
1283 25
    public function prime($primer = true)
1284
    {
1285 25
        if ( ! is_bool($primer) && ! is_callable($primer)) {
1286 1
            throw new \InvalidArgumentException('$primer is not a boolean or callable');
1287
        }
1288
1289 24
        if ($primer === false) {
1290
            unset($this->primers[$this->currentField]);
1291
1292
            return $this;
1293
        }
1294
1295 24
        if (array_key_exists('eagerCursor', $this->query) && !$this->query['eagerCursor']) {
1296 1
            throw new \BadMethodCallException("Can't call prime() when setting eagerCursor to false");
1297
        }
1298
1299 23
        $this->primers[$this->currentField] = $primer;
1300 23
        return $this;
1301
    }
1302
1303
    /**
1304
     * Remove all elements matching the given value or expression from the
1305
     * current array field.
1306
     *
1307
     * @see Expr::pull()
1308
     * @see http://docs.mongodb.org/manual/reference/operator/pull/
1309
     * @param mixed|Expr $valueOrExpression
1310
     * @return $this
1311
     */
1312 1
    public function pull($valueOrExpression)
1313
    {
1314 1
        $this->expr->pull($valueOrExpression);
1315 1
        return $this;
1316
    }
1317
1318
    /**
1319
     * Remove all elements matching any of the given values from the current
1320
     * array field.
1321
     *
1322
     * @see Expr::pullAll()
1323
     * @see http://docs.mongodb.org/manual/reference/operator/pullAll/
1324
     * @param array $values
1325
     * @return $this
1326
     */
1327 1
    public function pullAll(array $values)
1328
    {
1329 1
        $this->expr->pullAll($values);
1330 1
        return $this;
1331
    }
1332
1333
    /**
1334
     * Append one or more values to the current array field.
1335
     *
1336
     * If the field does not exist, it will be set to an array containing the
1337
     * value(s) in the argument. If the field is not an array, the query
1338
     * will yield an error.
1339
     *
1340
     * Multiple values may be specified by providing an Expr object and using
1341
     * {@link Expr::each()}. {@link Expr::slice()} and {@link Expr::sort()} may
1342
     * also be used to limit and order array elements, respectively.
1343
     *
1344
     * @see Expr::push()
1345
     * @see http://docs.mongodb.org/manual/reference/operator/push/
1346
     * @see http://docs.mongodb.org/manual/reference/operator/each/
1347
     * @see http://docs.mongodb.org/manual/reference/operator/slice/
1348
     * @see http://docs.mongodb.org/manual/reference/operator/sort/
1349
     * @param mixed|Expr $valueOrExpression
1350
     * @return $this
1351
     */
1352 6
    public function push($valueOrExpression)
1353
    {
1354 6
        $this->expr->push($valueOrExpression);
1355 6
        return $this;
1356
    }
1357
1358
    /**
1359
     * Append multiple values to the current array field.
1360
     *
1361
     * If the field does not exist, it will be set to an array containing the
1362
     * values in the argument. If the field is not an array, the query will
1363
     * yield an error.
1364
     *
1365
     * This operator is deprecated in MongoDB 2.4. {@link Builder::push()} and
1366
     * {@link Expr::each()} should be used in its place.
1367
     *
1368
     * @see Expr::pushAll()
1369
     * @see http://docs.mongodb.org/manual/reference/operator/pushAll/
1370
     * @param array $values
1371
     * @return $this
1372
     */
1373 1
    public function pushAll(array $values)
1374
    {
1375 1
        $this->expr->pushAll($values);
1376 1
        return $this;
1377
    }
1378
1379
    /**
1380
     * Specify $gte and $lt criteria for the current field.
1381
     *
1382
     * This method is shorthand for specifying $gte criteria on the lower bound
1383
     * and $lt criteria on the upper bound. The upper bound is not inclusive.
1384
     *
1385
     * @see Expr::range()
1386
     * @param mixed $start
1387
     * @param mixed $end
1388
     * @return $this
1389
     */
1390 3
    public function range($start, $end)
1391
    {
1392 3
        $this->expr->range($start, $end);
1393 3
        return $this;
1394
    }
1395
1396
    /**
1397
     * @param bool $bool
1398
     * @return $this
1399
     */
1400 2
    public function readOnly($bool = true)
1401
    {
1402 2
        $this->readOnly = $bool;
1403 2
        return $this;
1404
    }
1405
1406
    /**
1407
     * Set the "reduce" option for a mapReduce or group command.
1408
     *
1409
     * @param string|\MongoCode $reduce
1410
     * @return $this
1411
     * @throws \BadMethodCallException if the query is not a mapReduce or group command
1412
     */
1413 2 View Code Duplication
    public function reduce($reduce)
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...
1414
    {
1415 2
        switch ($this->query['type']) {
1416
            case Query::TYPE_MAP_REDUCE:
1417 1
                $this->query['mapReduce']['reduce'] = $reduce;
1418 1
                break;
1419
1420
            case Query::TYPE_GROUP:
1421
                $this->query['group']['reduce'] = $reduce;
1422
                break;
1423
1424
            default:
1425 1
                throw new \BadMethodCallException('mapReduce(), map() or group() must be called before reduce()');
1426
        }
1427
1428 1
        return $this;
1429
    }
1430
1431
    /**
1432
     * @param object $document
1433
     * @return $this
1434
     */
1435 10
    public function references($document)
1436
    {
1437 10
        $this->expr->references($document);
1438 8
        return $this;
1439
    }
1440
1441
    /**
1442
     * @param bool $bool
1443
     * @return $this
1444
     */
1445 5
    public function refresh($bool = true)
1446
    {
1447 5
        $this->refresh = $bool;
1448 5
        return $this;
1449
    }
1450
1451
    /**
1452
     * @param string $documentName
1453
     * @return $this
1454
     */
1455 1
    public function remove($documentName = null)
1456
    {
1457 1
        $this->setDocumentName($documentName);
1458 1
        $this->query['type'] = Query::TYPE_REMOVE;
1459
1460 1
        return $this;
1461
    }
1462
1463
    /**
1464
     * Rename the current field.
1465
     *
1466
     * @see Expr::rename()
1467
     * @see http://docs.mongodb.org/manual/reference/operator/rename/
1468
     * @param string $name
1469
     * @return $this
1470
     */
1471
    public function rename($name)
1472
    {
1473
        $this->expr->rename($name);
1474
        return $this;
1475
    }
1476
1477
    /**
1478
     * @param bool $bool
1479
     * @return $this
1480
     */
1481 4
    public function returnNew($bool = true)
1482
    {
1483 4
        $this->refresh(true);
1484 4
        $this->query['new'] = (boolean) $bool;
1485
1486 4
        return $this;
1487
    }
1488
1489
    /**
1490
     * Set one or more fields to be included in the query projection.
1491
     *
1492
     * @param array|string $fieldName,...
0 ignored issues
show
Documentation introduced by
There is no parameter named $fieldName,.... Did you maybe mean $fieldName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1493
     * @return $this
1494
     */
1495 19 View Code Duplication
    public function select($fieldName = 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...
1496
    {
1497 19
        if ( ! isset($this->query['select'])) {
1498 18
            $this->query['select'] = [];
1499
        }
1500
1501 19
        $fieldNames = is_array($fieldName) ? $fieldName : func_get_args();
1502
1503 19
        foreach ($fieldNames as $fieldName) {
1504 16
            $this->query['select'][$fieldName] = 1;
1505
        }
1506
1507 19
        return $this;
1508
    }
1509
1510
    /**
1511
     * Select only matching embedded documents in an array field for the query
1512
     * projection.
1513
     *
1514
     * @see http://docs.mongodb.org/manual/reference/projection/elemMatch/
1515
     * @param string $fieldName
1516
     * @param array|Expr $expression
1517
     * @return $this
1518
     */
1519 2
    public function selectElemMatch($fieldName, $expression)
1520
    {
1521 2
        if ($expression instanceof Expr) {
1522 1
            $expression = $expression->getQuery();
1523
        }
1524 2
        $this->query['select'][$fieldName] = ['$elemMatch' => $expression];
1525 2
        return $this;
1526
    }
1527
1528
    /**
1529
     * Select a metadata field for the query projection.
1530
     *
1531
     * @see http://docs.mongodb.org/master/reference/operator/projection/meta/
1532
     * @param string $fieldName
1533
     * @param string $metaDataKeyword
1534
     * @return $this
1535
     */
1536 2
    public function selectMeta($fieldName, $metaDataKeyword)
1537
    {
1538 2
        $this->query['select'][$fieldName] = ['$meta' => $metaDataKeyword];
1539 2
        return $this;
1540
    }
1541
1542
    /**
1543
     * Select a slice of an array field for the query projection.
1544
     *
1545
     * The $countOrSkip parameter has two very different meanings, depending on
1546
     * whether or not $limit is provided. See the MongoDB documentation for more
1547
     * information.
1548
     *
1549
     * @see http://docs.mongodb.org/manual/reference/projection/slice/
1550
     * @param string $fieldName
1551
     * @param integer $countOrSkip Count parameter, or skip if limit is specified
1552
     * @param integer $limit       Limit parameter used in conjunction with skip
1553
     * @return $this
1554
     */
1555 3
    public function selectSlice($fieldName, $countOrSkip, $limit = null)
1556
    {
1557 3
        $slice = $countOrSkip;
1558 3
        if ($limit !== null) {
1559 2
            $slice = [$slice, $limit];
1560
        }
1561 3
        $this->query['select'][$fieldName] = ['$slice' => $slice];
1562 3
        return $this;
1563
    }
1564
1565
    /**
1566
     * Set the current field to a value.
1567
     *
1568
     * This is only relevant for insert, update, or findAndUpdate queries. For
1569
     * update and findAndUpdate queries, the $atomic parameter will determine
1570
     * whether or not a $set operator is used.
1571
     *
1572
     * @see Expr::set()
1573
     * @see http://docs.mongodb.org/manual/reference/operator/set/
1574
     * @param mixed $value
1575
     * @param boolean $atomic
1576
     * @return $this
1577
     */
1578 16
    public function set($value, $atomic = true)
1579
    {
1580 16
        $this->expr->set($value, $atomic && $this->query['type'] !== Query::TYPE_INSERT);
1581 16
        return $this;
1582
    }
1583
1584
    /**
1585
     * Set the expression's "new object".
1586
     *
1587
     * @see Expr::setNewObj()
1588
     * @param array $newObj
1589
     * @return $this
1590
     */
1591
    public function setNewObj(array $newObj)
1592
    {
1593
        $this->expr->setNewObj($newObj);
1594
        return $this;
1595
    }
1596
1597
    /**
1598
     * Set the current field to the value if the document is inserted in an
1599
     * upsert operation.
1600
     *
1601
     * If an update operation with upsert: true results in an insert of a
1602
     * document, then $setOnInsert assigns the specified values to the fields in
1603
     * the document. If the update operation does not result in an insert,
1604
     * $setOnInsert does nothing.
1605
     *
1606
     * @see Expr::setOnInsert()
1607
     * @see https://docs.mongodb.org/manual/reference/operator/update/setOnInsert/
1608
     * @param mixed $value
1609
     * @return $this
1610
     */
1611 2
    public function setOnInsert($value)
1612
    {
1613 2
        $this->expr->setOnInsert($value);
1614 2
        return $this;
1615
    }
1616
1617
    /**
1618
     * Set the read preference for the query.
1619
     *
1620
     * This is only relevant for read-only queries and commands.
1621
     *
1622
     * @see http://docs.mongodb.org/manual/core/read-preference/
1623
     * @param ReadPreference $readPreference
1624
     * @return $this
1625
     */
1626 6
    public function setReadPreference(ReadPreference $readPreference)
1627
    {
1628 6
        $this->query['readPreference'] = $readPreference;
1629 6
        return $this;
1630
    }
1631
1632
    /**
1633
     * Set the expression's query criteria.
1634
     *
1635
     * @see Expr::setQuery()
1636
     * @param array $query
1637
     * @return $this
1638
     */
1639 18
    public function setQueryArray(array $query)
1640
    {
1641 18
        $this->expr->setQuery($query);
1642 18
        return $this;
1643
    }
1644
1645
    /**
1646
     * Specify $size criteria for the current field.
1647
     *
1648
     * @see Expr::size()
1649
     * @see http://docs.mongodb.org/manual/reference/operator/size/
1650
     * @param integer $size
1651
     * @return $this
1652
     */
1653 1
    public function size($size)
1654
    {
1655 1
        $this->expr->size((integer) $size);
1656 1
        return $this;
1657
    }
1658
1659
    /**
1660
     * Set the skip for the query cursor.
1661
     *
1662
     * This is only relevant for find queries, or mapReduce queries that store
1663
     * results in an output collecton and return a cursor.
1664
     *
1665
     * @see Query::prepareCursor()
1666
     * @param integer $skip
1667
     * @return $this
1668
     */
1669
    public function skip($skip)
1670
    {
1671
        $this->query['skip'] = (integer) $skip;
1672
        return $this;
1673
    }
1674
1675
    /**
1676
     * Set the snapshot cursor flag.
1677
     *
1678
     * @param boolean $bool
1679
     * @return $this
1680
     */
1681
    public function snapshot($bool = true)
1682
    {
1683
        $this->query['snapshot'] = (boolean) $bool;
1684
        return $this;
1685
    }
1686
1687
    /**
1688
     * Set one or more field/order pairs on which to sort the query.
1689
     *
1690
     * If sorting by multiple fields, the first argument should be an array of
1691
     * field name (key) and order (value) pairs.
1692
     *
1693
     * @param array|string $fieldName Field name or array of field/order pairs
1694
     * @param int|string $order       Field order (if one field is specified)
1695
     * @return $this
1696
     */
1697 31
    public function sort($fieldName, $order = 1)
1698
    {
1699 31
        if ( ! isset($this->query['sort'])) {
1700 31
            $this->query['sort'] = [];
1701
        }
1702
1703 31
        $fields = is_array($fieldName) ? $fieldName : [$fieldName => $order];
1704
1705 31
        foreach ($fields as $fieldName => $order) {
1706 14
            if (is_string($order)) {
1707 9
                $order = strtolower($order) === 'asc' ? 1 : -1;
1708
            }
1709 14
            $this->query['sort'][$fieldName] = (integer) $order;
1710
        }
1711
1712 31
        return $this;
1713
    }
1714
1715
    /**
1716
     * Specify a projected metadata field on which to sort the query.
1717
     *
1718
     * Sort order is not configurable for metadata fields. Sorting by a metadata
1719
     * field requires the same field and $meta expression to exist in the
1720
     * projection document. This method will call {@link Builder::selectMeta()}
1721
     * if the field is not already set in the projection.
1722
     *
1723
     * @see http://docs.mongodb.org/master/reference/operator/projection/meta/#sort
1724
     * @param string $fieldName       Field name of the projected metadata
1725
     * @param string $metaDataKeyword
1726
     * @return $this
1727
     */
1728 2
    public function sortMeta($fieldName, $metaDataKeyword)
1729
    {
1730
        /* It's possible that the field is already projected without the $meta
1731
         * operator. We'll assume that the user knows what they're doing in that
1732
         * case and will not attempt to override the projection.
1733
         */
1734 2
        if ( ! isset($this->query['select'][$fieldName])) {
1735 1
            $this->selectMeta($fieldName, $metaDataKeyword);
1736
        }
1737
1738 2
        $this->query['sort'][$fieldName] = ['$meta' => $metaDataKeyword];
1739
1740 2
        return $this;
1741
    }
1742
1743
    /**
1744
     * Specify $text criteria for the current field.
1745
     *
1746
     * The $language option may be set with {@link Builder::language()}.
1747
     *
1748
     * @see Expr::text()
1749
     * @see http://docs.mongodb.org/master/reference/operator/query/text/
1750
     * @param string $search
1751
     * @return $this
1752
     */
1753 1
    public function text($search)
1754
    {
1755 1
        $this->expr->text($search);
1756 1
        return $this;
1757
    }
1758
1759
    /**
1760
     * Specify $type criteria for the current field.
1761
     *
1762
     * @see Expr::type()
1763
     * @see http://docs.mongodb.org/manual/reference/operator/type/
1764
     * @param integer $type
1765
     * @return $this
1766
     */
1767 2
    public function type($type)
1768
    {
1769 2
        $this->expr->type($type);
1770 2
        return $this;
1771
    }
1772
1773
    /**
1774
     * Unset the current field.
1775
     *
1776
     * The field will be removed from the document (not set to null).
1777
     *
1778
     * @see Expr::unsetField()
1779
     * @see http://docs.mongodb.org/manual/reference/operator/unset/
1780
     * @return $this
1781
     */
1782 4
    public function unsetField()
1783
    {
1784 4
        $this->expr->unsetField();
1785 4
        return $this;
1786
    }
1787
1788
    /**
1789
     * @param string $documentName
1790
     * @return $this
1791
     */
1792 21 View Code Duplication
    public function updateOne($documentName = 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...
1793
    {
1794 21
        $this->setDocumentName($documentName);
1795 21
        $this->query['type'] = Query::TYPE_UPDATE;
1796 21
        $this->query['multiple'] = false;
1797
1798 21
        return $this;
1799
    }
1800
1801
    /**
1802
     * @param string $documentName
1803
     * @return $this
1804
     */
1805 3 View Code Duplication
    public function updateMany($documentName = 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...
1806
    {
1807 3
        $this->setDocumentName($documentName);
1808 3
        $this->query['type'] = Query::TYPE_UPDATE;
1809 3
        $this->query['multiple'] = true;
1810
1811 3
        return $this;
1812
    }
1813
1814
    /**
1815
     * Set the "upsert" option for an update or findAndUpdate query.
1816
     *
1817
     * @param boolean $bool
1818
     * @return $this
1819
     */
1820 7
    public function upsert($bool = true)
1821
    {
1822 7
        $this->query['upsert'] = (boolean) $bool;
1823 7
        return $this;
1824
    }
1825
1826
    /**
1827
     * Specify a JavaScript expression to use for matching documents.
1828
     *
1829
     * @see Expr::where()
1830
     * @see http://docs.mongodb.org/manual/reference/operator/where/
1831
     * @param string|\MongoCode $javascript
1832
     * @return $this
1833
     */
1834 3
    public function where($javascript)
1835
    {
1836 3
        $this->expr->where($javascript);
1837 3
        return $this;
1838
    }
1839
1840
    /**
1841
     * Add $within criteria with a $box shape to the query.
1842
     *
1843
     * @deprecated 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin
1844
     * @see Builder::geoWithinBox()
1845
     * @see Expr::withinBox()
1846
     * @see http://docs.mongodb.org/manual/reference/operator/box/
1847
     * @param float $x1
1848
     * @param float $y1
1849
     * @param float $x2
1850
     * @param float $y2
1851
     * @return $this
1852
     */
1853 1
    public function withinBox($x1, $y1, $x2, $y2)
1854
    {
1855 1
        $this->expr->withinBox($x1, $y1, $x2, $y2);
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Query\Expr::withinBox() has been deprecated with message: 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1856 1
        return $this;
1857
    }
1858
1859
    /**
1860
     * Add $within criteria with a $center shape to the query.
1861
     *
1862
     * @deprecated 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin
1863
     * @see Builder::geoWithinCenter()
1864
     * @see Expr::withinCenter()
1865
     * @see http://docs.mongodb.org/manual/reference/operator/center/
1866
     * @param float $x
1867
     * @param float $y
1868
     * @param float $radius
1869
     * @return $this
1870
     */
1871 1
    public function withinCenter($x, $y, $radius)
1872
    {
1873 1
        $this->expr->withinCenter($x, $y, $radius);
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Query\Expr::withinCenter() has been deprecated with message: 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1874 1
        return $this;
1875
    }
1876
1877
    /**
1878
     * Add $within criteria with a $centerSphere shape to the query.
1879
     *
1880
     * @deprecated 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin
1881
     * @see Builder::geoWithinCenterSphere()
1882
     * @see Expr::withinCenterSphere()
1883
     * @see http://docs.mongodb.org/manual/reference/operator/centerSphere/
1884
     * @param float $x
1885
     * @param float $y
1886
     * @param float $radius
1887
     * @return $this
1888
     */
1889 1
    public function withinCenterSphere($x, $y, $radius)
1890
    {
1891 1
        $this->expr->withinCenterSphere($x, $y, $radius);
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Que...r::withinCenterSphere() has been deprecated with message: 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1892 1
        return $this;
1893
    }
1894
1895
    /**
1896
     * Add $within criteria with a $polygon shape to the query.
1897
     *
1898
     * Point coordinates are in x, y order (easting, northing for projected
1899
     * coordinates, longitude, latitude for geographic coordinates).
1900
     *
1901
     * The last point coordinate is implicitly connected with the first.
1902
     *
1903
     * @deprecated 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin
1904
     * @see Builder::geoWithinPolygon()
1905
     * @see Expr::withinPolygon()
1906
     * @see http://docs.mongodb.org/manual/reference/operator/polygon/
1907
     * @param array $point,... Three or more point coordinate tuples
0 ignored issues
show
Bug introduced by
There is no parameter named $point,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1908
     * @return $this
1909
     */
1910 1
    public function withinPolygon(/* array($x1, $y1), array($x2, $y2), ... */)
1911
    {
1912 1
        $this->expr->withinPolygon(...func_get_args());
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Query\Expr::withinPolygon() has been deprecated with message: 1.1 MongoDB 2.4 deprecated $within in favor of $geoWithin

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1913 1
        return $this;
1914
    }
1915
1916
    /**
1917
     * Get Discriminator Values
1918
     *
1919
     * @param \Traversable $classNames
1920
     * @return array an array of discriminatorValues (mixed type)
1921
     * @throws \InvalidArgumentException if the number of found collections > 1
1922
     */
1923 2
    private function getDiscriminatorValues($classNames)
1924
    {
1925 2
        $discriminatorValues = array();
1926 2
        $collections = array();
1927 2
        foreach ($classNames as $className) {
1928 2
            $class = $this->dm->getClassMetadata($className);
1929 2
            $discriminatorValues[] = $class->discriminatorValue;
1930 2
            $key = $this->dm->getDocumentDatabase($className)->getDatabaseName() . '.' . $class->getCollection();
1931 2
            $collections[$key] = $key;
1932
        }
1933 2
        if (count($collections) > 1) {
1934 1
            throw new \InvalidArgumentException('Documents involved are not all mapped to the same database collection.');
1935
        }
1936 1
        return $discriminatorValues;
1937
    }
1938
1939
    /**
1940
     * @param string[]|string $documentName an array of document names or just one.
1941
     */
1942 290
    private function setDocumentName($documentName)
1943
    {
1944 290
        if (is_array($documentName)) {
1945 2
            $documentNames = $documentName;
1946 2
            $documentName = $documentNames[0];
1947
1948 2
            $metadata = $this->dm->getClassMetadata($documentName);
1949 2
            $discriminatorField = $metadata->discriminatorField;
1950 2
            $discriminatorValues = $this->getDiscriminatorValues($documentNames);
0 ignored issues
show
Documentation introduced by
$documentNames is of type array, but the function expects a object<Traversable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1951
1952
            // If a defaultDiscriminatorValue is set and it is among the discriminators being queries, add NULL to the list
1953 1 View Code Duplication
            if ($metadata->defaultDiscriminatorValue && array_search($metadata->defaultDiscriminatorValue, $discriminatorValues) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1954 1
                $discriminatorValues[] = null;
1955
            }
1956
1957 1
            $this->field($discriminatorField)->in($discriminatorValues);
1958
        }
1959
1960 289
        if ($documentName !== null) {
1961 289
            $this->collection = $this->dm->getDocumentCollection($documentName);
1962 289
            $this->class = $this->dm->getClassMetadata($documentName);
1963
1964
            // Expr also needs to know
1965 289
            $this->expr->setClassMetadata($this->class);
1966
        }
1967 289
    }
1968
}
1969