Skip to content

Commit 34638fd

Browse files
authored
Add sort option to GeoQueries (#424)
1 parent d7b7c1a commit 34638fd

File tree

2 files changed

+137
-14
lines changed

2 files changed

+137
-14
lines changed

src/Parse/ParseQuery.php

+24-14
Original file line numberDiff line numberDiff line change
@@ -770,34 +770,46 @@ public function near($key, $point)
770770
* @param string $key The key of the ParseGeoPoint
771771
* @param ParseGeoPoint $point The ParseGeoPoint that is used.
772772
* @param int $maxDistance Maximum distance (in radians)
773+
* @param bool $sort Return objects sorted by distance
773774
*
774775
* @return ParseQuery Returns this query, so you can chain this call.
775776
*/
776-
public function withinRadians($key, $point, $maxDistance)
777+
public function withinRadians($key, $point, $maxDistance, $sort = true)
777778
{
778-
$this->near($key, $point);
779-
$this->addCondition($key, '$maxDistance', $maxDistance);
779+
if ($sort) {
780+
$this->near($key, $point);
781+
$this->addCondition($key, '$maxDistance', $maxDistance);
782+
} else {
783+
$this->addCondition(
784+
$key,
785+
'$geoWithin',
786+
[
787+
'$centerSphere' => [
788+
[$point->getLongitude(), $point->getLatitude()],
789+
$maxDistance
790+
]
791+
]
792+
);
793+
}
780794

781795
return $this;
782796
}
783797

784798
/**
785799
* Add a proximity based constraint for finding objects with key point
786800
* values near the point given and within the maximum distance given.
787-
* Radius of earth used is 3958.5 miles.
801+
* Radius of earth used is 3958.8 miles.
788802
*
789803
* @param string $key The key of the ParseGeoPoint
790804
* @param ParseGeoPoint $point The ParseGeoPoint that is used.
791805
* @param int $maxDistance Maximum distance (in miles)
806+
* @param bool $sort Return objects sorted by distance
792807
*
793808
* @return ParseQuery Returns this query, so you can chain this call.
794809
*/
795-
public function withinMiles($key, $point, $maxDistance)
810+
public function withinMiles($key, $point, $maxDistance, $sort = true)
796811
{
797-
$this->near($key, $point);
798-
$this->addCondition($key, '$maxDistance', $maxDistance / 3958.8);
799-
800-
return $this;
812+
return $this->withinRadians($key, $point, $maxDistance / 3958.8, $sort);
801813
}
802814

803815
/**
@@ -808,15 +820,13 @@ public function withinMiles($key, $point, $maxDistance)
808820
* @param string $key The key of the ParseGeoPoint
809821
* @param ParseGeoPoint $point The ParseGeoPoint that is used.
810822
* @param int $maxDistance Maximum distance (in kilometers)
823+
* @param bool $sort Return objects sorted by distance
811824
*
812825
* @return ParseQuery Returns this query, so you can chain this call.
813826
*/
814-
public function withinKilometers($key, $point, $maxDistance)
827+
public function withinKilometers($key, $point, $maxDistance, $sort = true)
815828
{
816-
$this->near($key, $point);
817-
$this->addCondition($key, '$maxDistance', $maxDistance / 6371.0);
818-
819-
return $this;
829+
return $this->withinRadians($key, $point, $maxDistance / 6371.0, $sort);
820830
}
821831

822832
/**

tests/Parse/ParseGeoPointTest.php

+113
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,119 @@ public function testGeoMaxDistanceWithUnits()
202202
$this->assertEquals(0, count($results));
203203
}
204204

205+
public function testGeoMaxDistanceWithUnitsUnsorted()
206+
{
207+
Helper::clearClass('PlaceObject');
208+
// [SAC] 38.52 -121.50 Sacramento,CA
209+
$sacramento = new ParseGeoPoint(38.52, -121.50);
210+
$obj = ParseObject::create('PlaceObject');
211+
$obj->set('location', $sacramento);
212+
$obj->set('name', 'Sacramento');
213+
$obj->save();
214+
215+
// [HNL] 21.35 -157.93 Honolulu Int,HI
216+
$honolulu = new ParseGeoPoint(21.35, -157.93);
217+
$obj = ParseObject::create('PlaceObject');
218+
$obj->set('location', $honolulu);
219+
$obj->set('name', 'Honolulu');
220+
$obj->save();
221+
222+
// [51Q] 37.75 -122.68 San Francisco,CA
223+
$sanfran = new ParseGeoPoint(37.75, -122.68);
224+
$obj = ParseObject::create('PlaceObject');
225+
$obj->set('location', $sanfran);
226+
$obj->set('name', 'San Francisco');
227+
$obj->save();
228+
229+
// test point SFO
230+
$point = new ParseGeoPoint(37.6189722, -122.3748889);
231+
232+
// Kilometers
233+
// baseline all
234+
$query = new ParseQuery('PlaceObject');
235+
$query->near('location', $point);
236+
$results = $query->find();
237+
$this->assertEquals(3, count($results));
238+
239+
// max with all
240+
$query = new ParseQuery('PlaceObject');
241+
$query->withinKilometers('location', $point, 4000.0, false);
242+
$results = $query->find();
243+
$this->assertEquals(3, count($results));
244+
245+
// drop hawaii
246+
$query = new ParseQuery('PlaceObject');
247+
$query->withinKilometers('location', $point, 3700.0, false);
248+
$results = $query->find();
249+
$this->assertEquals(2, count($results));
250+
251+
// drop sacramento
252+
$query = new ParseQuery('PlaceObject');
253+
$query->withinKilometers('location', $point, 100.0, false);
254+
$results = $query->find();
255+
$this->assertEquals(1, count($results));
256+
$this->assertEquals('San Francisco', $results[0]->get('name'));
257+
258+
// drop SF
259+
$query = new ParseQuery('PlaceObject');
260+
$query->withinKilometers('location', $point, 10.0, false);
261+
$results = $query->find();
262+
$this->assertEquals(0, count($results));
263+
264+
// Miles
265+
// max with all
266+
$query = new ParseQuery('PlaceObject');
267+
$query->withinMiles('location', $point, 2500.0, false);
268+
$results = $query->find();
269+
$this->assertEquals(3, count($results));
270+
271+
// drop hawaii
272+
$query = new ParseQuery('PlaceObject');
273+
$query->withinMiles('location', $point, 2200.0, false);
274+
$results = $query->find();
275+
$this->assertEquals(2, count($results));
276+
277+
// drop sacramento
278+
$query = new ParseQuery('PlaceObject');
279+
$query->withinMiles('location', $point, 75.0, false);
280+
$results = $query->find();
281+
$this->assertEquals(1, count($results));
282+
$this->assertEquals('San Francisco', $results[0]->get('name'));
283+
284+
// drop SF
285+
$query = new ParseQuery('PlaceObject');
286+
$query->withinMiles('location', $point, 10.0, false);
287+
$results = $query->find();
288+
$this->assertEquals(0, count($results));
289+
}
290+
291+
public function testGeoQueriesUnsorted()
292+
{
293+
Helper::clearClass('PlaceObject');
294+
$sacramento = new ParseGeoPoint(38.52, -121.50);
295+
$obj = ParseObject::create('PlaceObject');
296+
$obj->set('location', $sacramento);
297+
$obj->set('name', 'Sacramento');
298+
$obj->save();
299+
300+
$point = new ParseGeoPoint(37.6189722, -122.3748889);
301+
302+
$query = new ParseQuery('PlaceObject');
303+
$query->withinRadians('location', $point, 3.14 * 2, false);
304+
$this->assertEquals($query->_getOptions(), [
305+
'where' => [
306+
'location' => [
307+
'$geoWithin' => [
308+
'$centerSphere' => [
309+
[-122.3748889, 37.6189722],
310+
3.14 * 2
311+
]
312+
]
313+
]
314+
]
315+
]);
316+
}
317+
205318
public function testBadLatitude()
206319
{
207320
$this->setExpectedException(

0 commit comments

Comments
 (0)