Skip to content
Browse files

Merge pull request #171 from doctrine/mindistance-option

Implement $minDistance query operator and geoNear option
  • Loading branch information...
2 parents 4a75fa7 + 2b4f78b commit d23af82cbeae827360f3425eeff845493798ebbc @jmikola jmikola committed Apr 9, 2014
View
36 lib/Doctrine/MongoDB/Query/Builder.php
@@ -421,9 +421,9 @@ public function geoIntersects($geometry)
*
* This method sets the "near" option for the geoNear command. The "num"
* option may be set using {@link Expr::limit()}. The "distanceMultiplier",
- * "maxDistance", and "spherical" options may be set using their respective
- * builder methods. Additional query criteria will be assigned to the
- * "query" option.
+ * "maxDistance", "minDistance", and "spherical" options may be set using
+ * their respective builder methods. Additional query criteria will be
+ * assigned to the "query" option.
*
* @see http://docs.mongodb.org/manual/reference/command/geoNear/
* @param float|array|Point $x
@@ -873,6 +873,36 @@ public function maxDistance($maxDistance)
}
/**
+ * Set the "minDistance" option for a geoNear command query or add
+ * $minDistance criteria to the query.
+ *
+ * If the query is a geoNear command ({@link Expr::geoNear()} was called),
+ * the "minDistance" command option will be set; otherwise, $minDistance
+ * will be added to the current expression.
+ *
+ * If the query uses GeoJSON points, $minDistance will be interpreted in
+ * meters. If legacy point coordinates are used, $minDistance will be
+ * interpreted in radians.
+ *
+ * @see Expr::minDistance()
+ * @see http://docs.mongodb.org/manual/reference/command/geoNear/
+ * @see http://docs.mongodb.org/manual/reference/operator/minDistance/
+ * @see http://docs.mongodb.org/manual/reference/operator/near/
+ * @see http://docs.mongodb.org/manual/reference/operator/nearSphere/
+ * @param float $minDistance
+ * @return self
+ */
+ public function minDistance($minDistance)
+ {
+ if ($this->query['type'] === Query::TYPE_GEO_NEAR) {
+ $this->query['geoNear']['options']['minDistance'] = $minDistance;
+ } else {
+ $this->expr->minDistance($minDistance);
+ }
+ return $this;
+ }
+
+ /**
* Specify $mod criteria for the current field.
*
* @see Expr::mod()
View
37 lib/Doctrine/MongoDB/Query/Expr.php
@@ -537,6 +537,43 @@ public function maxDistance($maxDistance)
}
/**
+ * Set the $minDistance option for $near or $nearSphere criteria.
+ *
+ * This method must be called after near() or nearSphere(), since placement
+ * of the $minDistance option depends on whether a GeoJSON point or legacy
+ * coordinates were provided for $near/$nearSphere.
+ *
+ * @see http://docs.mongodb.org/manual/reference/operator/minDistance/
+ * @param float $minDistance
+ * @return self
+ * @throws BadMethodCallException if the query does not already have $near or $nearSphere criteria
+ */
+ public function minDistance($minDistance)
+ {
+ if ($this->currentField) {
+ $query = &$this->query[$this->currentField];
+ } else {
+ $query = &$this->query;
+ }
+
+ if ( ! isset($query['$near']) && ! isset($query['$nearSphere'])) {
+ throw new BadMethodCallException(
+ 'This method requires a $near or $nearSphere operator (call near() or nearSphere() first)'
+ );
+ }
+
+ if (isset($query['$near']['$geometry'])) {
+ $query['$near']['$minDistance'] = $minDistance;
+ } elseif (isset($query['$nearSphere']['$geometry'])) {
+ $query['$nearSphere']['$minDistance'] = $minDistance;
+ } else {
+ $query['$minDistance'] = $minDistance;
+ }
+
+ return $this;
+ }
+
+ /**
* Specify $mod criteria for the current field.
*
* @see Builder::mod()
View
14 tests/Doctrine/MongoDB/Tests/Query/BuilderTest.php
@@ -333,6 +333,7 @@ public function provideProxiedExprMethods()
'type()' => array('type', array(7)),
'all()' => array('all', array(array('value1', 'value2'))),
'maxDistance' => array('maxDistance', array(5)),
+ 'minDistance' => array('minDistance', array(5)),
'mod()' => array('mod', array(2, 0)),
'near()' => array('near', array(1, 2)),
'nearSphere()' => array('nearSphere', array(1, 2)),
@@ -457,6 +458,19 @@ public function testMaxDistanceWithGeoNearCommand()
$this->assertEquals($expected, $qb->debug('geoNear'));
}
+ public function testMinDistanceWithGeoNearCommand()
+ {
+ $expected = array(
+ 'near' => array(0, 0),
+ 'options' => array('spherical' => false, 'minDistance' => 5),
+ );
+
+ $qb = $this->getTestQueryBuilder();
+
+ $this->assertSame($qb, $qb->geoNear(0, 0)->minDistance(5));
+ $this->assertEquals($expected, $qb->debug('geoNear'));
+ }
+
/**
* @expectedException BadMethodCallException
*/
View
50 tests/Doctrine/MongoDB/Tests/Query/ExprTest.php
@@ -113,6 +113,56 @@ public function testMaxDistanceRequiresNearOrNearSphereOperator()
/**
* @dataProvider provideGeoJsonPoint
*/
+ public function testMinDistanceWithNearAndGeoJsonPoint($point, array $expected)
+ {
+ $expr = new Expr();
+ $expr->near($point);
+
+ $this->assertSame($expr, $expr->minDistance(1));
+ $this->assertEquals(array('$near' => $expected + array('$minDistance' => 1)), $expr->getQuery());
+ }
+
+ public function testMinDistanceWithNearAndLegacyCoordinates()
+ {
+ $expr = new Expr();
+ $expr->near(1, 2);
+
+ $this->assertSame($expr, $expr->minDistance(1));
+ $this->assertEquals(array('$near' => array(1, 2), '$minDistance' => 1), $expr->getQuery());
+ }
+
+ public function testMinDistanceWithNearSphereAndGeoJsonPoint()
+ {
+ $json = array('type' => 'Point', 'coordinates' => array(1, 2));
+
+ $expr = new Expr();
+ $expr->nearSphere($this->getMockPoint($json));
+
+ $this->assertSame($expr, $expr->minDistance(1));
+ $this->assertEquals(array('$nearSphere' => array('$geometry' => $json, '$minDistance' => 1)), $expr->getQuery());
+ }
+
+ public function testMinDistanceWithNearSphereAndLegacyCoordinates()
+ {
+ $expr = new Expr();
+ $expr->nearSphere(1, 2);
+
+ $this->assertSame($expr, $expr->minDistance(1));
+ $this->assertEquals(array('$nearSphere' => array(1, 2), '$minDistance' => 1), $expr->getQuery());
+ }
+
+ /**
+ * @expectedException BadMethodCallException
+ */
+ public function testMinDistanceRequiresNearOrNearSphereOperator()
+ {
+ $expr = new Expr();
+ $expr->minDistance(1);
+ }
+
+ /**
+ * @dataProvider provideGeoJsonPoint
+ */
public function testNearWithGeoJsonPoint($point, array $expected)
{
$expr = new Expr();

0 comments on commit d23af82

Please sign in to comment.
Something went wrong with that request. Please try again.