|
16 | 16 | use MongoDB\Collection; |
17 | 17 | use MongoDB\Driver\Cursor; |
18 | 18 | use OutOfRangeException; |
| 19 | +use TypeError; |
19 | 20 | use function array_map; |
20 | 21 | use function array_merge; |
21 | 22 | use function array_unshift; |
22 | 23 | use function assert; |
| 24 | +use function func_get_arg; |
| 25 | +use function func_num_args; |
| 26 | +use function gettype; |
23 | 27 | use function is_array; |
| 28 | +use function is_bool; |
24 | 29 | use function sprintf; |
25 | 30 |
|
26 | 31 | /** |
@@ -218,36 +223,63 @@ public function geoNear($x, $y = null) : Stage\GeoNear |
218 | 223 | return $stage; |
219 | 224 | } |
220 | 225 |
|
| 226 | + // phpcs:disable Squiz.Commenting.FunctionComment.ExtraParamComment |
221 | 227 | /** |
222 | 228 | * Returns the assembled aggregation pipeline |
223 | 229 | * |
| 230 | + * @param bool $applyFilters Whether to apply filters on the aggregation |
| 231 | + * pipeline stage |
| 232 | + * |
224 | 233 | * For pipelines where the first stage is a $geoNear stage, it will apply |
225 | 234 | * the document filters and discriminator queries to the query portion of |
226 | 235 | * the geoNear operation. For all other pipelines, it prepends a $match stage |
227 | 236 | * containing the required query. |
| 237 | + * |
| 238 | + * For aggregation pipelines that will be nested (e.g. in a facet stage), |
| 239 | + * you should not apply filters as this may cause wrong results to be |
| 240 | + * given. |
228 | 241 | */ |
229 | | - public function getPipeline() : array |
| 242 | + // phpcs:enable Squiz.Commenting.FunctionComment.ExtraParamComment |
| 243 | + public function getPipeline(/* bool $applyFilters = true */) : array |
230 | 244 | { |
| 245 | + $applyFilters = func_num_args() > 0 ? func_get_arg(0) : true; |
| 246 | + |
| 247 | + if (! is_bool($applyFilters)) { |
| 248 | + throw new TypeError(sprintf( |
| 249 | + 'Argument 1 passed to %s must be of the type bool, %s given', |
| 250 | + __METHOD__, |
| 251 | + gettype($applyFilters) |
| 252 | + )); |
| 253 | + } |
| 254 | + |
231 | 255 | $pipeline = array_map( |
232 | 256 | static function (Stage $stage) { |
233 | 257 | return $stage->getExpression(); |
234 | 258 | }, |
235 | 259 | $this->stages |
236 | 260 | ); |
237 | 261 |
|
238 | | - if ($this->getStage(0) instanceof Stage\GeoNear) { |
239 | | - $pipeline[0]['$geoNear']['query'] = $this->applyFilters($pipeline[0]['$geoNear']['query']); |
240 | | - } elseif ($this->getStage(0) instanceof Stage\IndexStats) { |
| 262 | + if ($this->getStage(0) instanceof Stage\IndexStats) { |
241 | 263 | // Don't apply any filters when using an IndexStats stage: since it |
242 | 264 | // needs to be the first pipeline stage, prepending a match stage |
243 | 265 | // with discriminator information will not work |
244 | 266 |
|
| 267 | + $applyFilters = false; |
| 268 | + } |
| 269 | + |
| 270 | + if (! $applyFilters) { |
245 | 271 | return $pipeline; |
246 | | - } else { |
247 | | - $matchExpression = $this->applyFilters([]); |
248 | | - if ($matchExpression !== []) { |
249 | | - array_unshift($pipeline, ['$match' => $matchExpression]); |
250 | | - } |
| 272 | + } |
| 273 | + |
| 274 | + if ($this->getStage(0) instanceof Stage\GeoNear) { |
| 275 | + $pipeline[0]['$geoNear']['query'] = $this->applyFilters($pipeline[0]['$geoNear']['query']); |
| 276 | + |
| 277 | + return $pipeline; |
| 278 | + } |
| 279 | + |
| 280 | + $matchExpression = $this->applyFilters([]); |
| 281 | + if ($matchExpression !== []) { |
| 282 | + array_unshift($pipeline, ['$match' => $matchExpression]); |
251 | 283 | } |
252 | 284 |
|
253 | 285 | return $pipeline; |
|
0 commit comments