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 Doctrine\ODM\MongoDB\Mapping\MappingException; |
||
11 | use GeoJson\Geometry\Geometry; |
||
12 | use GeoJson\Geometry\Point; |
||
13 | use InvalidArgumentException; |
||
14 | use LogicException; |
||
15 | use MongoDB\BSON\Binary; |
||
16 | use MongoDB\BSON\Javascript; |
||
17 | use function array_key_exists; |
||
18 | use function array_map; |
||
19 | use function array_merge; |
||
20 | use function array_values; |
||
21 | use function assert; |
||
22 | use function explode; |
||
23 | use function func_get_args; |
||
24 | use function in_array; |
||
25 | use function is_array; |
||
26 | use function is_string; |
||
27 | use function key; |
||
28 | use function sprintf; |
||
29 | use function strpos; |
||
30 | use function strtolower; |
||
31 | |||
32 | /** |
||
33 | * Query expression builder for ODM. |
||
34 | */ |
||
35 | class Expr |
||
36 | { |
||
37 | /** |
||
38 | * The query criteria array. |
||
39 | * |
||
40 | * @var array |
||
41 | */ |
||
42 | private $query = []; |
||
43 | |||
44 | /** |
||
45 | * The "new object" array containing either a full document or a number of |
||
46 | * atomic update operators. |
||
47 | * |
||
48 | * @see docs.mongodb.org/manual/reference/method/db.collection.update/#update-parameter |
||
49 | * |
||
50 | * @var array |
||
51 | */ |
||
52 | private $newObj = []; |
||
53 | |||
54 | /** |
||
55 | * The current field we are operating on. |
||
56 | * |
||
57 | * @var string|null |
||
58 | */ |
||
59 | private $currentField; |
||
60 | |||
61 | /** |
||
62 | * The DocumentManager instance for this query |
||
63 | * |
||
64 | * @var DocumentManager |
||
65 | */ |
||
66 | private $dm; |
||
67 | |||
68 | /** |
||
69 | * The ClassMetadata instance for the document being queried |
||
70 | * |
||
71 | * @var ClassMetadata |
||
72 | */ |
||
73 | private $class; |
||
74 | |||
75 | 392 | public function __construct(DocumentManager $dm) |
|
76 | { |
||
77 | 392 | $this->dm = $dm; |
|
78 | 392 | } |
|
79 | |||
80 | /** |
||
81 | * Add one or more $and clauses to the current query. |
||
82 | * |
||
83 | * @see Builder::addAnd() |
||
84 | * @see http://docs.mongodb.org/manual/reference/operator/and/ |
||
85 | * |
||
86 | * @param array|Expr $expression |
||
87 | * @param array|Expr ...$expressions |
||
88 | */ |
||
89 | 3 | public function addAnd($expression, ...$expressions) : self |
|
90 | { |
||
91 | 3 | if (! isset($this->query['$and'])) { |
|
92 | 3 | $this->query['$and'] = []; |
|
93 | } |
||
94 | |||
95 | 3 | $this->query['$and'] = array_merge( |
|
96 | 3 | $this->query['$and'], |
|
97 | 3 | array_map( |
|
98 | static function ($expression) { |
||
99 | 3 | return $expression instanceof Expr ? $expression->getQuery() : $expression; |
|
100 | 3 | }, |
|
101 | 3 | func_get_args() |
|
102 | ) |
||
103 | ); |
||
104 | |||
105 | 3 | return $this; |
|
106 | } |
||
107 | |||
108 | /** |
||
109 | * Add one or more $nor clauses to the current query. |
||
110 | * |
||
111 | * @see Builder::addNor() |
||
112 | * @see http://docs.mongodb.org/manual/reference/operator/nor/ |
||
113 | * |
||
114 | * @param array|Expr $expression |
||
115 | * @param array|Expr ...$expressions |
||
116 | */ |
||
117 | 1 | public function addNor($expression, ...$expressions) : self |
|
118 | { |
||
119 | 1 | if (! isset($this->query['$nor'])) { |
|
120 | 1 | $this->query['$nor'] = []; |
|
121 | } |
||
122 | |||
123 | 1 | $this->query['$nor'] = array_merge( |
|
124 | 1 | $this->query['$nor'], |
|
125 | array_map(static function ($expression) { |
||
126 | 1 | return $expression instanceof Expr ? $expression->getQuery() : $expression; |
|
127 | 1 | }, func_get_args()) |
|
128 | ); |
||
129 | |||
130 | 1 | return $this; |
|
131 | } |
||
132 | |||
133 | /** |
||
134 | * Add one or more $or clauses to the current query. |
||
135 | * |
||
136 | * @see Builder::addOr() |
||
137 | * @see http://docs.mongodb.org/manual/reference/operator/or/ |
||
138 | * |
||
139 | * @param array|Expr $expression |
||
140 | * @param array|Expr ...$expressions |
||
141 | */ |
||
142 | 5 | public function addOr($expression, ...$expressions) : self |
|
143 | { |
||
144 | 5 | if (! isset($this->query['$or'])) { |
|
145 | 5 | $this->query['$or'] = []; |
|
146 | } |
||
147 | |||
148 | 5 | $this->query['$or'] = array_merge( |
|
149 | 5 | $this->query['$or'], |
|
150 | array_map(static function ($expression) { |
||
151 | 5 | return $expression instanceof Expr ? $expression->getQuery() : $expression; |
|
152 | 5 | }, func_get_args()) |
|
153 | ); |
||
154 | |||
155 | 5 | return $this; |
|
156 | } |
||
157 | |||
158 | /** |
||
159 | * Append one or more values to the current array field only if they do not |
||
160 | * already exist in the array. |
||
161 | * |
||
162 | * If the field does not exist, it will be set to an array containing the |
||
163 | * unique value(s) in the argument. If the field is not an array, the query |
||
164 | * will yield an error. |
||
165 | * |
||
166 | * Multiple values may be specified by provided an Expr object and using |
||
167 | * {@link Expr::each()}. |
||
168 | * |
||
169 | * @see Builder::addToSet() |
||
170 | * @see http://docs.mongodb.org/manual/reference/operator/addToSet/ |
||
171 | * @see http://docs.mongodb.org/manual/reference/operator/each/ |
||
172 | * |
||
173 | * @param mixed|Expr $valueOrExpression |
||
174 | */ |
||
175 | 5 | public function addToSet($valueOrExpression) : self |
|
176 | { |
||
177 | 5 | if ($valueOrExpression instanceof Expr) { |
|
178 | 1 | $valueOrExpression = $valueOrExpression->getQuery(); |
|
179 | } |
||
180 | |||
181 | 5 | $this->requiresCurrentField(); |
|
182 | 5 | $this->newObj['$addToSet'][$this->currentField] = $valueOrExpression; |
|
183 | 5 | return $this; |
|
184 | } |
||
185 | |||
186 | /** |
||
187 | * Specify $all criteria for the current field. |
||
188 | * |
||
189 | * @see Builder::all() |
||
190 | * @see http://docs.mongodb.org/manual/reference/operator/all/ |
||
191 | */ |
||
192 | 2 | public function all(array $values) : self |
|
193 | { |
||
194 | 2 | return $this->operator('$all', $values); |
|
195 | } |
||
196 | |||
197 | /** |
||
198 | * Apply a bitwise operation on the current field |
||
199 | * |
||
200 | * @see http://docs.mongodb.org/manual/reference/operator/update/bit/ |
||
201 | */ |
||
202 | 3 | protected function bit(string $operator, int $value) : self |
|
203 | { |
||
204 | 3 | $this->requiresCurrentField(); |
|
205 | 3 | $this->newObj['$bit'][$this->currentField][$operator] = $value; |
|
206 | 3 | return $this; |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * Apply a bitwise and operation on the current field. |
||
211 | * |
||
212 | * @see Builder::bitAnd() |
||
213 | * @see http://docs.mongodb.org/manual/reference/operator/update/bit/ |
||
214 | */ |
||
215 | 1 | public function bitAnd(int $value) : self |
|
216 | { |
||
217 | 1 | return $this->bit('and', $value); |
|
218 | } |
||
219 | |||
220 | /** |
||
221 | * Apply a bitwise or operation on the current field. |
||
222 | * |
||
223 | * @see Builder::bitOr() |
||
224 | * @see http://docs.mongodb.org/manual/reference/operator/update/bit/ |
||
225 | */ |
||
226 | 1 | public function bitOr(int $value) : self |
|
227 | { |
||
228 | 1 | return $this->bit('or', $value); |
|
229 | } |
||
230 | |||
231 | /** |
||
232 | * Matches documents where all of the bit positions given by the query are |
||
233 | * clear. |
||
234 | * |
||
235 | * @see Builder::bitsAllClear() |
||
236 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllClear/ |
||
237 | * |
||
238 | * @param int|array|Binary $value |
||
239 | */ |
||
240 | public function bitsAllClear($value) : self |
||
241 | { |
||
242 | $this->requiresCurrentField(); |
||
243 | return $this->operator('$bitsAllClear', $value); |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Matches documents where all of the bit positions given by the query are |
||
248 | * set. |
||
249 | * |
||
250 | * @see Builder::bitsAllSet() |
||
251 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAllSet/ |
||
252 | * |
||
253 | * @param int|array|Binary $value |
||
254 | */ |
||
255 | public function bitsAllSet($value) : self |
||
256 | { |
||
257 | $this->requiresCurrentField(); |
||
258 | return $this->operator('$bitsAllSet', $value); |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Matches documents where any of the bit positions given by the query are |
||
263 | * clear. |
||
264 | * |
||
265 | * @see Builder::bitsAnyClear() |
||
266 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnyClear/ |
||
267 | * |
||
268 | * @param int|array|Binary $value |
||
269 | */ |
||
270 | public function bitsAnyClear($value) : self |
||
271 | { |
||
272 | $this->requiresCurrentField(); |
||
273 | return $this->operator('$bitsAnyClear', $value); |
||
274 | } |
||
275 | |||
276 | /** |
||
277 | * Matches documents where any of the bit positions given by the query are |
||
278 | * set. |
||
279 | * |
||
280 | * @see Builder::bitsAnySet() |
||
281 | * @see https://docs.mongodb.org/manual/reference/operator/query/bitsAnySet/ |
||
282 | * |
||
283 | * @param int|array|Binary $value |
||
284 | */ |
||
285 | public function bitsAnySet($value) : self |
||
286 | { |
||
287 | $this->requiresCurrentField(); |
||
288 | return $this->operator('$bitsAnySet', $value); |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Apply a bitwise xor operation on the current field. |
||
293 | * |
||
294 | * @see Builder::bitXor() |
||
295 | * @see http://docs.mongodb.org/manual/reference/operator/update/bit/ |
||
296 | */ |
||
297 | 1 | public function bitXor(int $value) : self |
|
298 | { |
||
299 | 1 | return $this->bit('xor', $value); |
|
300 | } |
||
301 | |||
302 | /** |
||
303 | * A boolean flag to enable or disable case sensitive search for $text |
||
304 | * criteria. |
||
305 | * |
||
306 | * This method must be called after text(). |
||
307 | * |
||
308 | * @see Builder::caseSensitive() |
||
309 | * @see http://docs.mongodb.org/manual/reference/operator/text/ |
||
310 | * |
||
311 | * @throws BadMethodCallException If the query does not already have $text criteria. |
||
312 | */ |
||
313 | 3 | public function caseSensitive(bool $caseSensitive) : self |
|
314 | { |
||
315 | 3 | if (! isset($this->query['$text'])) { |
|
316 | 1 | throw new BadMethodCallException('This method requires a $text operator (call text() first)'); |
|
317 | } |
||
318 | |||
319 | // Remove caseSensitive option to keep support for older database versions |
||
320 | 2 | if ($caseSensitive) { |
|
321 | 2 | $this->query['$text']['$caseSensitive'] = true; |
|
322 | 1 | } elseif (isset($this->query['$text']['$caseSensitive'])) { |
|
323 | 1 | unset($this->query['$text']['$caseSensitive']); |
|
324 | } |
||
325 | |||
326 | 2 | return $this; |
|
327 | } |
||
328 | |||
329 | /** |
||
330 | * Associates a comment to any expression taking a query predicate. |
||
331 | * |
||
332 | * @see Builder::comment() |
||
333 | * @see http://docs.mongodb.org/manual/reference/operator/query/comment/ |
||
334 | */ |
||
335 | public function comment(string $comment) : self |
||
336 | { |
||
337 | $this->query['$comment'] = $comment; |
||
338 | return $this; |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Sets the value of the current field to the current date, either as a date or a timestamp. |
||
343 | * |
||
344 | * @see Builder::currentDate() |
||
345 | * @see http://docs.mongodb.org/manual/reference/operator/update/currentDate/ |
||
346 | * |
||
347 | * @throws InvalidArgumentException If an invalid type is given. |
||
348 | */ |
||
349 | 3 | public function currentDate(string $type = 'date') : self |
|
350 | { |
||
351 | 3 | if (! in_array($type, ['date', 'timestamp'])) { |
|
352 | 1 | throw new InvalidArgumentException('Type for currentDate operator must be date or timestamp.'); |
|
353 | } |
||
354 | |||
355 | 2 | $this->requiresCurrentField(); |
|
356 | 2 | $this->newObj['$currentDate'][$this->currentField]['$type'] = $type; |
|
357 | 2 | return $this; |
|
358 | } |
||
359 | |||
360 | /** |
||
361 | * A boolean flag to enable or disable diacritic sensitive search for $text |
||
362 | * criteria. |
||
363 | * |
||
364 | * This method must be called after text(). |
||
365 | * |
||
366 | * @see Builder::diacriticSensitive() |
||
367 | * @see http://docs.mongodb.org/manual/reference/operator/text/ |
||
368 | * |
||
369 | * @throws BadMethodCallException If the query does not already have $text criteria. |
||
370 | */ |
||
371 | 3 | public function diacriticSensitive(bool $diacriticSensitive) : self |
|
372 | { |
||
373 | 3 | if (! isset($this->query['$text'])) { |
|
374 | 1 | throw new BadMethodCallException('This method requires a $text operator (call text() first)'); |
|
375 | } |
||
376 | |||
377 | // Remove diacriticSensitive option to keep support for older database versions |
||
378 | 2 | if ($diacriticSensitive) { |
|
379 | 2 | $this->query['$text']['$diacriticSensitive'] = true; |
|
380 | 1 | } elseif (isset($this->query['$text']['$diacriticSensitive'])) { |
|
381 | 1 | unset($this->query['$text']['$diacriticSensitive']); |
|
382 | } |
||
383 | |||
384 | 2 | return $this; |
|
385 | } |
||
386 | |||
387 | /** |
||
388 | * Add $each criteria to the expression for a $push operation. |
||
389 | * |
||
390 | * @see Expr::push() |
||
391 | * @see http://docs.mongodb.org/manual/reference/operator/each/ |
||
392 | */ |
||
393 | 4 | public function each(array $values) : self |
|
394 | { |
||
395 | 4 | return $this->operator('$each', $values); |
|
396 | } |
||
397 | |||
398 | /** |
||
399 | * Specify $elemMatch criteria for the current field. |
||
400 | * |
||
401 | * @see Builder::elemMatch() |
||
402 | * @see http://docs.mongodb.org/manual/reference/operator/elemMatch/ |
||
403 | * |
||
404 | * @param array|Expr $expression |
||
405 | */ |
||
406 | 4 | public function elemMatch($expression) : self |
|
407 | { |
||
408 | 4 | return $this->operator('$elemMatch', $expression instanceof Expr ? $expression->getQuery() : $expression); |
|
409 | } |
||
410 | |||
411 | /** |
||
412 | * Specify an equality match for the current field. |
||
413 | * |
||
414 | * @see Builder::equals() |
||
415 | * |
||
416 | * @param mixed $value |
||
417 | */ |
||
418 | 104 | public function equals($value) : self |
|
419 | { |
||
420 | 104 | if ($this->currentField) { |
|
421 | 103 | $this->query[$this->currentField] = $value; |
|
422 | } else { |
||
423 | 1 | $this->query = $value; |
|
424 | } |
||
425 | 104 | return $this; |
|
426 | } |
||
427 | |||
428 | /** |
||
429 | * Specify $exists criteria for the current field. |
||
430 | * |
||
431 | * @see Builder::exists() |
||
432 | * @see http://docs.mongodb.org/manual/reference/operator/exists/ |
||
433 | */ |
||
434 | 5 | public function exists(bool $bool) : self |
|
435 | { |
||
436 | 5 | return $this->operator('$exists', $bool); |
|
437 | } |
||
438 | |||
439 | /** |
||
440 | * Set the current field for building the expression. |
||
441 | * |
||
442 | * @see Builder::field() |
||
443 | */ |
||
444 | 192 | public function field(string $field) : self |
|
445 | { |
||
446 | 192 | $this->currentField = $field; |
|
447 | 192 | return $this; |
|
448 | } |
||
449 | |||
450 | /** |
||
451 | * Add $geoIntersects criteria with a GeoJSON geometry to the expression. |
||
452 | * |
||
453 | * The geometry parameter GeoJSON object or an array corresponding to the |
||
454 | * geometry's JSON representation. |
||
455 | * |
||
456 | * @see Builder::geoIntersects() |
||
457 | * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/ |
||
458 | * |
||
459 | * @param array|Geometry $geometry |
||
460 | */ |
||
461 | 2 | public function geoIntersects($geometry) : self |
|
462 | { |
||
463 | 2 | if ($geometry instanceof Geometry) { |
|
0 ignored issues
–
show
|
|||
464 | 1 | $geometry = $geometry->jsonSerialize(); |
|
465 | } |
||
466 | |||
467 | 2 | return $this->operator('$geoIntersects', ['$geometry' => $geometry]); |
|
468 | } |
||
469 | |||
470 | /** |
||
471 | * Add $geoWithin criteria with a GeoJSON geometry to the expression. |
||
472 | * |
||
473 | * The geometry parameter GeoJSON object or an array corresponding to the |
||
474 | * geometry's JSON representation. |
||
475 | * |
||
476 | * @see Builder::geoWithin() |
||
477 | * @see http://docs.mongodb.org/manual/reference/operator/geoIntersects/ |
||
478 | * |
||
479 | * @param array|Geometry $geometry |
||
480 | */ |
||
481 | 2 | public function geoWithin($geometry) : self |
|
482 | { |
||
483 | 2 | if ($geometry instanceof Geometry) { |
|
0 ignored issues
–
show
The class
GeoJson\Geometry\Geometry does not exist. Did you forget a USE statement, or did you not list all dependencies?
This error could be the result of: 1. Missing dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed.
Loading history...
|
|||
484 | 1 | $geometry = $geometry->jsonSerialize(); |
|
485 | } |
||
486 | |||
487 | 2 | return $this->operator('$geoWithin', ['$geometry' => $geometry]); |
|
488 | } |
||
489 | |||
490 | /** |
||
491 | * Add $geoWithin criteria with a $box shape to the expression. |
||
492 | * |
||
493 | * A rectangular polygon will be constructed from a pair of coordinates |
||
494 | * corresponding to the bottom left and top right corners. |
||
495 | * |
||
496 | * Note: the $box operator only supports legacy coordinate pairs and 2d |
||
497 | * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes. |
||
498 | * |
||
499 | * @see Builder::geoWithinBox() |
||
500 | * @see http://docs.mongodb.org/manual/reference/operator/box/ |
||
501 | */ |
||
502 | 1 | public function geoWithinBox(float $x1, float $y1, float $x2, float $y2) : self |
|
503 | { |
||
504 | 1 | $shape = ['$box' => [[$x1, $y1], [$x2, $y2]]]; |
|
505 | |||
506 | 1 | return $this->operator('$geoWithin', $shape); |
|
507 | } |
||
508 | |||
509 | /** |
||
510 | * Add $geoWithin criteria with a $center shape to the expression. |
||
511 | * |
||
512 | * Note: the $center operator only supports legacy coordinate pairs and 2d |
||
513 | * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes. |
||
514 | * |
||
515 | * @see Builider::geoWithinCenter() |
||
516 | * @see http://docs.mongodb.org/manual/reference/operator/center/ |
||
517 | */ |
||
518 | 1 | public function geoWithinCenter(float $x, float $y, float $radius) : self |
|
519 | { |
||
520 | 1 | $shape = ['$center' => [[$x, $y], $radius]]; |
|
521 | |||
522 | 1 | return $this->operator('$geoWithin', $shape); |
|
523 | } |
||
524 | |||
525 | /** |
||
526 | * Add $geoWithin criteria with a $centerSphere shape to the expression. |
||
527 | * |
||
528 | * Note: the $centerSphere operator supports both 2d and 2dsphere indexes. |
||
529 | * |
||
530 | * @see Builder::geoWithinCenterSphere() |
||
531 | * @see http://docs.mongodb.org/manual/reference/operator/centerSphere/ |
||
532 | */ |
||
533 | 1 | public function geoWithinCenterSphere(float $x, float $y, float $radius) : self |
|
534 | { |
||
535 | 1 | $shape = ['$centerSphere' => [[$x, $y], $radius]]; |
|
536 | |||
537 | 1 | return $this->operator('$geoWithin', $shape); |
|
538 | } |
||
539 | |||
540 | /** |
||
541 | * Add $geoWithin criteria with a $polygon shape to the expression. |
||
542 | * |
||
543 | * Point coordinates are in x, y order (easting, northing for projected |
||
544 | * coordinates, longitude, latitude for geographic coordinates). |
||
545 | * |
||
546 | * The last point coordinate is implicitly connected with the first. |
||
547 | * |
||
548 | * Note: the $polygon operator only supports legacy coordinate pairs and 2d |
||
549 | * indexes. This cannot be used with 2dsphere indexes and GeoJSON shapes. |
||
550 | * |
||
551 | * @see Builder::geoWithinPolygon() |
||
552 | * @see http://docs.mongodb.org/manual/reference/operator/polygon/ |
||
553 | * |
||
554 | * @param array $point1 First point of the polygon |
||
555 | * @param array $point2 Second point of the polygon |
||
556 | * @param array $point3 Third point of the polygon |
||
557 | * @param array ...$points Additional points of the polygon |
||
558 | * |
||
559 | * @throws InvalidArgumentException If less than three points are given. |
||
560 | */ |
||
561 | 1 | public function geoWithinPolygon($point1, $point2, $point3, ...$points) : self |
|
562 | { |
||
563 | 1 | $shape = ['$polygon' => func_get_args()]; |
|
564 | |||
565 | 1 | return $this->operator('$geoWithin', $shape); |
|
566 | } |
||
567 | |||
568 | /** |
||
569 | * Return the current field. |
||
570 | */ |
||
571 | 2 | public function getCurrentField() : ?string |
|
572 | { |
||
573 | 2 | return $this->currentField; |
|
574 | } |
||
575 | |||
576 | /** |
||
577 | * Gets prepared newObj part of expression. |
||
578 | */ |
||
579 | 177 | public function getNewObj() : array |
|
580 | { |
||
581 | 177 | return $this->dm->getUnitOfWork() |
|
582 | 177 | ->getDocumentPersister($this->class->name) |
|
583 | 177 | ->prepareQueryOrNewObj($this->newObj, true); |
|
584 | } |
||
585 | |||
586 | /** |
||
587 | * Gets prepared query part of expression. |
||
588 | */ |
||
589 | 253 | public function getQuery() : array |
|
590 | { |
||
591 | 253 | return $this->dm->getUnitOfWork() |
|
592 | 253 | ->getDocumentPersister($this->class->name) |
|
593 | 253 | ->prepareQueryOrNewObj($this->query); |
|
594 | } |
||
595 | |||
596 | /** |
||
597 | * Specify $gt criteria for the current field. |
||
598 | * |
||
599 | * @see Builder::gt() |
||
600 | * @see http://docs.mongodb.org/manual/reference/operator/gt/ |
||
601 | * |
||
602 | * @param mixed $value |
||
603 | */ |
||
604 | 2 | public function gt($value) : self |
|
605 | { |
||
606 | 2 | return $this->operator('$gt', $value); |
|
607 | } |
||
608 | |||
609 | /** |
||
610 | * Specify $gte criteria for the current field. |
||
611 | * |
||
612 | * @see Builder::gte() |
||
613 | * @see http://docs.mongodb.org/manual/reference/operator/gte/ |
||
614 | * |
||
615 | * @param mixed $value |
||
616 | */ |
||
617 | 2 | public function gte($value) : self |
|
618 | { |
||
619 | 2 | return $this->operator('$gte', $value); |
|
620 | } |
||
621 | |||
622 | /** |
||
623 | * Specify $in criteria for the current field. |
||
624 | * |
||
625 | * @see Builder::in() |
||
626 | * @see http://docs.mongodb.org/manual/reference/operator/in/ |
||
627 | */ |
||
628 | 31 | public function in(array $values) : self |
|
629 | { |
||
630 | 31 | return $this->operator('$in', array_values($values)); |
|
631 | } |
||
632 | |||
633 | /** |
||
634 | * Increment the current field. |
||
635 | * |
||
636 | * If the field does not exist, it will be set to this value. |
||
637 | * |
||
638 | * @see Builder::inc() |
||
639 | * @see http://docs.mongodb.org/manual/reference/operator/inc/ |
||
640 | * |
||
641 | * @param float|int $value |
||
642 | */ |
||
643 | 5 | public function inc($value) : self |
|
644 | { |
||
645 | 5 | $this->requiresCurrentField(); |
|
646 | 5 | $this->newObj['$inc'][$this->currentField] = $value; |
|
647 | 5 | return $this; |
|
648 | } |
||
649 | |||
650 | /** |
||
651 | * Checks that the current field includes a reference to the supplied document. |
||
652 | */ |
||
653 | 6 | public function includesReferenceTo(object $document) : self |
|
654 | { |
||
655 | 6 | $this->requiresCurrentField(); |
|
656 | 6 | $mapping = $this->getReferenceMapping(); |
|
657 | 4 | $reference = $this->dm->createReference($document, $mapping); |
|
658 | 4 | $storeAs = $mapping['storeAs'] ?? null; |
|
659 | 4 | $keys = []; |
|
660 | |||
661 | switch ($storeAs) { |
||
662 | 4 | case ClassMetadata::REFERENCE_STORE_AS_ID: |
|
663 | 2 | $this->query[$mapping['name']] = $reference; |
|
664 | 2 | return $this; |
|
665 | break; |
||
666 | |||
667 | 3 | case ClassMetadata::REFERENCE_STORE_AS_REF: |
|
668 | $keys = ['id' => true]; |
||
669 | break; |
||
670 | |||
671 | 3 | case ClassMetadata::REFERENCE_STORE_AS_DB_REF: |
|
672 | 1 | case ClassMetadata::REFERENCE_STORE_AS_DB_REF_WITH_DB: |
|
673 | 3 | $keys = ['$ref' => true, '$id' => true, '$db' => true]; |
|
674 | |||
675 | 3 | if ($storeAs === ClassMetadata::REFERENCE_STORE_AS_DB_REF) { |
|
676 | 2 | unset($keys['$db']); |
|
677 | } |
||
678 | |||
679 | 3 | if (isset($mapping['targetDocument'])) { |
|
680 | 1 | unset($keys['$ref'], $keys['$db']); |
|
681 | } |
||
682 | 3 | break; |
|
683 | |||
684 | default: |
||
685 | throw new InvalidArgumentException(sprintf('Reference type %s is invalid.', $storeAs)); |
||
686 | } |
||
687 | |||
688 | 3 | foreach ($keys as $key => $value) { |
|
689 | 3 | $this->query[$mapping['name']]['$elemMatch'][$key] = $reference[$key]; |
|
690 | } |
||
691 | |||
692 | 3 | return $this; |
|
693 | } |
||
694 | |||
695 | /** |
||
696 | * Set the $language option for $text criteria. |
||
697 | * |
||
698 | * This method must be called after text(). |
||
699 | * |
||
700 | * @see Builder::language() |
||
701 | * @see http://docs.mongodb.org/manual/reference/operator/text/ |
||
702 | * |
||
703 | * @throws BadMethodCallException If the query does not already have $text criteria. |
||
704 | */ |
||
705 | 2 | public function language(string $language) : self |
|
706 | { |
||
707 | 2 | if (! isset($this->query['$text'])) { |
|
708 | 1 | throw new BadMethodCallException('This method requires a $text operator (call text() first)'); |
|
709 | } |
||
710 | |||
711 | 1 | $this->query['$text']['$language'] = $language; |
|
712 | |||
713 | 1 | return $this; |
|
714 | } |
||
715 | |||
716 | /** |
||
717 | * Specify $lt criteria for the current field. |
||
718 | * |
||
719 | * @see Builder::lte() |
||
720 | * @see http://docs.mongodb.org/manual/reference/operator/lte/ |
||
721 | * |
||
722 | * @param mixed $value |
||
723 | */ |
||
724 | 4 | public function lt($value) : self |
|
725 | { |
||
726 | 4 | return $this->operator('$lt', $value); |
|
727 | } |
||
728 | |||
729 | /** |
||
730 | * Specify $lte criteria for the current field. |
||
731 | * |
||
732 | * @see Builder::lte() |
||
733 | * @see http://docs.mongodb.org/manual/reference/operator/lte/ |
||
734 | * |
||
735 | * @param mixed $value |
||
736 | */ |
||
737 | 2 | public function lte($value) : self |
|
738 | { |
||
739 | 2 | return $this->operator('$lte', $value); |
|
740 | } |
||
741 | |||
742 | /** |
||
743 | * Updates the value of the field to a specified value if the specified value is greater than the current value of the field. |
||
744 | * |
||
745 | * @see Builder::max() |
||
746 | * @see http://docs.mongodb.org/manual/reference/operator/update/max/ |
||
747 | * |
||
748 | * @param mixed $value |
||
749 | */ |
||
750 | public function max($value) : self |
||
751 | { |
||
752 | $this->requiresCurrentField(); |
||
753 | $this->newObj['$max'][$this->currentField] = $value; |
||
754 | return $this; |
||
755 | } |
||
756 | |||
757 | /** |
||
758 | * Updates the value of the field to a specified value if the specified value is less than the current value of the field. |
||
759 | * |
||
760 | * @see Builder::min() |
||
761 | * @see http://docs.mongodb.org/manual/reference/operator/update/min/ |
||
762 | * |
||
763 | * @param mixed $value |
||
764 | */ |
||
765 | public function min($value) : self |
||
766 | { |
||
767 | $this->requiresCurrentField(); |
||
768 | $this->newObj['$min'][$this->currentField] = $value; |
||
769 | return $this; |
||
770 | } |
||
771 | |||
772 | /** |
||
773 | * Specify $mod criteria for the current field. |
||
774 | * |
||
775 | * @see Builder::mod() |
||
776 | * @see http://docs.mongodb.org/manual/reference/operator/mod/ |
||
777 | * |
||
778 | * @param float|int $divisor |
||
779 | * @param float|int $remainder |
||
780 | */ |
||
781 | public function mod($divisor, $remainder = 0) : self |
||
782 | { |
||
783 | return $this->operator('$mod', [$divisor, $remainder]); |
||
784 | } |
||
785 | |||
786 | /** |
||
787 | * Multiply the current field. |
||
788 | * |
||
789 | * If the field does not exist, it will be set to 0. |
||
790 | * |
||
791 | * @see Builder::mul() |
||
792 | * @see http://docs.mongodb.org/manual/reference/operator/mul/ |
||
793 | * |
||
794 | * @param float|int $value |
||
795 | */ |
||
796 | public function mul($value) : self |
||
797 | { |
||
798 | $this->requiresCurrentField(); |
||
799 | $this->newObj['$mul'][$this->currentField] = $value; |
||
800 | return $this; |
||
801 | } |
||
802 | |||
803 | /** |
||
804 | * Add $near criteria to the expression. |
||
805 | * |
||
806 | * A GeoJSON point may be provided as the first and only argument for |
||
807 | * 2dsphere queries. This single parameter may be a GeoJSON point object or |
||
808 | * an array corresponding to the point's JSON representation. |
||
809 | * |
||
810 | * @see Builder::near() |
||
811 | * @see http://docs.mongodb.org/manual/reference/operator/near/ |
||
812 | * |
||
813 | * @param float|array|Point $x |
||
814 | * @param float $y |
||
815 | */ |
||
816 | 3 | public function near($x, $y = null) : self |
|
817 | { |
||
818 | 3 | if ($x instanceof Point) { |
|
0 ignored issues
–
show
The class
GeoJson\Geometry\Point does not exist. Did you forget a USE statement, or did you not list all dependencies?
This error could be the result of: 1. Missing dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed.
Loading history...
|
|||
819 | 1 | $x = $x->jsonSerialize(); |
|
820 | } |
||
821 | |||
822 | 3 | if (is_array($x)) { |
|
823 | 2 | return $this->operator('$near', ['$geometry' => $x]); |
|
824 | } |
||
825 | |||
826 | 1 | return $this->operator('$near', [$x, $y]); |
|
827 | } |
||
828 | |||
829 | /** |
||
830 | * Add $nearSphere criteria to the expression. |
||
831 | * |
||
832 | * A GeoJSON point may be provided as the first and only argument for |
||
833 | * 2dsphere queries. This single parameter may be a GeoJSON point object or |
||
834 | * an array corresponding to the point's JSON representation. |
||
835 | * |
||
836 | * @see Builder::nearSphere() |
||
837 | * @see http://docs.mongodb.org/manual/reference/operator/nearSphere/ |
||
838 | * |
||
839 | * @param float|array|Point $x |
||
840 | * @param float $y |
||
841 | */ |
||
842 | 3 | public function nearSphere($x, $y = null) : self |
|
843 | { |
||
844 | 3 | if ($x instanceof Point) { |
|
0 ignored issues
–
show
The class
GeoJson\Geometry\Point does not exist. Did you forget a USE statement, or did you not list all dependencies?
This error could be the result of: 1. Missing dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed.
Loading history...
|
|||
845 | 1 | $x = $x->jsonSerialize(); |
|
846 | } |
||
847 | |||
848 | 3 | if (is_array($x)) { |
|
849 | 2 | return $this->operator('$nearSphere', ['$geometry' => $x]); |
|
850 | } |
||
851 | |||
852 | 1 | return $this->operator('$nearSphere', [$x, $y]); |
|
853 | } |
||
854 | |||
855 | /** |
||
856 | * Negates an expression for the current field. |
||
857 | * |
||
858 | * @see Builder::not() |
||
859 | * @see http://docs.mongodb.org/manual/reference/operator/not/ |
||
860 | * |
||
861 | * @param array|Expr $expression |
||
862 | */ |
||
863 | 2 | public function not($expression) : self |
|
864 | { |
||
865 | 2 | return $this->operator('$not', $expression instanceof Expr ? $expression->getQuery() : $expression); |
|
866 | } |
||
867 | |||
868 | /** |
||
869 | * Specify $ne criteria for the current field. |
||
870 | * |
||
871 | * @see Builder::notEqual() |
||
872 | * @see http://docs.mongodb.org/manual/reference/operator/ne/ |
||
873 | * |
||
874 | * @param mixed $value |
||
875 | */ |
||
876 | 6 | public function notEqual($value) : self |
|
877 | { |
||
878 | 6 | return $this->operator('$ne', $value); |
|
879 | } |
||
880 | |||
881 | /** |
||
882 | * Specify $nin criteria for the current field. |
||
883 | * |
||
884 | * @see Builder::notIn() |
||
885 | * @see http://docs.mongodb.org/manual/reference/operator/nin/ |
||
886 | */ |
||
887 | 6 | public function notIn(array $values) : self |
|
888 | { |
||
889 | 6 | return $this->operator('$nin', array_values($values)); |
|
890 | } |
||
891 | |||
892 | /** |
||
893 | * Defines an operator and value on the expression. |
||
894 | * |
||
895 | * If there is a current field, the operator will be set on it; otherwise, |
||
896 | * the operator is set at the top level of the query. |
||
897 | * |
||
898 | * @param mixed $value |
||
899 | */ |
||
900 | 81 | public function operator(string $operator, $value) : self |
|
901 | { |
||
902 | 81 | $this->wrapEqualityCriteria(); |
|
903 | |||
904 | 81 | if ($this->currentField) { |
|
905 | 56 | $this->query[$this->currentField][$operator] = $value; |
|
906 | } else { |
||
907 | 27 | $this->query[$operator] = $value; |
|
908 | } |
||
909 | 81 | return $this; |
|
910 | } |
||
911 | |||
912 | /** |
||
913 | * Remove the first element from the current array field. |
||
914 | * |
||
915 | * @see Builder::popFirst() |
||
916 | * @see http://docs.mongodb.org/manual/reference/operator/pop/ |
||
917 | */ |
||
918 | 2 | public function popFirst() : self |
|
919 | { |
||
920 | 2 | $this->requiresCurrentField(); |
|
921 | 2 | $this->newObj['$pop'][$this->currentField] = -1; |
|
922 | 2 | return $this; |
|
923 | } |
||
924 | |||
925 | /** |
||
926 | * Remove the last element from the current array field. |
||
927 | * |
||
928 | * @see Builder::popLast() |
||
929 | * @see http://docs.mongodb.org/manual/reference/operator/pop/ |
||
930 | */ |
||
931 | 1 | public function popLast() : self |
|
932 | { |
||
933 | 1 | $this->requiresCurrentField(); |
|
934 | 1 | $this->newObj['$pop'][$this->currentField] = 1; |
|
935 | 1 | return $this; |
|
936 | } |
||
937 | |||
938 | /** |
||
939 | * Add $position criteria to the expression for a $push operation. |
||
940 | * |
||
941 | * This is useful in conjunction with {@link Expr::each()} for a |
||
942 | * {@link Expr::push()} operation. |
||
943 | * |
||
944 | * @see http://docs.mongodb.org/manual/reference/operator/update/position/ |
||
945 | */ |
||
946 | 1 | public function position(int $position) : self |
|
947 | { |
||
948 | 1 | return $this->operator('$position', $position); |
|
949 | } |
||
950 | |||
951 | /** |
||
952 | * Remove all elements matching the given value or expression from the |
||
953 | * current array field. |
||
954 | * |
||
955 | * @see Builder::pull() |
||
956 | * @see http://docs.mongodb.org/manual/reference/operator/pull/ |
||
957 | * |
||
958 | * @param mixed|Expr $valueOrExpression |
||
959 | */ |
||
960 | 2 | public function pull($valueOrExpression) : self |
|
961 | { |
||
962 | 2 | if ($valueOrExpression instanceof Expr) { |
|
963 | 1 | $valueOrExpression = $valueOrExpression->getQuery(); |
|
964 | } |
||
965 | |||
966 | 2 | $this->requiresCurrentField(); |
|
967 | 2 | $this->newObj['$pull'][$this->currentField] = $valueOrExpression; |
|
968 | 2 | return $this; |
|
969 | } |
||
970 | |||
971 | /** |
||
972 | * Remove all elements matching any of the given values from the current |
||
973 | * array field. |
||
974 | * |
||
975 | * @see Builder::pullAll() |
||
976 | * @see http://docs.mongodb.org/manual/reference/operator/pullAll/ |
||
977 | */ |
||
978 | public function pullAll(array $values) : self |
||
979 | { |
||
980 | $this->requiresCurrentField(); |
||
981 | $this->newObj['$pullAll'][$this->currentField] = $values; |
||
982 | return $this; |
||
983 | } |
||
984 | |||
985 | /** |
||
986 | * Append one or more values to the current array field. |
||
987 | * |
||
988 | * If the field does not exist, it will be set to an array containing the |
||
989 | * value(s) in the argument. If the field is not an array, the query |
||
990 | * will yield an error. |
||
991 | * |
||
992 | * Multiple values may be specified by providing an Expr object and using |
||
993 | * {@link Expr::each()}. {@link Expr::slice()} and {@link Expr::sort()} may |
||
994 | * also be used to limit and order array elements, respectively. |
||
995 | * |
||
996 | * @see Builder::push() |
||
997 | * @see http://docs.mongodb.org/manual/reference/operator/push/ |
||
998 | * @see http://docs.mongodb.org/manual/reference/operator/each/ |
||
999 | * @see http://docs.mongodb.org/manual/reference/operator/slice/ |
||
1000 | * @see http://docs.mongodb.org/manual/reference/operator/sort/ |
||
1001 | * |
||
1002 | * @param mixed|Expr $valueOrExpression |
||
1003 | */ |
||
1004 | 8 | public function push($valueOrExpression) : self |
|
1005 | { |
||
1006 | 8 | if ($valueOrExpression instanceof Expr) { |
|
1007 | 3 | $valueOrExpression = array_merge( |
|
1008 | 3 | ['$each' => []], |
|
1009 | 3 | $valueOrExpression->getQuery() |
|
1010 | ); |
||
1011 | } |
||
1012 | |||
1013 | 8 | $this->requiresCurrentField(); |
|
1014 | 8 | $this->newObj['$push'][$this->currentField] = $valueOrExpression; |
|
1015 | 8 | return $this; |
|
1016 | } |
||
1017 | |||
1018 | /** |
||
1019 | * Specify $gte and $lt criteria for the current field. |
||
1020 | * |
||
1021 | * This method is shorthand for specifying $gte criteria on the lower bound |
||
1022 | * and $lt criteria on the upper bound. The upper bound is not inclusive. |
||
1023 | * |
||
1024 | * @see Builder::range() |
||
1025 | * |
||
1026 | * @param mixed $start |
||
1027 | * @param mixed $end |
||
1028 | */ |
||
1029 | 2 | public function range($start, $end) : self |
|
1030 | { |
||
1031 | 2 | return $this->operator('$gte', $start)->operator('$lt', $end); |
|
1032 | } |
||
1033 | |||
1034 | /** |
||
1035 | * Checks that the value of the current field is a reference to the supplied document. |
||
1036 | */ |
||
1037 | 13 | public function references(object $document) : self |
|
1038 | { |
||
1039 | 13 | $this->requiresCurrentField(); |
|
1040 | 13 | $mapping = $this->getReferenceMapping(); |
|
1041 | 11 | $reference = $this->dm->createReference($document, $mapping); |
|
1042 | 11 | $storeAs = $mapping['storeAs'] ?? null; |
|
1043 | 11 | $keys = []; |
|
1044 | |||
1045 | switch ($storeAs) { |
||
1046 | 11 | case ClassMetadata::REFERENCE_STORE_AS_ID: |
|
1047 | 4 | $this->query[$mapping['name']] = $reference; |
|
1048 | 4 | return $this; |
|
1049 | break; |
||
1050 | |||
1051 | 8 | case ClassMetadata::REFERENCE_STORE_AS_REF: |
|
1052 | $keys = ['id' => true]; |
||
1053 | break; |
||
1054 | |||
1055 | 8 | case ClassMetadata::REFERENCE_STORE_AS_DB_REF: |
|
1056 | 3 | case ClassMetadata::REFERENCE_STORE_AS_DB_REF_WITH_DB: |
|
1057 | 8 | $keys = ['$ref' => true, '$id' => true, '$db' => true]; |
|
1058 | |||
1059 | 8 | if ($storeAs === ClassMetadata::REFERENCE_STORE_AS_DB_REF) { |
|
1060 | 5 | unset($keys['$db']); |
|
1061 | } |
||
1062 | |||
1063 | 8 | if (isset($mapping['targetDocument'])) { |
|
1064 | 4 | unset($keys['$ref'], $keys['$db']); |
|
1065 | } |
||
1066 | 8 | break; |
|
1067 | |||
1068 | default: |
||
1069 | throw new InvalidArgumentException(sprintf('Reference type %s is invalid.', $storeAs)); |
||
1070 | } |
||
1071 | |||
1072 | 8 | foreach ($keys as $key => $value) { |
|
1073 | 8 | $this->query[$mapping['name'] . '.' . $key] = $reference[$key]; |
|
1074 | } |
||
1075 | |||
1076 | 8 | return $this; |
|
1077 | } |
||
1078 | |||
1079 | /** |
||
1080 | * Rename the current field. |
||
1081 | * |
||
1082 | * @see Builder::rename() |
||
1083 | * @see http://docs.mongodb.org/manual/reference/operator/rename/ |
||
1084 | */ |
||
1085 | public function rename(string $name) : self |
||
1086 | { |
||
1087 | $this->requiresCurrentField(); |
||
1088 | $this->newObj['$rename'][$this->currentField] = $name; |
||
1089 | return $this; |
||
1090 | } |
||
1091 | |||
1092 | /** |
||
1093 | * Set the current field to a value. |
||
1094 | * |
||
1095 | * This is only relevant for insert, update, or findAndUpdate queries. For |
||
1096 | * update and findAndUpdate queries, the $atomic parameter will determine |
||
1097 | * whether or not a $set operator is used. |
||
1098 | * |
||
1099 | * @see Builder::set() |
||
1100 | * @see http://docs.mongodb.org/manual/reference/operator/set/ |
||
1101 | * |
||
1102 | * @param mixed $value |
||
1103 | */ |
||
1104 | 19 | public function set($value, bool $atomic = true) : self |
|
1105 | { |
||
1106 | 19 | $this->requiresCurrentField(); |
|
1107 | 19 | assert($this->currentField !== null); |
|
1108 | |||
1109 | 19 | if ($atomic) { |
|
1110 | 16 | $this->newObj['$set'][$this->currentField] = $value; |
|
1111 | 16 | return $this; |
|
1112 | } |
||
1113 | |||
1114 | 3 | if (strpos($this->currentField, '.') === false) { |
|
1115 | 2 | $this->newObj[$this->currentField] = $value; |
|
1116 | 2 | return $this; |
|
1117 | } |
||
1118 | |||
1119 | 2 | $keys = explode('.', $this->currentField); |
|
1120 | 2 | $current = &$this->newObj; |
|
1121 | 2 | foreach ($keys as $key) { |
|
1122 | 2 | $current = &$current[$key]; |
|
1123 | } |
||
1124 | 2 | $current = $value; |
|
1125 | |||
1126 | 2 | return $this; |
|
1127 | } |
||
1128 | |||
1129 | /** |
||
1130 | * Sets ClassMetadata for document being queried. |
||
1131 | */ |
||
1132 | 390 | public function setClassMetadata(ClassMetadata $class) : void |
|
1133 | { |
||
1134 | 390 | $this->class = $class; |
|
1135 | 390 | } |
|
1136 | |||
1137 | /** |
||
1138 | * Set the "new object". |
||
1139 | * |
||
1140 | * @see Builder::setNewObj() |
||
1141 | */ |
||
1142 | public function setNewObj(array $newObj) : self |
||
1143 | { |
||
1144 | $this->newObj = $newObj; |
||
1145 | return $this; |
||
1146 | } |
||
1147 | |||
1148 | /** |
||
1149 | * Set the current field to the value if the document is inserted in an |
||
1150 | * upsert operation. |
||
1151 | * |
||
1152 | * If an update operation with upsert: true results in an insert of a |
||
1153 | * document, then $setOnInsert assigns the specified values to the fields in |
||
1154 | * the document. If the update operation does not result in an insert, |
||
1155 | * $setOnInsert does nothing. |
||
1156 | * |
||
1157 | * @see Builder::setOnInsert() |
||
1158 | * @see https://docs.mongodb.org/manual/reference/operator/update/setOnInsert/ |
||
1159 | * |
||
1160 | * @param mixed $value |
||
1161 | */ |
||
1162 | 1 | public function setOnInsert($value) : self |
|
1163 | { |
||
1164 | 1 | $this->requiresCurrentField(); |
|
1165 | 1 | $this->newObj['$setOnInsert'][$this->currentField] = $value; |
|
1166 | |||
1167 | 1 | return $this; |
|
1168 | } |
||
1169 | |||
1170 | /** |
||
1171 | * Set the query criteria. |
||
1172 | * |
||
1173 | * @see Builder::setQueryArray() |
||
1174 | */ |
||
1175 | 18 | public function setQuery(array $query) : self |
|
1176 | { |
||
1177 | 18 | $this->query = $query; |
|
1178 | 18 | return $this; |
|
1179 | } |
||
1180 | |||
1181 | /** |
||
1182 | * Specify $size criteria for the current field. |
||
1183 | * |
||
1184 | * @see Builder::size() |
||
1185 | * @see http://docs.mongodb.org/manual/reference/operator/size/ |
||
1186 | */ |
||
1187 | public function size(int $size) : self |
||
1188 | { |
||
1189 | return $this->operator('$size', $size); |
||
1190 | } |
||
1191 | |||
1192 | /** |
||
1193 | * Add $slice criteria to the expression for a $push operation. |
||
1194 | * |
||
1195 | * This is useful in conjunction with {@link Expr::each()} for a |
||
1196 | * {@link Expr::push()} operation. {@link Builder::selectSlice()} should be |
||
1197 | * used for specifying $slice for a query projection. |
||
1198 | * |
||
1199 | * @see http://docs.mongodb.org/manual/reference/operator/slice/ |
||
1200 | */ |
||
1201 | 2 | public function slice(int $slice) : self |
|
1202 | { |
||
1203 | 2 | return $this->operator('$slice', $slice); |
|
1204 | } |
||
1205 | |||
1206 | /** |
||
1207 | * Add $sort criteria to the expression for a $push operation. |
||
1208 | * |
||
1209 | * If sorting by multiple fields, the first argument should be an array of |
||
1210 | * field name (key) and order (value) pairs. |
||
1211 | * |
||
1212 | * This is useful in conjunction with {@link Expr::each()} for a |
||
1213 | * {@link Expr::push()} operation. {@link Builder::sort()} should be used to |
||
1214 | * sort the results of a query. |
||
1215 | * |
||
1216 | * @see http://docs.mongodb.org/manual/reference/operator/sort/ |
||
1217 | * |
||
1218 | * @param array|string $fieldName Field name or array of field/order pairs |
||
1219 | * @param int|string $order Field order (if one field is specified) |
||
1220 | */ |
||
1221 | 2 | public function sort($fieldName, $order = null) : self |
|
1222 | { |
||
1223 | 2 | $fields = is_array($fieldName) ? $fieldName : [$fieldName => $order]; |
|
1224 | |||
1225 | return $this->operator('$sort', array_map(function ($order) { |
||
1226 | 2 | return $this->normalizeSortOrder($order); |
|
1227 | 2 | }, $fields)); |
|
1228 | } |
||
1229 | |||
1230 | /** |
||
1231 | * Specify $text criteria for the current query. |
||
1232 | * |
||
1233 | * The $language option may be set with {@link Expr::language()}. |
||
1234 | * |
||
1235 | * @see Builder::text() |
||
1236 | * @see http://docs.mongodb.org/master/reference/operator/query/text/ |
||
1237 | */ |
||
1238 | 6 | public function text(string $search) : self |
|
1239 | { |
||
1240 | 6 | $this->query['$text'] = ['$search' => $search]; |
|
1241 | 6 | return $this; |
|
1242 | } |
||
1243 | |||
1244 | /** |
||
1245 | * Specify $type criteria for the current field. |
||
1246 | * |
||
1247 | * @see Builder::type() |
||
1248 | * @see http://docs.mongodb.org/manual/reference/operator/type/ |
||
1249 | * |
||
1250 | * @param int|string $type |
||
1251 | */ |
||
1252 | 1 | public function type($type) : self |
|
1253 | { |
||
1254 | 1 | return $this->operator('$type', $type); |
|
1255 | } |
||
1256 | |||
1257 | /** |
||
1258 | * Unset the current field. |
||
1259 | * |
||
1260 | * The field will be removed from the document (not set to null). |
||
1261 | * |
||
1262 | * @see Builder::unsetField() |
||
1263 | * @see http://docs.mongodb.org/manual/reference/operator/unset/ |
||
1264 | */ |
||
1265 | 3 | public function unsetField() : self |
|
1266 | { |
||
1267 | 3 | $this->requiresCurrentField(); |
|
1268 | 3 | $this->newObj['$unset'][$this->currentField] = 1; |
|
1269 | 3 | return $this; |
|
1270 | } |
||
1271 | |||
1272 | /** |
||
1273 | * Specify a JavaScript expression to use for matching documents. |
||
1274 | * |
||
1275 | * @see Builder::where() |
||
1276 | * @see http://docs.mongodb.org/manual/reference/operator/where/ |
||
1277 | * |
||
1278 | * @param string|Javascript $javascript |
||
1279 | */ |
||
1280 | 3 | public function where($javascript) : self |
|
1281 | { |
||
1282 | 3 | $this->query['$where'] = $javascript; |
|
1283 | 3 | return $this; |
|
1284 | } |
||
1285 | |||
1286 | /** |
||
1287 | * Gets reference mapping for current field from current class or its descendants. |
||
1288 | * |
||
1289 | * @throws MappingException |
||
1290 | */ |
||
1291 | 19 | private function getReferenceMapping() : array |
|
1292 | { |
||
1293 | 19 | $this->requiresCurrentField(); |
|
1294 | 19 | assert($this->currentField !== null); |
|
1295 | |||
1296 | try { |
||
1297 | 19 | return $this->class->getFieldMapping($this->currentField); |
|
1298 | 6 | } catch (MappingException $e) { |
|
1299 | 6 | if (empty($this->class->discriminatorMap)) { |
|
1300 | throw $e; |
||
1301 | } |
||
1302 | 6 | $mapping = null; |
|
1303 | 6 | $foundIn = null; |
|
1304 | 6 | foreach ($this->class->discriminatorMap as $child) { |
|
1305 | 6 | $childClass = $this->dm->getClassMetadata($child); |
|
1306 | 6 | if (! $childClass->hasAssociation($this->currentField)) { |
|
1307 | 4 | continue; |
|
1308 | } |
||
1309 | |||
1310 | 4 | if ($foundIn !== null && $mapping !== null && $mapping !== $childClass->getFieldMapping($this->currentField)) { |
|
1311 | 2 | throw MappingException::referenceFieldConflict($this->currentField, $foundIn->name, $childClass->name); |
|
1312 | } |
||
1313 | 4 | $mapping = $childClass->getFieldMapping($this->currentField); |
|
1314 | 4 | $foundIn = $childClass; |
|
1315 | } |
||
1316 | 4 | if ($mapping === null) { |
|
1317 | 2 | throw MappingException::mappingNotFoundInClassNorDescendants($this->class->name, $this->currentField); |
|
1318 | } |
||
1319 | |||
1320 | 2 | return $mapping; |
|
1321 | } |
||
1322 | } |
||
1323 | |||
1324 | /** |
||
1325 | * @param int|string $order |
||
1326 | */ |
||
1327 | 2 | private function normalizeSortOrder($order) : int |
|
1328 | { |
||
1329 | 2 | if (is_string($order)) { |
|
1330 | $order = strtolower($order) === 'asc' ? 1 : -1; |
||
1331 | } |
||
1332 | |||
1333 | 2 | return $order; |
|
1334 | } |
||
1335 | |||
1336 | /** |
||
1337 | * Ensure that a current field has been set. |
||
1338 | * |
||
1339 | * @throws LogicException If a current field has not been set. |
||
1340 | */ |
||
1341 | 69 | private function requiresCurrentField() : void |
|
1342 | { |
||
1343 | 69 | if (! $this->currentField) { |
|
1344 | throw new LogicException('This method requires you set a current field using field().'); |
||
1345 | } |
||
1346 | 69 | } |
|
1347 | |||
1348 | /** |
||
1349 | * Wraps equality criteria with an operator. |
||
1350 | * |
||
1351 | * If equality criteria was previously specified for a field, it cannot be |
||
1352 | * merged with other operators without first being wrapped in an operator of |
||
1353 | * its own. Ideally, we would wrap it with $eq, but that is only available |
||
1354 | * in MongoDB 2.8. Using a single-element $in is backwards compatible. |
||
1355 | * |
||
1356 | * @see Expr::operator() |
||
1357 | */ |
||
1358 | 81 | private function wrapEqualityCriteria() : void |
|
1359 | { |
||
1360 | /* If the current field has no criteria yet, do nothing. This ensures |
||
1361 | * that we do not inadvertently inject {"$in": null} into the query. |
||
1362 | */ |
||
1363 | 81 | if ($this->currentField && ! isset($this->query[$this->currentField]) && ! array_key_exists($this->currentField, $this->query)) { |
|
1364 | 55 | return; |
|
1365 | } |
||
1366 | |||
1367 | 31 | if ($this->currentField) { |
|
1368 | 5 | $query = &$this->query[$this->currentField]; |
|
1369 | } else { |
||
1370 | 27 | $query = &$this->query; |
|
1371 | } |
||
1372 | |||
1373 | /* If the query is an empty array, we'll assume that the user has not |
||
1374 | * specified criteria. Otherwise, check if the array includes a query |
||
1375 | * operator (checking the first key is sufficient). If neither of these |
||
1376 | * conditions are met, we'll wrap the query value with $in. |
||
1377 | */ |
||
1378 | 31 | if (is_array($query)) { |
|
1379 | 31 | $key = key($query); |
|
1380 | |||
1381 | 31 | if (empty($query) || (is_string($key) && strpos($key, '$') === 0)) { |
|
1382 | 31 | return; |
|
1383 | } |
||
1384 | } |
||
1385 | |||
1386 | 2 | $query = ['$in' => [$query]]; |
|
1387 | 2 | } |
|
1388 | } |
||
1389 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.