Skip to content

Commit b098ab9

Browse files
authored
Support minDistance and maxDistance options for $near and $nearSphere operators (#2583)
* Support minDistance and maxDistance options for $near and $nearSphere operators * Fix static analysis errors
1 parent 3cec5e3 commit b098ab9

File tree

7 files changed

+215
-21
lines changed

7 files changed

+215
-21
lines changed

lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@
2929
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
3030
use Doctrine\Persistence\Mapping\MappingException;
3131
use InvalidArgumentException;
32+
use Iterator as SplIterator;
3233
use MongoDB\BSON\ObjectId;
3334
use MongoDB\Collection;
34-
use MongoDB\Driver\Cursor;
35+
use MongoDB\Driver\CursorInterface;
3536
use MongoDB\Driver\Exception\Exception as DriverException;
3637
use MongoDB\Driver\Exception\WriteException;
3738
use MongoDB\Driver\WriteConcern;
@@ -581,7 +582,7 @@ private function getShardKeyQuery(object $document): array
581582
/**
582583
* Wraps the supplied base cursor in the corresponding ODM class.
583584
*/
584-
private function wrapCursor(Cursor $baseCursor): Iterator
585+
private function wrapCursor(SplIterator&CursorInterface $baseCursor): Iterator
585586
{
586587
return new CachingIterator(new HydratingIterator($baseCursor, $this->dm->getUnitOfWork(), $this->class));
587588
}

lib/Doctrine/ODM/MongoDB/Query/Builder.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -991,9 +991,9 @@ public function mul($value): self
991991
* @param float|array<string, mixed>|Point $x
992992
* @param float $y
993993
*/
994-
public function near($x, $y = null): self
994+
public function near($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
995995
{
996-
$this->expr->near($x, $y);
996+
$this->expr->near($x, $y, $minDistance, $maxDistance);
997997

998998
return $this;
999999
}
@@ -1011,9 +1011,9 @@ public function near($x, $y = null): self
10111011
* @param float|array<string, mixed>|Point $x
10121012
* @param float $y
10131013
*/
1014-
public function nearSphere($x, $y = null): self
1014+
public function nearSphere($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
10151015
{
1016-
$this->expr->nearSphere($x, $y);
1016+
$this->expr->nearSphere($x, $y, $minDistance, $maxDistance);
10171017

10181018
return $this;
10191019
}

lib/Doctrine/ODM/MongoDB/Query/Expr.php

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use MongoDB\BSON\Binary;
1616
use MongoDB\BSON\Javascript;
1717

18+
use function array_filter;
1819
use function array_key_exists;
1920
use function array_map;
2021
use function array_merge;
@@ -822,17 +823,34 @@ public function mul($value): self
822823
* @param float|array<string, mixed>|Point $x
823824
* @param float $y
824825
*/
825-
public function near($x, $y = null): self
826+
public function near($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
826827
{
827828
if ($x instanceof Point) {
828829
$x = $x->jsonSerialize();
829830
}
830831

831832
if (is_array($x)) {
832-
return $this->operator('$near', ['$geometry' => $x]);
833+
return $this->operator(
834+
'$near',
835+
array_filter([
836+
'$geometry' => $x,
837+
'$minDistance' => $minDistance,
838+
'$maxDistance' => $maxDistance,
839+
]),
840+
);
841+
}
842+
843+
$this->operator('$near', [$x, $y]);
844+
845+
if ($minDistance !== null) {
846+
$this->operator('$minDistance', $minDistance);
833847
}
834848

835-
return $this->operator('$near', [$x, $y]);
849+
if ($maxDistance !== null) {
850+
$this->operator('$maxDistance', $maxDistance);
851+
}
852+
853+
return $this;
836854
}
837855

838856
/**
@@ -848,17 +866,34 @@ public function near($x, $y = null): self
848866
* @param float|array<string, mixed>|Point $x
849867
* @param float $y
850868
*/
851-
public function nearSphere($x, $y = null): self
869+
public function nearSphere($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
852870
{
853871
if ($x instanceof Point) {
854872
$x = $x->jsonSerialize();
855873
}
856874

857875
if (is_array($x)) {
858-
return $this->operator('$nearSphere', ['$geometry' => $x]);
876+
return $this->operator(
877+
'$nearSphere',
878+
array_filter([
879+
'$geometry' => $x,
880+
'$minDistance' => $minDistance,
881+
'$maxDistance' => $maxDistance,
882+
]),
883+
);
884+
}
885+
886+
$this->operator('$nearSphere', [$x, $y]);
887+
888+
if ($minDistance !== null) {
889+
$this->operator('$minDistance', $minDistance);
859890
}
860891

861-
return $this->operator('$nearSphere', [$x, $y]);
892+
if ($maxDistance !== null) {
893+
$this->operator('$maxDistance', $maxDistance);
894+
}
895+
896+
return $this;
862897
}
863898

864899
/**

lib/Doctrine/ODM/MongoDB/Types/Type.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,7 @@ public static function getTypesMap(): array
257257
return self::$typesMap;
258258
}
259259

260-
/** @return string */
261-
public function __toString()
260+
public function __toString(): string
262261
{
263262
$e = explode('\\', static::class);
264263
$className = end($e);

psalm-baseline.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,6 @@
279279
<code>$datetime instanceof DateTime</code>
280280
</RedundantCondition>
281281
</file>
282-
<file src="lib/Doctrine/ODM/MongoDB/Types/Type.php">
283-
<MethodSignatureMustProvideReturnType>
284-
<code>__toString</code>
285-
</MethodSignatureMustProvideReturnType>
286-
</file>
287282
<file src="lib/Doctrine/ODM/MongoDB/UnitOfWork.php">
288283
<InvalidArgument>
289284
<code>$assoc</code>

tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,8 @@ public static function provideProxiedExprMethods(): array
504504
'type()' => ['type', [7]],
505505
'all()' => ['all', [['value1', 'value2']]],
506506
'mod()' => ['mod', [2, 0]],
507-
'near()' => ['near', [1, 2]],
508-
'nearSphere()' => ['nearSphere', [1, 2]],
507+
'near()' => ['near', [1, 2], null, 5, 10],
508+
'nearSphere()' => ['nearSphere', [1, 2], null, 5, 10],
509509
'geoIntersects()' => ['geoIntersects', [self::createGeometry()]],
510510
'geoWithin()' => ['geoWithin', [self::createGeometry()]],
511511
'geoWithinBox()' => ['geoWithinBox', [1, 2, 3, 4]],

tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,64 @@ public function testNearWithGeoJsonPoint($point, array $expected): void
422422
self::assertEquals(['$near' => $expected], $expr->getQuery());
423423
}
424424

425+
public function testNearWithGeoJsonPointAndMinDistance(): void
426+
{
427+
$expr = $this->createExpr();
428+
429+
$coordinates = [1, 2];
430+
$point = new Point($coordinates);
431+
432+
self::assertSame($expr, $expr->near($point, null, 5));
433+
self::assertEquals(
434+
[
435+
'$near' => [
436+
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
437+
'$minDistance' => 5,
438+
],
439+
],
440+
$expr->getQuery(),
441+
);
442+
}
443+
444+
public function testNearWithGeoJsonPointAndMaxDistance(): void
445+
{
446+
$expr = $this->createExpr();
447+
448+
$coordinates = [1, 2];
449+
$point = new Point($coordinates);
450+
451+
self::assertSame($expr, $expr->near($point, null, null, 10));
452+
self::assertEquals(
453+
[
454+
'$near' => [
455+
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
456+
'$maxDistance' => 10,
457+
],
458+
],
459+
$expr->getQuery(),
460+
);
461+
}
462+
463+
public function testNearWithGeoJsonPointAndMinAndMaxDistance(): void
464+
{
465+
$expr = $this->createExpr();
466+
467+
$coordinates = [1, 2];
468+
$point = new Point($coordinates);
469+
470+
self::assertSame($expr, $expr->near($point, null, 5, 10));
471+
self::assertEquals(
472+
[
473+
'$near' => [
474+
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
475+
'$minDistance' => 5,
476+
'$maxDistance' => 10,
477+
],
478+
],
479+
$expr->getQuery(),
480+
);
481+
}
482+
425483
public function testNearWithLegacyCoordinates(): void
426484
{
427485
$expr = $this->createExpr();
@@ -430,6 +488,30 @@ public function testNearWithLegacyCoordinates(): void
430488
self::assertEquals(['$near' => [1, 2]], $expr->getQuery());
431489
}
432490

491+
public function testNearWithLegacyCoordinatesAndMinDistance(): void
492+
{
493+
$expr = $this->createExpr();
494+
495+
self::assertSame($expr, $expr->near(1, 2, 5));
496+
self::assertEquals(['$near' => [1, 2], '$minDistance' => 5], $expr->getQuery());
497+
}
498+
499+
public function testNearWithLegacyCoordinatesAndMaxDistance(): void
500+
{
501+
$expr = $this->createExpr();
502+
503+
self::assertSame($expr, $expr->near(1, 2, null, 10));
504+
self::assertEquals(['$near' => [1, 2], '$maxDistance' => 10], $expr->getQuery());
505+
}
506+
507+
public function testNearWithLegacyCoordinatesAndMinAndMaxDistance(): void
508+
{
509+
$expr = $this->createExpr();
510+
511+
self::assertSame($expr, $expr->near(1, 2, 5, 10));
512+
self::assertEquals(['$near' => [1, 2], '$minDistance' => 5, '$maxDistance' => 10], $expr->getQuery());
513+
}
514+
433515
/**
434516
* @param Point|array<string, mixed> $point
435517
* @param array<string, mixed> $expected
@@ -443,6 +525,64 @@ public function testNearSphereWithGeoJsonPoint($point, array $expected): void
443525
self::assertEquals(['$nearSphere' => $expected], $expr->getQuery());
444526
}
445527

528+
public function testNearSphereWithGeoJsonPointAndMinDistance(): void
529+
{
530+
$expr = $this->createExpr();
531+
532+
$coordinates = [1, 2];
533+
$point = new Point($coordinates);
534+
535+
self::assertSame($expr, $expr->nearSphere($point, null, 5));
536+
self::assertEquals(
537+
[
538+
'$nearSphere' => [
539+
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
540+
'$minDistance' => 5,
541+
],
542+
],
543+
$expr->getQuery(),
544+
);
545+
}
546+
547+
public function testNearSphereWithGeoJsonPointAndMaxDistance(): void
548+
{
549+
$expr = $this->createExpr();
550+
551+
$coordinates = [1, 2];
552+
$point = new Point($coordinates);
553+
554+
self::assertSame($expr, $expr->nearSphere($point, null, null, 10));
555+
self::assertEquals(
556+
[
557+
'$nearSphere' => [
558+
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
559+
'$maxDistance' => 10,
560+
],
561+
],
562+
$expr->getQuery(),
563+
);
564+
}
565+
566+
public function testNearSphereWithGeoJsonPointAndMinAndMaxDistance(): void
567+
{
568+
$expr = $this->createExpr();
569+
570+
$coordinates = [1, 2];
571+
$point = new Point($coordinates);
572+
573+
self::assertSame($expr, $expr->nearSphere($point, null, 5, 10));
574+
self::assertEquals(
575+
[
576+
'$nearSphere' => [
577+
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
578+
'$minDistance' => 5,
579+
'$maxDistance' => 10,
580+
],
581+
],
582+
$expr->getQuery(),
583+
);
584+
}
585+
446586
public function testNearSphereWithLegacyCoordinates(): void
447587
{
448588
$expr = $this->createExpr();
@@ -451,6 +591,30 @@ public function testNearSphereWithLegacyCoordinates(): void
451591
self::assertEquals(['$nearSphere' => [1, 2]], $expr->getQuery());
452592
}
453593

594+
public function testNearSphereWithLegacyCoordinatesAndMinDistance(): void
595+
{
596+
$expr = $this->createExpr();
597+
598+
self::assertSame($expr, $expr->nearSphere(1, 2, 5));
599+
self::assertEquals(['$nearSphere' => [1, 2], '$minDistance' => 5], $expr->getQuery());
600+
}
601+
602+
public function testNearSphereWithLegacyCoordinatesAndMaxDistance(): void
603+
{
604+
$expr = $this->createExpr();
605+
606+
self::assertSame($expr, $expr->nearSphere(1, 2, null, 10));
607+
self::assertEquals(['$nearSphere' => [1, 2], '$maxDistance' => 10], $expr->getQuery());
608+
}
609+
610+
public function testNearSphereWithLegacyCoordinatesAndMinAndMaxDistance(): void
611+
{
612+
$expr = $this->createExpr();
613+
614+
self::assertSame($expr, $expr->nearSphere(1, 2, 5, 10));
615+
self::assertEquals(['$nearSphere' => [1, 2], '$minDistance' => 5, '$maxDistance' => 10], $expr->getQuery());
616+
}
617+
454618
public function testPullWithValue(): void
455619
{
456620
$expr = $this->createExpr();

0 commit comments

Comments
 (0)