These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Doctrine\ODM\MongoDB\Query; |
||
6 | |||
7 | use BadMethodCallException; |
||
8 | use Doctrine\ODM\MongoDB\DocumentManager; |
||
9 | use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; |
||
10 | use GeoJson\Geometry\Geometry; |
||
11 | use GeoJson\Geometry\Point; |
||
12 | use InvalidArgumentException; |
||
13 | use MongoDB\BSON\Binary; |
||
14 | use MongoDB\BSON\Javascript; |
||
15 | use MongoDB\Collection; |
||
16 | use MongoDB\Driver\ReadPreference; |
||
17 | use function array_filter; |
||
18 | use function array_key_exists; |
||
19 | use function count; |
||
20 | use function func_get_args; |
||
21 | use function in_array; |
||
22 | use function is_array; |
||
23 | use function is_bool; |
||
24 | use function is_callable; |
||
25 | use function is_string; |
||
26 | use function strtolower; |
||
27 | |||
28 | /** |
||
29 | * Query builder for ODM. |
||
30 | */ |
||
31 | class Builder |
||
32 | { |
||
33 | /** |
||
34 | * The DocumentManager instance for this query |
||
35 | * |
||
36 | * @var DocumentManager |
||
37 | */ |
||
38 | private $dm; |
||
39 | |||
40 | /** |
||
41 | * The ClassMetadata instance. |
||
42 | * |
||
43 | * @var ClassMetadata |
||
44 | */ |
||
45 | private $class; |
||
46 | |||
47 | /** |
||
48 | * The current field we are operating on. |
||
49 | * |
||
50 | * @todo Change this to private once ODM requires doctrine/mongodb 1.1+ |
||
51 | * @var string |
||
52 | */ |
||
53 | protected $currentField; |
||
54 | |||
55 | /** |
||
56 | * Whether or not to hydrate the data to documents. |
||
57 | * |
||
58 | * @var bool |
||
59 | */ |
||
60 | private $hydrate = true; |
||
61 | |||
62 | /** |
||
63 | * Whether or not to refresh the data for documents that are already in the identity map. |
||
64 | * |
||
65 | * @var bool |
||
66 | */ |
||
67 | private $refresh = false; |
||
68 | |||
69 | /** |
||
70 | * Array of primer Closure instances. |
||
71 | * |
||
72 | * @var array |
||
73 | */ |
||
74 | private $primers = []; |
||
75 | |||
76 | /** |
||
77 | * Whether or not to register documents in UnitOfWork. |
||
78 | * |
||
79 | * @var bool |
||
80 | */ |
||
81 | private $readOnly = false; |
||
82 | |||
83 | /** |
||
84 | * The Collection instance. |
||
85 | * |
||
86 | * @var Collection |
||
87 | */ |
||
88 | private $collection; |
||
89 | |||
90 | /** |
||
91 | * Array containing the query data. |
||
92 | * |
||
93 | * @var array |
||
94 | */ |
||
95 | private $query = ['type' => Query::TYPE_FIND]; |
||
96 | |||
97 | /** |
||
98 | * The Expr instance used for building this query. |
||
99 | * |
||
100 | * This object includes the query criteria and the "new object" used for |
||
101 | * insert and update queries. |
||
102 | * |
||
103 | * @var Expr $expr |
||
104 | */ |
||
105 | private $expr; |
||
106 | |||
107 | /** |
||
108 | * Construct a Builder |
||
109 | * |
||
110 | * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none |
||
111 | */ |
||
112 | 286 | public function __construct(DocumentManager $dm, $documentName = null) |
|
113 | { |
||
114 | 286 | $this->dm = $dm; |
|
115 | 286 | $this->expr = new Expr($dm); |
|
116 | 286 | if ($documentName === null) { |
|
117 | 9 | return; |
|
118 | } |
||
119 | |||
120 | 278 | $this->setDocumentName($documentName); |
|
121 | 277 | } |
|
122 | |||
123 | 1 | public function __clone() |
|
124 | { |
||
125 | 1 | $this->expr = clone $this->expr; |
|
126 | 1 | } |
|
127 | |||
128 | /** |
||
129 | * Add one or more $and clauses to the current query. |
||
130 | * |
||
131 | * You can create a new expression using the {@link Builder::expr()} method. |
||
132 | * |
||
133 | * @see Expr::addAnd() |
||
134 | * @see http://docs.mongodb.org/manual/reference/operator/and/ |
||
135 | * |
||
136 | * @param array|Expr $expression |
||
137 | * @param array|Expr ...$expressions |
||
138 | */ |
||
139 | 4 | public function addAnd($expression, ...$expressions) : self |
|
140 | { |
||
141 | 4 | $this->expr->addAnd(...func_get_args()); |
|
142 | 4 | return $this; |
|
143 | } |
||
144 | |||
145 | /** |
||
146 | * Add one or more $nor clauses to the current query. |
||
147 | * |
||
148 | * You can create a new expression using the {@link Builder::expr()} method. |
||
149 | * |
||
150 | * @see Expr::addNor() |
||
151 | * @see http://docs.mongodb.org/manual/reference/operator/nor/ |
||
152 | * |
||
153 | * @param array|Expr $expression |
||
154 | * @param array|Expr ...$expressions |
||
155 | */ |
||
156 | 3 | public function addNor($expression, ...$expressions) : self |
|
157 | { |
||
158 | 3 | $this->expr->addNor(...func_get_args()); |
|
159 | 3 | return $this; |
|
160 | } |
||
161 | |||
162 | /** |
||
163 | * Add one or more $or clauses to the current query. |
||
164 | * |
||
165 | * You can create a new expression using the {@link Builder::expr()} method. |
||
166 | * |
||
167 | * @see Expr::addOr() |
||
168 | * @see http://docs.mongodb.org/manual/reference/operator/or/ |
||
169 | * |
||
170 | * @param array|Expr $expression |
||
171 | * @param array|Expr ...$expressions |
||
172 | */ |
||
173 | 6 | public function addOr($expression, ...$expressions) : self |
|
174 | { |
||
175 | 6 | $this->expr->addOr(...func_get_args()); |
|
176 | 6 | return $this; |
|
177 | } |
||
178 | |||
179 | /** |
||
180 | * Append one or more values to the current array field only if they do not |
||
181 | * already exist in the array. |
||
182 | * |
||
183 | * If the field does not exist, it will be set to an array containing the |
||
184 | * unique value(s) in the argument. If the field is not an array, the query |
||
185 | * will yield an error. |
||
186 | * |
||
187 | * Multiple values may be specified by provided an Expr object and using |
||
188 | * {@link Expr::each()}. |
||
189 | * |
||
190 | * @see Expr::addToSet() |
||
191 | * @see http://docs.mongodb.org/manual/reference/operator/addToSet/ |
||
192 | * @see http://docs.mongodb.org/manual/reference/operator/each/ |
||
193 | * |
||
194 | * @param mixed|Expr $valueOrExpression |
||
195 | */ |
||
196 | 5 | public function addToSet($valueOrExpression) : self |
|
197 | { |
||
198 | 5 | $this->expr->addToSet($valueOrExpression); |
|
199 | 5 | return $this; |
|
200 | } |
||
201 | |||
202 | /** |
||
203 | * Specify $all criteria for the current field. |
||
204 | * |
||
205 | * @see Expr::all() |
||
206 | * @see http://docs.mongodb.org/manual/reference/operator/all/ |
||
207 | */ |
||
208 | 3 | public function all(array $values) : self |
|
209 | { |
||
210 | 3 | $this->expr->all($values); |
|
211 | 3 | return $this; |
|
212 | } |
||
213 | |||
214 | /** |
||
215 | * Apply a bitwise and operation on the current field. |
||
216 | * |
||
217 | * @see Expr::bitAnd() |
||
218 | * @see http://docs.mongodb.org/manual/reference/operator/update/bit/ |
||
219 | * |
||
220 | * @return $this |
||
221 | */ |
||
222 | 1 | public function bitAnd(int $value) : self |
|
223 | { |
||
224 | 1 | $this->expr->bitAnd($value); |
|
225 | 1 | return $this; |
|
226 | } |
||
227 | |||
228 | /** |
||
229 | * Apply a bitwise or operation on the current field. |
||
230 | * |
||
231 | * @see Expr::bitOr() |
||
232 | * @see http://docs.mongodb.org/manual/reference/operator/update/bit/ |
||
233 | */ |
||
234 | 1 | public function bitOr(int $value) : self |
|
235 | { |
||
236 | 1 | $this->expr->bitOr($value); |
|
237 | 1 | return $this; |
|
238 | } |
||
239 | |||
240 | /** |
||
241 | * Matches documents where all of the bit positions given by the query are |
||
242 | * clear. |
||
243 | * |
||
244 | * @see Expr::bitsAllClear() |
||
245 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllClear/ |
||
246 | * |
||
247 | * @param int|array|Binary $value |
||
248 | */ |
||
249 | 1 | public function bitsAllClear($value) : self |
|
250 | { |
||
251 | 1 | $this->expr->bitsAllClear($value); |
|
252 | 1 | return $this; |
|
253 | } |
||
254 | |||
255 | /** |
||
256 | * Matches documents where all of the bit positions given by the query are |
||
257 | * set. |
||
258 | * |
||
259 | * @see Expr::bitsAllSet() |
||
260 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllSet/ |
||
261 | * |
||
262 | * @param int|array|Binary $value |
||
263 | */ |
||
264 | 1 | public function bitsAllSet($value) : self |
|
265 | { |
||
266 | 1 | $this->expr->bitsAllSet($value); |
|
267 | 1 | return $this; |
|
268 | } |
||
269 | |||
270 | /** |
||
271 | * Matches documents where any of the bit positions given by the query are |
||
272 | * clear. |
||
273 | * |
||
274 | * @see Expr::bitsAnyClear() |
||
275 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnyClear/ |
||
276 | * |
||
277 | * @param int|array|Binary $value |
||
278 | */ |
||
279 | 1 | public function bitsAnyClear($value) : self |
|
280 | { |
||
281 | 1 | $this->expr->bitsAnyClear($value); |
|
282 | 1 | return $this; |
|
283 | } |
||
284 | |||
285 | /** |
||
286 | * Matches documents where any of the bit positions given by the query are |
||
287 | * set. |
||
288 | * |
||
289 | * @see Expr::bitsAnySet() |
||
290 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnySet/ |
||
291 | * |
||
292 | * @param int|array|Binary $value |
||
293 | */ |
||
294 | 1 | public function bitsAnySet($value) : self |
|
295 | { |
||
296 | 1 | $this->expr->bitsAnySet($value); |
|
297 | 1 | return $this; |
|
298 | } |
||
299 | |||
300 | /** |
||
301 | * Apply a bitwise xor operation on the current field. |
||
302 | * |
||
303 | * @see Expr::bitXor() |
||
304 | * @see http://docs.mongodb.org/manual/reference/operator/update/bit/ |
||
305 | */ |
||
306 | 1 | public function bitXor(int $value) : self |
|
307 | { |
||
308 | 1 | $this->expr->bitXor($value); |
|
309 | 1 | return $this; |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * A boolean flag to enable or disable case sensitive search for $text |
||
314 | * criteria. |
||
315 | * |
||
316 | * This method must be called after text(). |
||
317 | * |
||
318 | * @see Expr::caseSensitive() |
||
319 | * @see http://docs.mongodb.org/manual/reference/operator/text/ |
||
320 | * |
||
321 | * @throws BadMethodCallException If the query does not already have $text criteria. |
||
322 | */ |
||
323 | 1 | public function caseSensitive(bool $caseSensitive) : self |
|
324 | { |
||
325 | 1 | $this->expr->caseSensitive($caseSensitive); |
|
326 | 1 | return $this; |
|
327 | } |
||
328 | |||
329 | /** |
||
330 | * Associates a comment to any expression taking a query predicate. |
||
331 | * |
||
332 | * @see Expr::comment() |
||
333 | * @see http://docs.mongodb.org/manual/reference/operator/query/comment/ |
||
334 | */ |
||
335 | 1 | public function comment(string $comment) : self |
|
336 | { |
||
337 | 1 | $this->expr->comment($comment); |
|
338 | 1 | return $this; |
|
339 | } |
||
340 | |||
341 | /** |
||
342 | * Change the query type to count. |
||
343 | */ |
||
344 | public function count() : self |
||
345 | { |
||
346 | $this->query['type'] = Query::TYPE_COUNT; |
||
347 | return $this; |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Sets the value of the current field to the current date, either as a date or a timestamp. |
||
352 | * |
||
353 | * @see Expr::currentDate() |
||
354 | * @see http://docs.mongodb.org/manual/reference/operator/currentDate/ |
||
355 | */ |
||
356 | 3 | public function currentDate(string $type = 'date') : self |
|
357 | { |
||
358 | 3 | $this->expr->currentDate($type); |
|
359 | 2 | return $this; |
|
360 | } |
||
361 | |||
362 | /** |
||
363 | * Return an array of information about the Builder state for debugging. |
||
364 | * |
||
365 | * The $name parameter may be used to return a specific key from the |
||
366 | * internal $query array property. If omitted, the entire array will be |
||
367 | * returned. |
||
368 | * |
||
369 | * @return mixed |
||
370 | */ |
||
371 | 28 | public function debug(?string $name = null) |
|
372 | { |
||
373 | 28 | return $name !== null ? $this->query[$name] : $this->query; |
|
374 | } |
||
375 | |||
376 | /** |
||
377 | * A boolean flag to enable or disable diacritic sensitive search for $text |
||
378 | * criteria. |
||
379 | * |
||
380 | * This method must be called after text(). |
||
381 | * |
||
382 | * @see Builder::diacriticSensitive() |
||
383 | * @see http://docs.mongodb.org/manual/reference/operator/text/ |
||
384 | * |
||
385 | * @throws BadMethodCallException If the query does not already have $text criteria. |
||
386 | */ |
||
387 | 1 | public function diacriticSensitive(bool $diacriticSensitive) : self |
|
388 | { |
||
389 | 1 | $this->expr->diacriticSensitive($diacriticSensitive); |
|
390 | 1 | return $this; |
|
391 | } |
||
392 | |||
393 | /** |
||
394 | * Change the query type to a distinct command. |
||
395 | * |
||
396 | * @see http://docs.mongodb.org/manual/reference/command/distinct/ |
||
397 | */ |
||
398 | 2 | public function distinct(string $field) : self |
|
399 | { |
||
400 | 2 | $this->query['type'] = Query::TYPE_DISTINCT; |
|
401 | 2 | $this->query['distinct'] = $field; |
|
402 | 2 | return $this; |
|
403 | } |
||
404 | |||
405 | /** |
||
406 | * Specify $elemMatch criteria for the current field. |
||
407 | * |
||
408 | * You can create a new expression using the {@link Builder::expr()} method. |
||
409 | * |
||
410 | * @see Expr::elemMatch() |
||
411 | * @see http://docs.mongodb.org/manual/reference/operator/elemMatch/ |
||
412 | * |
||
413 | * @param array|Expr $expression |
||
414 | */ |
||
415 | 6 | public function elemMatch($expression) : self |
|
416 | { |
||
417 | 6 | $this->expr->elemMatch($expression); |
|
418 | 6 | return $this; |
|
419 | } |
||
420 | |||
421 | /** |
||
422 | * Specify an equality match for the current field. |
||
423 | * |
||
424 | * @see Expr::equals() |
||
425 | * |
||
426 | * @param mixed $value |
||
427 | */ |
||
428 | 79 | public function equals($value) : self |
|
429 | { |
||
430 | 79 | $this->expr->equals($value); |
|
431 | 79 | return $this; |
|
432 | } |
||
433 | |||
434 | /** |
||
435 | * Set one or more fields to be excluded from the query projection. |
||
436 | * |
||
437 | * If fields have been selected for inclusion, only the "_id" field may be |
||
438 | * excluded. |
||
439 | * |
||
440 | * @param array|string $fieldName,... |
||
441 | */ |
||
442 | 6 | public function exclude($fieldName = null) : self |
|
443 | { |
||
444 | 6 | if (! isset($this->query['select'])) { |
|
445 | 6 | $this->query['select'] = []; |
|
446 | } |
||
447 | |||
448 | 6 | $fieldNames = is_array($fieldName) ? $fieldName : func_get_args(); |
|
449 | |||
450 | 6 | foreach ($fieldNames as $fieldName) { |
|
451 | 4 | $this->query['select'][$fieldName] = 0; |
|
452 | } |
||
453 | |||
454 | 6 | return $this; |
|
455 | } |
||
456 | |||
457 | /** |
||
458 | * Specify $exists criteria for the current field. |
||
459 | * |
||
460 | * @see Expr::exists() |
||
461 | * @see http://docs.mongodb.org/manual/reference/operator/exists/ |
||
462 | */ |
||
463 | 5 | public function exists(bool $bool) : self |
|
464 | { |
||
465 | 5 | $this->expr->exists($bool); |
|
466 | 5 | return $this; |
|
467 | } |
||
468 | |||
469 | /** |
||
470 | * Create a new Expr instance that can be used as an expression with the Builder |
||
471 | */ |
||
472 | 26 | public function expr() : Expr |
|
473 | { |
||
474 | 26 | $expr = new Expr($this->dm); |
|
475 | 26 | $expr->setClassMetadata($this->class); |
|
476 | |||
477 | 26 | return $expr; |
|
478 | } |
||
479 | |||
480 | /** |
||
481 | * Set the current field to operate on. |
||
482 | */ |
||
483 | 145 | public function field(string $field) : self |
|
484 | { |
||
485 | 145 | $this->currentField = $field; |
|
486 | 145 | $this->expr->field($field); |
|
487 | |||
488 | 145 | return $this; |
|
489 | } |
||
490 | |||
491 | /** |
||
492 | * Set the "finalize" option for a mapReduce or group command. |
||
493 | * |
||
494 | * @param string|Javascript $finalize |
||
495 | * |
||
496 | * @throws BadMethodCallException If the query is not a mapReduce or group command. |
||
497 | */ |
||
498 | 2 | public function finalize($finalize) : self |
|
499 | { |
||
500 | 2 | switch ($this->query['type']) { |
|
501 | case Query::TYPE_MAP_REDUCE: |
||
502 | 1 | $this->query['mapReduce']['options']['finalize'] = $finalize; |
|
503 | 1 | break; |
|
504 | |||
505 | case Query::TYPE_GROUP: |
||
506 | $this->query['group']['options']['finalize'] = $finalize; |
||
507 | break; |
||
508 | |||
509 | default: |
||
510 | 1 | throw new BadMethodCallException('mapReduce(), map() or group() must be called before finalize()'); |
|
511 | } |
||
512 | |||
513 | 1 | return $this; |
|
514 | } |
||
515 | |||
516 | /** |
||
517 | * Change the query type to find and optionally set and change the class being queried. |
||
518 | */ |
||
519 | 13 | public function find(?string $documentName = null) : self |
|
520 | { |
||
521 | 13 | $this->setDocumentName($documentName); |
|
522 | 13 | $this->query['type'] = Query::TYPE_FIND; |
|
523 | |||
524 | 13 | return $this; |
|
525 | } |
||
526 | |||
527 | 1 | public function findAndRemove(?string $documentName = null) : self |
|
528 | { |
||
529 | 1 | $this->setDocumentName($documentName); |
|
530 | 1 | $this->query['type'] = Query::TYPE_FIND_AND_REMOVE; |
|
531 | |||
532 | 1 | return $this; |
|
533 | } |
||
534 | |||
535 | 13 | public function findAndUpdate(?string $documentName = null) : self |
|
536 | { |
||
537 | 13 | $this->setDocumentName($documentName); |
|
538 | 13 | $this->query['type'] = Query::TYPE_FIND_AND_UPDATE; |
|
539 | |||
540 | 13 | return $this; |
|
541 | } |
||
542 | |||
543 | /** |
||
544 | * Add $geoIntersects criteria with a GeoJSON geometry to the query. |
||
545 | * |
||
546 | * The geometry parameter GeoJSON object or an array corresponding to the |
||
547 | * geometry's JSON representation. |
||
548 | * |
||
549 | * @see Expr::geoIntersects() |
||
550 | * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/ |
||
551 | * |
||
552 | * @param array|Geometry $geometry |
||
553 | */ |
||
554 | 1 | public function geoIntersects($geometry) : self |
|
555 | { |
||
556 | 1 | $this->expr->geoIntersects($geometry); |
|
557 | 1 | return $this; |
|
558 | } |
||
559 | |||
560 | /** |
||
561 | * Add $geoWithin criteria with a GeoJSON geometry to the query. |
||
562 | * |
||
563 | * The geometry parameter GeoJSON object or an array corresponding to the |
||
564 | * geometry's JSON representation. |
||
565 | * |
||
566 | * @see Expr::geoWithin() |
||
567 | * @see http://docs.mongodb.org/manual/reference/operator/geoWithin/ |
||
568 | * |
||
569 | * @param array|Geometry $geometry |
||
570 | */ |
||
571 | 1 | public function geoWithin($geometry) : self |
|
572 | { |
||
573 | 1 | $this->expr->geoWithin($geometry); |
|
574 | 1 | return $this; |
|
575 | } |
||
576 | |||
577 | /** |
||
578 | * Add $geoWithin criteria with a $box shape to the query. |
||
579 | * |
||
580 | * A rectangular polygon will be constructed from a pair of coordinates |
||
581 | * corresponding to the bottom left and top right corners. |
||
582 | * |
||
583 | * Note: the $box operator only supports legacy coordinate pairs and 2d |
||
584 | * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes. |
||
585 | * |
||
586 | * @see Expr::geoWithinBox() |
||
587 | * @see http://docs.mongodb.org/manual/reference/operator/box/ |
||
588 | */ |
||
589 | 1 | public function geoWithinBox(float $x1, float $y1, float $x2, float $y2) : self |
|
590 | { |
||
591 | 1 | $this->expr->geoWithinBox($x1, $y1, $x2, $y2); |
|
592 | 1 | return $this; |
|
593 | } |
||
594 | |||
595 | /** |
||
596 | * Add $geoWithin criteria with a $center shape to the query. |
||
597 | * |
||
598 | * Note: the $center operator only supports legacy coordinate pairs and 2d |
||
599 | * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes. |
||
600 | * |
||
601 | * @see Expr::geoWithinCenter() |
||
602 | * @see http://docs.mongodb.org/manual/reference/operator/center/ |
||
603 | */ |
||
604 | 1 | public function geoWithinCenter(float $x, float $y, float $radius) : self |
|
605 | { |
||
606 | 1 | $this->expr->geoWithinCenter($x, $y, $radius); |
|
607 | 1 | return $this; |
|
608 | } |
||
609 | |||
610 | /** |
||
611 | * Add $geoWithin criteria with a $centerSphere shape to the query. |
||
612 | * |
||
613 | * Note: the $centerSphere operator supports both 2d and 2dsphere indexes. |
||
614 | * |
||
615 | * @see Expr::geoWithinCenterSphere() |
||
616 | * @see http://docs.mongodb.org/manual/reference/operator/centerSphere/ |
||
617 | */ |
||
618 | 1 | public function geoWithinCenterSphere(float $x, float $y, float $radius) : self |
|
619 | { |
||
620 | 1 | $this->expr->geoWithinCenterSphere($x, $y, $radius); |
|
621 | 1 | return $this; |
|
622 | } |
||
623 | |||
624 | /** |
||
625 | * Add $geoWithin criteria with a $polygon shape to the query. |
||
626 | * |
||
627 | * Point coordinates are in x, y order (easting, northing for projected |
||
628 | * coordinates, longitude, latitude for geographic coordinates). |
||
629 | * |
||
630 | * The last point coordinate is implicitly connected with the first. |
||
631 | * |
||
632 | * Note: the $polygon operator only supports legacy coordinate pairs and 2d |
||
633 | * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes. |
||
634 | * |
||
635 | * @see Expr::geoWithinPolygon() |
||
636 | * @see http://docs.mongodb.org/manual/reference/operator/polygon/ |
||
637 | * |
||
638 | * @param array $point1 First point of the polygon |
||
639 | * @param array $point2 Second point of the polygon |
||
640 | * @param array $point3 Third point of the polygon |
||
641 | * @param array ...$points Additional points of the polygon |
||
642 | */ |
||
643 | 1 | public function geoWithinPolygon($point1, $point2, $point3, ...$points) : self |
|
644 | { |
||
645 | 1 | $this->expr->geoWithinPolygon(...func_get_args()); |
|
646 | 1 | return $this; |
|
647 | } |
||
648 | |||
649 | /** |
||
650 | * Return the expression's "new object". |
||
651 | * |
||
652 | * @see Expr::getNewObj() |
||
653 | */ |
||
654 | 13 | public function getNewObj() : array |
|
655 | { |
||
656 | 13 | return $this->expr->getNewObj(); |
|
657 | } |
||
658 | |||
659 | /** |
||
660 | * Gets the Query executable. |
||
661 | */ |
||
662 | 153 | public function getQuery(array $options = []) : Query |
|
663 | { |
||
664 | 153 | if ($this->query['type'] === Query::TYPE_MAP_REDUCE) { |
|
665 | $this->hydrate = false; |
||
666 | } |
||
667 | |||
668 | 153 | $documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name); |
|
669 | |||
670 | 153 | $query = $this->query; |
|
671 | |||
672 | 153 | $query['query'] = $this->expr->getQuery(); |
|
673 | 153 | $query['query'] = $documentPersister->addDiscriminatorToPreparedQuery($query['query']); |
|
674 | 153 | $query['query'] = $documentPersister->addFilterToPreparedQuery($query['query']); |
|
675 | |||
676 | 153 | $query['newObj'] = $this->expr->getNewObj(); |
|
677 | |||
678 | 153 | if (isset($query['distinct'])) { |
|
679 | 2 | $query['distinct'] = $documentPersister->prepareFieldName($query['distinct']); |
|
680 | } |
||
681 | |||
682 | 153 | if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION && ! empty($query['upsert']) && |
|
683 | 153 | (empty($query['query'][$this->class->discriminatorField]) || is_array($query['query'][$this->class->discriminatorField]))) { |
|
684 | 1 | throw new InvalidArgumentException('Upsert query that is to be performed on discriminated document does not have single ' . |
|
685 | 1 | 'discriminator. Either not use base class or set \'' . $this->class->discriminatorField . '\' field manually.'); |
|
686 | } |
||
687 | |||
688 | 152 | if (! empty($query['select'])) { |
|
689 | 14 | $query['select'] = $documentPersister->prepareProjection($query['select']); |
|
690 | 14 | if ($this->hydrate && $this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION |
|
691 | 14 | && ! isset($query['select'][$this->class->discriminatorField])) { |
|
692 | $includeMode = 0 < count(array_filter($query['select'], static function ($mode) { |
||
693 | 2 | return $mode === 1; |
|
694 | 2 | })); |
|
695 | 2 | if ($includeMode && ! isset($query['select'][$this->class->discriminatorField])) { |
|
696 | 1 | $query['select'][$this->class->discriminatorField] = 1; |
|
697 | } |
||
698 | } |
||
699 | } |
||
700 | |||
701 | 152 | if (isset($query['sort'])) { |
|
702 | 19 | $query['sort'] = $documentPersister->prepareSort($query['sort']); |
|
703 | } |
||
704 | |||
705 | 152 | if ($this->class->readPreference && ! array_key_exists('readPreference', $query)) { |
|
706 | 1 | $query['readPreference'] = new ReadPreference($this->class->readPreference, $this->class->readPreferenceTags); |
|
707 | } |
||
708 | |||
709 | 152 | return new Query( |
|
710 | 152 | $this->dm, |
|
711 | 152 | $this->class, |
|
712 | 152 | $this->collection, |
|
713 | 152 | $query, |
|
714 | 152 | $options, |
|
715 | 152 | $this->hydrate, |
|
716 | 152 | $this->refresh, |
|
717 | 152 | $this->primers, |
|
718 | 152 | $this->readOnly |
|
719 | ); |
||
720 | } |
||
721 | |||
722 | /** |
||
723 | * Return the expression's query criteria. |
||
724 | * |
||
725 | * @see Expr::getQuery() |
||
726 | */ |
||
727 | 33 | public function getQueryArray() : array |
|
728 | { |
||
729 | 33 | return $this->expr->getQuery(); |
|
730 | } |
||
731 | |||
732 | /** |
||
733 | * Get the type of this query. |
||
734 | */ |
||
735 | 2 | public function getType() : int |
|
736 | { |
||
737 | 2 | return $this->query['type']; |
|
738 | } |
||
739 | |||
740 | /** |
||
741 | * Specify $gt criteria for the current field. |
||
742 | * |
||
743 | * @see Expr::gt() |
||
744 | * @see http://docs.mongodb.org/manual/reference/operator/gt/ |
||
745 | * |
||
746 | * @param mixed $value |
||
747 | */ |
||
748 | 2 | public function gt($value) : self |
|
749 | { |
||
750 | 2 | $this->expr->gt($value); |
|
751 | 2 | return $this; |
|
752 | } |
||
753 | |||
754 | /** |
||
755 | * Specify $gte criteria for the current field. |
||
756 | * |
||
757 | * @see Expr::gte() |
||
758 | * @see http://docs.mongodb.org/manual/reference/operator/gte/ |
||
759 | * |
||
760 | * @param mixed $value |
||
761 | */ |
||
762 | 2 | public function gte($value) : self |
|
763 | { |
||
764 | 2 | $this->expr->gte($value); |
|
765 | 2 | return $this; |
|
766 | } |
||
767 | |||
768 | /** |
||
769 | * Set the index hint for the query. |
||
770 | * |
||
771 | * @param array|string $index |
||
772 | */ |
||
773 | public function hint($index) : self |
||
774 | { |
||
775 | $this->query['hint'] = $index; |
||
776 | return $this; |
||
777 | } |
||
778 | |||
779 | 17 | public function hydrate(bool $bool = true) : self |
|
780 | { |
||
781 | 17 | $this->hydrate = $bool; |
|
782 | 17 | return $this; |
|
783 | } |
||
784 | |||
785 | /** |
||
786 | * Set the immortal cursor flag. |
||
787 | */ |
||
788 | public function immortal(bool $bool = true) : self |
||
789 | { |
||
790 | $this->query['immortal'] = $bool; |
||
791 | return $this; |
||
792 | } |
||
793 | |||
794 | /** |
||
795 | * Specify $in criteria for the current field. |
||
796 | * |
||
797 | * @see Expr::in() |
||
798 | * @see http://docs.mongodb.org/manual/reference/operator/in/ |
||
799 | */ |
||
800 | 24 | public function in(array $values) : self |
|
801 | { |
||
802 | 24 | $this->expr->in($values); |
|
803 | 24 | return $this; |
|
804 | } |
||
805 | |||
806 | /** |
||
807 | * Increment the current field. |
||
808 | * |
||
809 | * If the field does not exist, it will be set to this value. |
||
810 | * |
||
811 | * @see Expr::inc() |
||
812 | * @see http://docs.mongodb.org/manual/reference/operator/inc/ |
||
813 | * |
||
814 | * @param float|int $value |
||
815 | */ |
||
816 | 6 | public function inc($value) : self |
|
817 | { |
||
818 | 6 | $this->expr->inc($value); |
|
819 | 6 | return $this; |
|
820 | } |
||
821 | |||
822 | 6 | public function includesReferenceTo(object $document) : self |
|
823 | { |
||
824 | 6 | $this->expr->includesReferenceTo($document); |
|
825 | 4 | return $this; |
|
826 | } |
||
827 | |||
828 | 1 | public function insert(?string $documentName = null) : self |
|
829 | { |
||
830 | 1 | $this->setDocumentName($documentName); |
|
831 | 1 | $this->query['type'] = Query::TYPE_INSERT; |
|
832 | |||
833 | 1 | return $this; |
|
834 | } |
||
835 | |||
836 | /** |
||
837 | * Set the $language option for $text criteria. |
||
838 | * |
||
839 | * This method must be called after text(). |
||
840 | * |
||
841 | * @see Expr::language() |
||
842 | * @see http://docs.mongodb.org/manual/reference/operator/text/ |
||
843 | */ |
||
844 | 1 | public function language(string $language) : self |
|
845 | { |
||
846 | 1 | $this->expr->language($language); |
|
847 | 1 | return $this; |
|
848 | } |
||
849 | |||
850 | /** |
||
851 | * Set the limit for the query. |
||
852 | * |
||
853 | * This is only relevant for find queries and geoNear and mapReduce |
||
854 | * commands. |
||
855 | * |
||
856 | * @see Query::prepareCursor() |
||
857 | */ |
||
858 | 2 | public function limit(int $limit) : self |
|
859 | { |
||
860 | 2 | $this->query['limit'] = $limit; |
|
861 | 2 | return $this; |
|
862 | } |
||
863 | |||
864 | /** |
||
865 | * Specify $lt criteria for the current field. |
||
866 | * |
||
867 | * @see Expr::lte() |
||
868 | * @see http://docs.mongodb.org/manual/reference/operator/lte/ |
||
869 | * |
||
870 | * @param mixed $value |
||
871 | */ |
||
872 | public function lt($value) : self |
||
873 | { |
||
874 | $this->expr->lt($value); |
||
875 | return $this; |
||
876 | } |
||
877 | |||
878 | /** |
||
879 | * Specify $lte criteria for the current field. |
||
880 | * |
||
881 | * @see Expr::lte() |
||
882 | * @see http://docs.mongodb.org/manual/reference/operator/lte/ |
||
883 | * |
||
884 | * @param mixed $value |
||
885 | */ |
||
886 | public function lte($value) : self |
||
887 | { |
||
888 | $this->expr->lte($value); |
||
889 | return $this; |
||
890 | } |
||
891 | |||
892 | /** |
||
893 | * Change the query type to a mapReduce command. |
||
894 | * |
||
895 | * The "reduce" option is not specified when calling this method; it must |
||
896 | * be set with the {@link Builder::reduce()} method. |
||
897 | * |
||
898 | * The "out" option defaults to inline, like {@link Builder::mapReduce()}. |
||
899 | * |
||
900 | * @see http://docs.mongodb.org/manual/reference/command/mapReduce/ |
||
901 | * |
||
902 | * @param string|Javascript $map |
||
903 | */ |
||
904 | 1 | public function map($map) : self |
|
905 | { |
||
906 | 1 | $this->query['type'] = Query::TYPE_MAP_REDUCE; |
|
907 | 1 | $this->query['mapReduce'] = [ |
|
908 | 1 | 'map' => $map, |
|
909 | 'reduce' => null, |
||
910 | 'out' => ['inline' => true], |
||
911 | 'options' => [], |
||
912 | ]; |
||
913 | 1 | return $this; |
|
914 | } |
||
915 | |||
916 | /** |
||
917 | * Change the query type to a mapReduce command. |
||
918 | * |
||
919 | * @see http://docs.mongodb.org/manual/reference/command/mapReduce/ |
||
920 | * |
||
921 | * @param string|Javascript $map |
||
922 | * @param string|Javascript $reduce |
||
923 | * @param array|string $out |
||
924 | * @param array $options |
||
925 | * |
||
926 | * @return $this |
||
927 | */ |
||
928 | 1 | public function mapReduce($map, $reduce, $out = ['inline' => true], array $options = []) : self |
|
929 | { |
||
930 | 1 | $this->query['type'] = Query::TYPE_MAP_REDUCE; |
|
931 | 1 | $this->query['mapReduce'] = [ |
|
932 | 1 | 'map' => $map, |
|
933 | 1 | 'reduce' => $reduce, |
|
934 | 1 | 'out' => $out, |
|
935 | 1 | 'options' => $options, |
|
936 | ]; |
||
937 | 1 | return $this; |
|
938 | } |
||
939 | |||
940 | /** |
||
941 | * Set additional options for a mapReduce command. |
||
942 | * |
||
943 | * @throws BadMethodCallException If the query is not a mapReduce command. |
||
944 | */ |
||
945 | 1 | public function mapReduceOptions(array $options) : self |
|
946 | { |
||
947 | 1 | if ($this->query['type'] !== Query::TYPE_MAP_REDUCE) { |
|
948 | 1 | throw new BadMethodCallException('This method requires a mapReduce command (call map() or mapReduce() first)'); |
|
949 | } |
||
950 | |||
951 | $this->query['mapReduce']['options'] = $options; |
||
952 | return $this; |
||
953 | } |
||
954 | |||
955 | /** |
||
956 | * Updates the value of the field to a specified value if the specified value is greater than the current value of the field. |
||
957 | * |
||
958 | * @see Expr::max() |
||
959 | * @see http://docs.mongodb.org/manual/reference/operator/update/max/ |
||
960 | * |
||
961 | * @param mixed $value |
||
962 | */ |
||
963 | 1 | public function max($value) : self |
|
964 | { |
||
965 | 1 | $this->expr->max($value); |
|
966 | 1 | return $this; |
|
967 | } |
||
968 | |||
969 | /** |
||
970 | * Specifies a cumulative time limit in milliseconds for processing operations on a cursor. |
||
971 | */ |
||
972 | public function maxTimeMS(int $ms) : self |
||
973 | { |
||
974 | $this->query['maxTimeMS'] = $ms; |
||
975 | return $this; |
||
976 | } |
||
977 | |||
978 | /** |
||
979 | * Updates the value of the field to a specified value if the specified value is less than the current value of the field. |
||
980 | * |
||
981 | * @see Expr::min() |
||
982 | * @see http://docs.mongodb.org/manual/reference/operator/update/min/ |
||
983 | * |
||
984 | * @param mixed $value |
||
985 | */ |
||
986 | 1 | public function min($value) : self |
|
987 | { |
||
988 | 1 | $this->expr->min($value); |
|
989 | 1 | return $this; |
|
990 | } |
||
991 | |||
992 | /** |
||
993 | * Specify $mod criteria for the current field. |
||
994 | * |
||
995 | * @see Expr::mod() |
||
996 | * @see http://docs.mongodb.org/manual/reference/operator/mod/ |
||
997 | * |
||
998 | * @param float|int $divisor |
||
999 | * @param float|int $remainder |
||
1000 | */ |
||
1001 | 1 | public function mod($divisor, $remainder = 0) : self |
|
1002 | { |
||
1003 | 1 | $this->expr->mod($divisor, $remainder); |
|
1004 | 1 | return $this; |
|
1005 | } |
||
1006 | |||
1007 | /** |
||
1008 | * Multiply the current field. |
||
1009 | * |
||
1010 | * If the field does not exist, it will be set to 0. |
||
1011 | * |
||
1012 | * @see Expr::mul() |
||
1013 | * @see http://docs.mongodb.org/manual/reference/operator/mul/ |
||
1014 | * |
||
1015 | * @param float|int $value |
||
1016 | */ |
||
1017 | 1 | public function mul($value) : self |
|
1018 | { |
||
1019 | 1 | $this->expr->mul($value); |
|
1020 | 1 | return $this; |
|
1021 | } |
||
1022 | |||
1023 | /** |
||
1024 | * Add $near criteria to the query. |
||
1025 | * |
||
1026 | * A GeoJSON point may be provided as the first and only argument for |
||
1027 | * 2dsphere queries. This single parameter may be a GeoJSON point object or |
||
1028 | * an array corresponding to the point's JSON representation. |
||
1029 | * |
||
1030 | * @see Expr::near() |
||
1031 | * @see http://docs.mongodb.org/manual/reference/operator/near/ |
||
1032 | * |
||
1033 | * @param float|array|Point $x |
||
1034 | * @param float $y |
||
1035 | */ |
||
1036 | 1 | public function near($x, $y = null) : self |
|
1037 | { |
||
1038 | 1 | $this->expr->near($x, $y); |
|
1039 | 1 | return $this; |
|
1040 | } |
||
1041 | |||
1042 | /** |
||
1043 | * Add $nearSphere criteria to the query. |
||
1044 | * |
||
1045 | * A GeoJSON point may be provided as the first and only argument for |
||
1046 | * 2dsphere queries. This single parameter may be a GeoJSON point object or |
||
1047 | * an array corresponding to the point's JSON representation. |
||
1048 | * |
||
1049 | * @see Expr::nearSphere() |
||
1050 | * @see http://docs.mongodb.org/manual/reference/operator/nearSphere/ |
||
1051 | * |
||
1052 | * @param float|array|Point $x |
||
1053 | * @param float $y |
||
1054 | */ |
||
1055 | 1 | public function nearSphere($x, $y = null) : self |
|
1056 | { |
||
1057 | 1 | $this->expr->nearSphere($x, $y); |
|
1058 | 1 | return $this; |
|
1059 | } |
||
1060 | |||
1061 | /** |
||
1062 | * Negates an expression for the current field. |
||
1063 | * |
||
1064 | * You can create a new expression using the {@link Builder::expr()} method. |
||
1065 | * |
||
1066 | * @see Expr::not() |
||
1067 | * @see http://docs.mongodb.org/manual/reference/operator/not/ |
||
1068 | * |
||
1069 | * @param array|Expr $expression |
||
1070 | */ |
||
1071 | 3 | public function not($expression) : self |
|
1072 | { |
||
1073 | 3 | $this->expr->not($expression); |
|
1074 | 3 | return $this; |
|
1075 | } |
||
1076 | |||
1077 | /** |
||
1078 | * Specify $ne criteria for the current field. |
||
1079 | * |
||
1080 | * @see Expr::notEqual() |
||
1081 | * @see http://docs.mongodb.org/manual/reference/operator/ne/ |
||
1082 | * |
||
1083 | * @param mixed $value |
||
1084 | */ |
||
1085 | 4 | public function notEqual($value) : self |
|
1086 | { |
||
1087 | 4 | $this->expr->notEqual($value); |
|
1088 | 4 | return $this; |
|
1089 | } |
||
1090 | |||
1091 | /** |
||
1092 | * Specify $nin criteria for the current field. |
||
1093 | * |
||
1094 | * @see Expr::notIn() |
||
1095 | * @see http://docs.mongodb.org/manual/reference/operator/nin/ |
||
1096 | * |
||
1097 | * @param array $values |
||
1098 | */ |
||
1099 | 4 | public function notIn(array $values) : self |
|
1100 | { |
||
1101 | 4 | $this->expr->notIn($values); |
|
1102 | 4 | return $this; |
|
1103 | } |
||
1104 | |||
1105 | /** |
||
1106 | * Set the "out" option for a mapReduce command. |
||
1107 | * |
||
1108 | * @param array|string $out |
||
1109 | * |
||
1110 | * @throws BadMethodCallException If the query is not a mapReduce command. |
||
1111 | */ |
||
1112 | 1 | public function out($out) : self |
|
1113 | { |
||
1114 | 1 | if ($this->query['type'] !== Query::TYPE_MAP_REDUCE) { |
|
1115 | 1 | throw new BadMethodCallException('This method requires a mapReduce command (call map() or mapReduce() first)'); |
|
1116 | } |
||
1117 | |||
1118 | $this->query['mapReduce']['out'] = $out; |
||
1119 | return $this; |
||
1120 | } |
||
1121 | |||
1122 | /** |
||
1123 | * Remove the first element from the current array field. |
||
1124 | * |
||
1125 | * @see Expr::popFirst() |
||
1126 | * @see http://docs.mongodb.org/manual/reference/operator/pop/ |
||
1127 | */ |
||
1128 | 3 | public function popFirst() : self |
|
1129 | { |
||
1130 | 3 | $this->expr->popFirst(); |
|
1131 | 3 | return $this; |
|
1132 | } |
||
1133 | |||
1134 | /** |
||
1135 | * Remove the last element from the current array field. |
||
1136 | * |
||
1137 | * @see Expr::popLast() |
||
1138 | * @see http://docs.mongodb.org/manual/reference/operator/pop/ |
||
1139 | */ |
||
1140 | 2 | public function popLast() : self |
|
1141 | { |
||
1142 | 2 | $this->expr->popLast(); |
|
1143 | 2 | return $this; |
|
1144 | } |
||
1145 | |||
1146 | /** |
||
1147 | * Use a primer to eagerly load all references in the current field. |
||
1148 | * |
||
1149 | * If $primer is true or a callable is provided, referenced documents for |
||
1150 | * this field will loaded into UnitOfWork immediately after the query is |
||
1151 | * executed. This will avoid multiple queries due to lazy initialization of |
||
1152 | * Proxy objects. |
||
1153 | * |
||
1154 | * If $primer is false, no priming will take place. That is also the default |
||
1155 | * behavior. |
||
1156 | * |
||
1157 | * If a custom callable is used, its signature should conform to the default |
||
1158 | * Closure defined in {@link ReferencePrimer::__construct()}. |
||
1159 | * |
||
1160 | * @param bool|callable $primer |
||
1161 | * |
||
1162 | * @throws InvalidArgumentException If $primer is not boolean or callable. |
||
1163 | */ |
||
1164 | 22 | public function prime($primer = true) : self |
|
1165 | { |
||
1166 | 22 | if (! is_bool($primer) && ! is_callable($primer)) { |
|
1167 | 1 | throw new InvalidArgumentException('$primer is not a boolean or callable'); |
|
1168 | } |
||
1169 | |||
1170 | 21 | if ($primer === false) { |
|
1171 | unset($this->primers[$this->currentField]); |
||
1172 | |||
1173 | return $this; |
||
1174 | } |
||
1175 | |||
1176 | 21 | $this->primers[$this->currentField] = $primer; |
|
1177 | 21 | return $this; |
|
1178 | } |
||
1179 | |||
1180 | /** |
||
1181 | * Remove all elements matching the given value or expression from the |
||
1182 | * current array field. |
||
1183 | * |
||
1184 | * @see Expr::pull() |
||
1185 | * @see http://docs.mongodb.org/manual/reference/operator/pull/ |
||
1186 | * |
||
1187 | * @param mixed|Expr $valueOrExpression |
||
1188 | */ |
||
1189 | 1 | public function pull($valueOrExpression) : self |
|
1190 | { |
||
1191 | 1 | $this->expr->pull($valueOrExpression); |
|
1192 | 1 | return $this; |
|
1193 | } |
||
1194 | |||
1195 | /** |
||
1196 | * Remove all elements matching any of the given values from the current |
||
1197 | * array field. |
||
1198 | * |
||
1199 | * @see Expr::pullAll() |
||
1200 | * @see http://docs.mongodb.org/manual/reference/operator/pullAll/ |
||
1201 | */ |
||
1202 | 1 | public function pullAll(array $values) : self |
|
1203 | { |
||
1204 | 1 | $this->expr->pullAll($values); |
|
1205 | 1 | return $this; |
|
1206 | } |
||
1207 | |||
1208 | /** |
||
1209 | * Append one or more values to the current array field. |
||
1210 | * |
||
1211 | * If the field does not exist, it will be set to an array containing the |
||
1212 | * value(s) in the argument. If the field is not an array, the query |
||
1213 | * will yield an error. |
||
1214 | * |
||
1215 | * Multiple values may be specified by providing an Expr object and using |
||
1216 | * {@link Expr::each()}. {@link Expr::slice()} and {@link Expr::sort()} may |
||
1217 | * also be used to limit and order array elements, respectively. |
||
1218 | * |
||
1219 | * @see Expr::push() |
||
1220 | * @see http://docs.mongodb.org/manual/reference/operator/push/ |
||
1221 | * @see http://docs.mongodb.org/manual/reference/operator/each/ |
||
1222 | * @see http://docs.mongodb.org/manual/reference/operator/slice/ |
||
1223 | * @see http://docs.mongodb.org/manual/reference/operator/sort/ |
||
1224 | * |
||
1225 | * @param mixed|Expr $valueOrExpression |
||
1226 | */ |
||
1227 | 6 | public function push($valueOrExpression) : self |
|
1228 | { |
||
1229 | 6 | $this->expr->push($valueOrExpression); |
|
1230 | 6 | return $this; |
|
1231 | } |
||
1232 | |||
1233 | /** |
||
1234 | * Specify $gte and $lt criteria for the current field. |
||
1235 | * |
||
1236 | * This method is shorthand for specifying $gte criteria on the lower bound |
||
1237 | * and $lt criteria on the upper bound. The upper bound is not inclusive. |
||
1238 | * |
||
1239 | * @see Expr::range() |
||
1240 | * |
||
1241 | * @param mixed $start |
||
1242 | * @param mixed $end |
||
1243 | */ |
||
1244 | 3 | public function range($start, $end) : self |
|
1245 | { |
||
1246 | 3 | $this->expr->range($start, $end); |
|
1247 | 3 | return $this; |
|
1248 | } |
||
1249 | |||
1250 | 2 | public function readOnly(bool $bool = true) : self |
|
1251 | { |
||
1252 | 2 | $this->readOnly = $bool; |
|
1253 | 2 | return $this; |
|
1254 | } |
||
1255 | |||
1256 | /** |
||
1257 | * Set the "reduce" option for a mapReduce or group command. |
||
1258 | * |
||
1259 | * @param string|Javascript $reduce |
||
1260 | * |
||
1261 | * @throws BadMethodCallException If the query is not a mapReduce or group command. |
||
1262 | */ |
||
1263 | 2 | public function reduce($reduce) : self |
|
1264 | { |
||
1265 | 2 | switch ($this->query['type']) { |
|
1266 | case Query::TYPE_MAP_REDUCE: |
||
1267 | 1 | $this->query['mapReduce']['reduce'] = $reduce; |
|
1268 | 1 | break; |
|
1269 | |||
1270 | case Query::TYPE_GROUP: |
||
1271 | $this->query['group']['reduce'] = $reduce; |
||
1272 | break; |
||
1273 | |||
1274 | default: |
||
1275 | 1 | throw new BadMethodCallException('mapReduce(), map() or group() must be called before reduce()'); |
|
1276 | } |
||
1277 | |||
1278 | 1 | return $this; |
|
1279 | } |
||
1280 | |||
1281 | 10 | public function references(object $document) : self |
|
1282 | { |
||
1283 | 10 | $this->expr->references($document); |
|
1284 | 8 | return $this; |
|
1285 | } |
||
1286 | |||
1287 | 5 | public function refresh(bool $bool = true) : self |
|
1288 | { |
||
1289 | 5 | $this->refresh = $bool; |
|
1290 | 5 | return $this; |
|
1291 | } |
||
1292 | |||
1293 | 1 | public function remove(?string $documentName = null) : self |
|
1294 | { |
||
1295 | 1 | $this->setDocumentName($documentName); |
|
1296 | 1 | $this->query['type'] = Query::TYPE_REMOVE; |
|
1297 | |||
1298 | 1 | return $this; |
|
1299 | } |
||
1300 | |||
1301 | /** |
||
1302 | * Rename the current field. |
||
1303 | * |
||
1304 | * @see Expr::rename() |
||
1305 | * @see http://docs.mongodb.org/manual/reference/operator/rename/ |
||
1306 | */ |
||
1307 | public function rename(string $name) : self |
||
1308 | { |
||
1309 | $this->expr->rename($name); |
||
1310 | return $this; |
||
1311 | } |
||
1312 | |||
1313 | 4 | public function returnNew(bool $bool = true) : self |
|
1314 | { |
||
1315 | 4 | $this->refresh(true); |
|
1316 | 4 | $this->query['new'] = $bool; |
|
1317 | |||
1318 | 4 | return $this; |
|
1319 | } |
||
1320 | |||
1321 | /** |
||
1322 | * Set one or more fields to be included in the query projection. |
||
1323 | * |
||
1324 | * @param array|string $fieldName,... |
||
1325 | */ |
||
1326 | 19 | public function select($fieldName = null) : self |
|
1327 | { |
||
1328 | 19 | if (! isset($this->query['select'])) { |
|
1329 | 18 | $this->query['select'] = []; |
|
1330 | } |
||
1331 | |||
1332 | 19 | $fieldNames = is_array($fieldName) ? $fieldName : func_get_args(); |
|
1333 | |||
1334 | 19 | foreach ($fieldNames as $fieldName) { |
|
1335 | 16 | $this->query['select'][$fieldName] = 1; |
|
1336 | } |
||
1337 | |||
1338 | 19 | return $this; |
|
1339 | } |
||
1340 | |||
1341 | /** |
||
1342 | * Select only matching embedded documents in an array field for the query |
||
1343 | * projection. |
||
1344 | * |
||
1345 | * @see http://docs.mongodb.org/manual/reference/projection/elemMatch/ |
||
1346 | * |
||
1347 | * @param array|Expr $expression |
||
1348 | */ |
||
1349 | 2 | public function selectElemMatch(string $fieldName, $expression) : self |
|
1350 | { |
||
1351 | 2 | if ($expression instanceof Expr) { |
|
1352 | 1 | $expression = $expression->getQuery(); |
|
1353 | } |
||
1354 | 2 | $this->query['select'][$fieldName] = ['$elemMatch' => $expression]; |
|
1355 | 2 | return $this; |
|
1356 | } |
||
1357 | |||
1358 | /** |
||
1359 | * Select a metadata field for the query projection. |
||
1360 | * |
||
1361 | * @see http://docs.mongodb.org/master/reference/operator/projection/meta/ |
||
1362 | */ |
||
1363 | 2 | public function selectMeta(string $fieldName, string $metaDataKeyword) : self |
|
1364 | { |
||
1365 | 2 | $this->query['select'][$fieldName] = ['$meta' => $metaDataKeyword]; |
|
1366 | 2 | return $this; |
|
1367 | } |
||
1368 | |||
1369 | /** |
||
1370 | * Select a slice of an array field for the query projection. |
||
1371 | * |
||
1372 | * The $countOrSkip parameter has two very different meanings, depending on |
||
1373 | * whether or not $limit is provided. See the MongoDB documentation for more |
||
1374 | * information. |
||
1375 | * |
||
1376 | * @see http://docs.mongodb.org/manual/reference/projection/slice/ |
||
1377 | */ |
||
1378 | 3 | public function selectSlice(string $fieldName, int $countOrSkip, ?int $limit = null) : self |
|
1379 | { |
||
1380 | 3 | $slice = $countOrSkip; |
|
1381 | 3 | if ($limit !== null) { |
|
1382 | 2 | $slice = [$slice, $limit]; |
|
1383 | } |
||
1384 | 3 | $this->query['select'][$fieldName] = ['$slice' => $slice]; |
|
1385 | 3 | return $this; |
|
1386 | } |
||
1387 | |||
1388 | /** |
||
1389 | * Set the current field to a value. |
||
1390 | * |
||
1391 | * This is only relevant for insert, update, or findAndUpdate queries. For |
||
1392 | * update and findAndUpdate queries, the $atomic parameter will determine |
||
1393 | * whether or not a $set operator is used. |
||
1394 | * |
||
1395 | * @see Expr::set() |
||
1396 | * @see http://docs.mongodb.org/manual/reference/operator/set/ |
||
1397 | * |
||
1398 | * @param mixed $value |
||
1399 | */ |
||
1400 | 16 | public function set($value, bool $atomic = true) : self |
|
1401 | { |
||
1402 | 16 | $this->expr->set($value, $atomic && $this->query['type'] !== Query::TYPE_INSERT); |
|
1403 | 16 | return $this; |
|
1404 | } |
||
1405 | |||
1406 | /** |
||
1407 | * Set the expression's "new object". |
||
1408 | * |
||
1409 | * @see Expr::setNewObj() |
||
1410 | */ |
||
1411 | public function setNewObj(array $newObj) : self |
||
1412 | { |
||
1413 | $this->expr->setNewObj($newObj); |
||
1414 | return $this; |
||
1415 | } |
||
1416 | |||
1417 | /** |
||
1418 | * Set the current field to the value if the document is inserted in an |
||
1419 | * upsert operation. |
||
1420 | * |
||
1421 | * If an update operation with upsert: true results in an insert of a |
||
1422 | * document, then $setOnInsert assigns the specified values to the fields in |
||
1423 | * the document. If the update operation does not result in an insert, |
||
1424 | * $setOnInsert does nothing. |
||
1425 | * |
||
1426 | * @see Expr::setOnInsert() |
||
1427 | * @see https://docs.mongodb.org/manual/reference/operator/update/setOnInsert/ |
||
1428 | * |
||
1429 | * @param mixed $value |
||
1430 | */ |
||
1431 | 2 | public function setOnInsert($value) : self |
|
1432 | { |
||
1433 | 2 | $this->expr->setOnInsert($value); |
|
1434 | 2 | return $this; |
|
1435 | } |
||
1436 | |||
1437 | /** |
||
1438 | * Set the read preference for the query. |
||
1439 | * |
||
1440 | * This is only relevant for read-only queries and commands. |
||
1441 | * |
||
1442 | * @see http://docs.mongodb.org/manual/core/read-preference/ |
||
1443 | */ |
||
1444 | 6 | public function setReadPreference(ReadPreference $readPreference) : self |
|
1445 | { |
||
1446 | 6 | $this->query['readPreference'] = $readPreference; |
|
1447 | 6 | return $this; |
|
1448 | } |
||
1449 | |||
1450 | /** |
||
1451 | * Set the expression's query criteria. |
||
1452 | * |
||
1453 | * @see Expr::setQuery() |
||
1454 | */ |
||
1455 | 18 | public function setQueryArray(array $query) : self |
|
1456 | { |
||
1457 | 18 | $this->expr->setQuery($query); |
|
1458 | 18 | return $this; |
|
1459 | } |
||
1460 | |||
1461 | /** |
||
1462 | * Specify $size criteria for the current field. |
||
1463 | * |
||
1464 | * @see Expr::size() |
||
1465 | * @see http://docs.mongodb.org/manual/reference/operator/size/ |
||
1466 | */ |
||
1467 | 1 | public function size(int $size) : self |
|
1468 | { |
||
1469 | 1 | $this->expr->size($size); |
|
1470 | 1 | return $this; |
|
1471 | } |
||
1472 | |||
1473 | /** |
||
1474 | * Set the skip for the query cursor. |
||
1475 | * |
||
1476 | * This is only relevant for find queries, or mapReduce queries that store |
||
1477 | * results in an output collection and return a cursor. |
||
1478 | * |
||
1479 | * @see Query::prepareCursor() |
||
1480 | */ |
||
1481 | public function skip(int $skip) : self |
||
1482 | { |
||
1483 | $this->query['skip'] = $skip; |
||
1484 | return $this; |
||
1485 | } |
||
1486 | |||
1487 | /** |
||
1488 | * Set the snapshot cursor flag. |
||
1489 | */ |
||
1490 | public function snapshot(bool $bool = true) : self |
||
1491 | { |
||
1492 | $this->query['snapshot'] = $bool; |
||
1493 | return $this; |
||
1494 | } |
||
1495 | |||
1496 | /** |
||
1497 | * Set one or more field/order pairs on which to sort the query. |
||
1498 | * |
||
1499 | * If sorting by multiple fields, the first argument should be an array of |
||
1500 | * field name (key) and order (value) pairs. |
||
1501 | * |
||
1502 | * @param array|string $fieldName Field name or array of field/order pairs |
||
1503 | * @param int|string $order Field order (if one field is specified) |
||
1504 | */ |
||
1505 | 27 | public function sort($fieldName, $order = 1) : self |
|
1506 | { |
||
1507 | 27 | if (! isset($this->query['sort'])) { |
|
1508 | 27 | $this->query['sort'] = []; |
|
1509 | } |
||
1510 | |||
1511 | 27 | $fields = is_array($fieldName) ? $fieldName : [$fieldName => $order]; |
|
1512 | |||
1513 | 27 | foreach ($fields as $fieldName => $order) { |
|
1514 | 14 | if (is_string($order)) { |
|
1515 | 9 | $order = strtolower($order) === 'asc' ? 1 : -1; |
|
1516 | } |
||
1517 | 14 | $this->query['sort'][$fieldName] = (int) $order; |
|
1518 | } |
||
1519 | |||
1520 | 27 | return $this; |
|
1521 | } |
||
1522 | |||
1523 | /** |
||
1524 | * Specify a projected metadata field on which to sort the query. |
||
1525 | * |
||
1526 | * Sort order is not configurable for metadata fields. Sorting by a metadata |
||
1527 | * field requires the same field and $meta expression to exist in the |
||
1528 | * projection document. This method will call {@link Builder::selectMeta()} |
||
1529 | * if the field is not already set in the projection. |
||
1530 | * |
||
1531 | * @see http://docs.mongodb.org/master/reference/operator/projection/meta/#sort |
||
1532 | */ |
||
1533 | 2 | public function sortMeta(string $fieldName, string $metaDataKeyword) : self |
|
1534 | { |
||
1535 | /* It's possible that the field is already projected without the $meta |
||
1536 | * operator. We'll assume that the user knows what they're doing in that |
||
1537 | * case and will not attempt to override the projection. |
||
1538 | */ |
||
1539 | 2 | if (! isset($this->query['select'][$fieldName])) { |
|
1540 | 1 | $this->selectMeta($fieldName, $metaDataKeyword); |
|
1541 | } |
||
1542 | |||
1543 | 2 | $this->query['sort'][$fieldName] = ['$meta' => $metaDataKeyword]; |
|
1544 | |||
1545 | 2 | return $this; |
|
1546 | } |
||
1547 | |||
1548 | /** |
||
1549 | * Specify $text criteria for the current field. |
||
1550 | * |
||
1551 | * The $language option may be set with {@link Builder::language()}. |
||
1552 | * |
||
1553 | * @see Expr::text() |
||
1554 | * @see http://docs.mongodb.org/master/reference/operator/query/text/ |
||
1555 | */ |
||
1556 | 1 | public function text(string $search) : self |
|
1557 | { |
||
1558 | 1 | $this->expr->text($search); |
|
1559 | 1 | return $this; |
|
1560 | } |
||
1561 | |||
1562 | /** |
||
1563 | * Specify $type criteria for the current field. |
||
1564 | * |
||
1565 | * @see Expr::type() |
||
1566 | * @see http://docs.mongodb.org/manual/reference/operator/type/ |
||
1567 | * |
||
1568 | * @param int|string $type |
||
1569 | */ |
||
1570 | 2 | public function type($type) : self |
|
1571 | { |
||
1572 | 2 | $this->expr->type($type); |
|
1573 | 2 | return $this; |
|
1574 | } |
||
1575 | |||
1576 | /** |
||
1577 | * Unset the current field. |
||
1578 | * |
||
1579 | * The field will be removed from the document (not set to null). |
||
1580 | * |
||
1581 | * @see Expr::unsetField() |
||
1582 | * @see http://docs.mongodb.org/manual/reference/operator/unset/ |
||
1583 | */ |
||
1584 | 4 | public function unsetField() : self |
|
1585 | { |
||
1586 | 4 | $this->expr->unsetField(); |
|
1587 | 4 | return $this; |
|
1588 | } |
||
1589 | |||
1590 | 23 | public function updateOne(?string $documentName = null) : self |
|
1591 | { |
||
1592 | 23 | $this->setDocumentName($documentName); |
|
1593 | 23 | $this->query['type'] = Query::TYPE_UPDATE; |
|
1594 | 23 | $this->query['multiple'] = false; |
|
1595 | |||
1596 | 23 | return $this; |
|
1597 | } |
||
1598 | |||
1599 | 3 | public function updateMany(?string $documentName = null) : self |
|
1600 | { |
||
1601 | 3 | $this->setDocumentName($documentName); |
|
1602 | 3 | $this->query['type'] = Query::TYPE_UPDATE; |
|
1603 | 3 | $this->query['multiple'] = true; |
|
1604 | |||
1605 | 3 | return $this; |
|
1606 | } |
||
1607 | |||
1608 | /** |
||
1609 | * Set the "upsert" option for an update or findAndUpdate query. |
||
1610 | */ |
||
1611 | 7 | public function upsert(bool $bool = true) : self |
|
1612 | { |
||
1613 | 7 | $this->query['upsert'] = $bool; |
|
1614 | 7 | return $this; |
|
1615 | } |
||
1616 | |||
1617 | /** |
||
1618 | * Specify a JavaScript expression to use for matching documents. |
||
1619 | * |
||
1620 | * @see Expr::where() |
||
1621 | * @see http://docs.mongodb.org/manual/reference/operator/where/ |
||
1622 | * |
||
1623 | * @param string|Javascript $javascript |
||
1624 | */ |
||
1625 | 3 | public function where($javascript) : self |
|
1626 | { |
||
1627 | 3 | $this->expr->where($javascript); |
|
1628 | 3 | return $this; |
|
1629 | } |
||
1630 | |||
1631 | /** |
||
1632 | * Get Discriminator Values |
||
1633 | * |
||
1634 | * @param string[] $classNames |
||
1635 | * |
||
1636 | * @throws InvalidArgumentException If the number of found collections > 1. |
||
1637 | */ |
||
1638 | 2 | private function getDiscriminatorValues($classNames) : array |
|
1639 | { |
||
1640 | 2 | $discriminatorValues = []; |
|
1641 | 2 | $collections = []; |
|
1642 | 2 | foreach ($classNames as $className) { |
|
1643 | 2 | $class = $this->dm->getClassMetadata($className); |
|
1644 | 2 | $discriminatorValues[] = $class->discriminatorValue; |
|
0 ignored issues
–
show
|
|||
1645 | 2 | $key = $this->dm->getDocumentDatabase($className)->getDatabaseName() . '.' . $class->getCollection(); |
|
1646 | 2 | $collections[$key] = $key; |
|
1647 | } |
||
1648 | 2 | if (count($collections) > 1) { |
|
1649 | 1 | throw new InvalidArgumentException('Documents involved are not all mapped to the same database collection.'); |
|
1650 | } |
||
1651 | 1 | return $discriminatorValues; |
|
1652 | } |
||
1653 | |||
1654 | /** |
||
1655 | * @param string[]|string|null $documentName an array of document names or just one. |
||
1656 | */ |
||
1657 | 285 | private function setDocumentName($documentName) |
|
1658 | { |
||
1659 | 285 | if (is_array($documentName)) { |
|
1660 | 2 | $documentNames = $documentName; |
|
1661 | 2 | $documentName = $documentNames[0]; |
|
1662 | |||
1663 | 2 | $metadata = $this->dm->getClassMetadata($documentName); |
|
1664 | 2 | $discriminatorField = $metadata->discriminatorField ?? ClassMetadata::DEFAULT_DISCRIMINATOR_FIELD; |
|
0 ignored issues
–
show
Accessing
discriminatorField on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
|
|||
1665 | 2 | $discriminatorValues = $this->getDiscriminatorValues($documentNames); |
|
1666 | |||
1667 | // If a defaultDiscriminatorValue is set and it is among the discriminators being queries, add NULL to the list |
||
1668 | 1 | if ($metadata->defaultDiscriminatorValue && in_array($metadata->defaultDiscriminatorValue, $discriminatorValues)) { |
|
0 ignored issues
–
show
Accessing
defaultDiscriminatorValue on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
|
|||
1669 | 1 | $discriminatorValues[] = null; |
|
1670 | } |
||
1671 | |||
1672 | 1 | $this->field($discriminatorField)->in($discriminatorValues); |
|
1673 | } |
||
1674 | |||
1675 | 284 | if ($documentName === null) { |
|
1676 | 41 | return; |
|
1677 | } |
||
1678 | |||
1679 | 284 | $this->collection = $this->dm->getDocumentCollection($documentName); |
|
1680 | 284 | $this->class = $this->dm->getClassMetadata($documentName); |
|
1681 | |||
1682 | // Expr also needs to know |
||
1683 | 284 | $this->expr->setClassMetadata($this->class); |
|
0 ignored issues
–
show
$this->class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata> . It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
1684 | 284 | } |
|
1685 | } |
||
1686 |
If you access a property on an interface, you most likely code against a concrete implementation of the interface.
Available Fixes
Adding an additional type check:
Changing the type hint: