Skip to content

Commit 60750a8

Browse files
committed
Merge pull request geocoder-php#28 from smhg/master
withDistance query method
2 parents fb9d415 + e82bd38 commit 60750a8

File tree

5 files changed

+89
-31
lines changed

5 files changed

+89
-31
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Basically, the behavior will add:
3636
* two new columns to your model (`latitude` and `longitude`);
3737
* four new methods to the _ActiveRecord_ API (`getDistanceTo()`, `isGeocoded()`,
3838
`getCoordinates()`, and `setCoordinates()`);
39-
* two new methods to the _ActiveQuery_ API (`filterByDistanceFrom()`,
39+
* three new methods to the _ActiveQuery_ API (`withDistance()`, `filterByDistanceFrom()`,
4040
`filterNear()`).
4141

4242

@@ -58,6 +58,18 @@ and longitude values.
5858

5959
### ActiveQuery API ###
6060

61+
`withDistance()` takes three arguments:
62+
63+
* a latitude value;
64+
* a longitude value;
65+
* a measure unit (`KILOMETERS_UNIT`, `MILES_UNIT`, or `NAUTICAL_MILES_UNIT`
66+
defined in the `Peer` class of the geocoded model);
67+
68+
It will add a `Distance` column on your current query and returns itself for
69+
fluid interface.
70+
Example use: combine with `orderByDistance()` and `limit()` to return closest
71+
matches.
72+
6173
`filterByDistanceFrom()` takes five arguments:
6274

6375
* a latitude value;

src/GeocodableBehaviorQueryBuilderModifier.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,21 @@ public function __construct(Behavior $behavior)
2929
public function queryMethods($builder)
3030
{
3131
$script = '';
32+
$script .= $this->addWithDistance($builder);
3233
$script .= $this->addFilterByDistanceFrom($builder);
3334
$script .= $this->addFilterNear($builder);
3435

3536
return $script;
3637
}
3738

38-
public function addFilterByDistanceFrom($builder)
39+
public function addWithDistance($builder)
3940
{
40-
$table = $this->behavior->getTable();
41-
foreach ($table->getColumns() as $col) {
42-
if ($col->isPrimaryKey()) {
43-
$pks[] = "\$this->getModelAliasOrName().'.".$col->getPhpName()."'";
44-
}
45-
}
46-
4741
$builder->declareClass('Criteria', 'PDO');
4842

4943
$queryClassName = $builder->getStubQueryBuilder()->getClassname();
5044
$peerClassName = $builder->getStubPeerBuilder()->getClassname();
5145

52-
return $this->behavior->renderTemplate('queryFilterByDistanceFrom', array(
46+
return $this->behavior->renderTemplate('queryWithDistance', array(
5347
'queryClassName' => $queryClassName,
5448
'defaultUnit' => $this->getDefaultUnit($builder),
5549
'peerClassName' => $peerClassName,
@@ -58,6 +52,18 @@ public function addFilterByDistanceFrom($builder)
5852
));
5953
}
6054

55+
public function addFilterByDistanceFrom($builder)
56+
{
57+
$builder->declareClass('Criteria', 'PDO');
58+
59+
$queryClassName = $builder->getStubQueryBuilder()->getClassname();
60+
61+
return $this->behavior->renderTemplate('queryFilterByDistanceFrom', array(
62+
'queryClassName' => $queryClassName,
63+
'defaultUnit' => $this->getDefaultUnit($builder)
64+
));
65+
}
66+
6167
public function addFilterNear($builder)
6268
{
6369
$builder->declareClassFromBuilder($builder->getStubObjectBuilder());

src/templates/queryFilterByDistanceFrom.php

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,8 @@
1212
*/
1313
public function filterByDistanceFrom($latitude, $longitude, $distance, $unit = <?php echo $defaultUnit ?>, $comparison = Criteria::LESS_THAN)
1414
{
15-
if (<?php echo $peerClassName ?>::MILES_UNIT === $unit) {
16-
$earthRadius = 3959;
17-
} elseif (<?php echo $peerClassName ?>::NAUTICAL_MILES_UNIT === $unit) {
18-
$earthRadius = 3440;
19-
} else {
20-
$earthRadius = 6371;
21-
}
22-
23-
$sql = 'ABS(%s * ACOS(%s * COS(RADIANS(%s)) * COS(RADIANS(%s) - %s) + %s * SIN(RADIANS(%s))))';
24-
$preparedSql = sprintf($sql,
25-
$earthRadius,
26-
cos(deg2rad($latitude)),
27-
$this->getAliasedColName(<?php echo $latitudeColumnConstant ?>),
28-
$this->getAliasedColName(<?php echo $longitudeColumnConstant ?>),
29-
deg2rad($longitude),
30-
sin(deg2rad($latitude)),
31-
$this->getAliasedColName(<?php echo $latitudeColumnConstant ?>)
32-
);
33-
3415
return $this
35-
->withColumn($preparedSql, 'Distance')
36-
->where(sprintf('%s %s ?', $preparedSql, $comparison), $distance, PDO::PARAM_STR)
16+
->withDistance($latitude, $longitude, $unit)
17+
->where(sprintf('Distance %s ?', $comparison), $distance, PDO::PARAM_STR)
3718
;
3819
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
/**
3+
* Adds distance from a given origin column to query.
4+
*
5+
* @param double $latitude The latitude of the origin point.
6+
* @param double $longitude The longitude of the origin point.
7+
* @param double $unit The unit measure.
8+
*
9+
* @return <?php echo $queryClassName ?> The current query, for fluid interface
10+
*/
11+
public function withDistance($latitude, $longitude, $unit = <?php echo $defaultUnit ?>)
12+
{
13+
if (<?php echo $peerClassName ?>::MILES_UNIT === $unit) {
14+
$earthRadius = 3959;
15+
} elseif (<?php echo $peerClassName ?>::NAUTICAL_MILES_UNIT === $unit) {
16+
$earthRadius = 3440;
17+
} else {
18+
$earthRadius = 6371;
19+
}
20+
21+
$sql = 'ABS(%s * ACOS(%s * COS(RADIANS(%s)) * COS(RADIANS(%s) - %s) + %s * SIN(RADIANS(%s))))';
22+
$preparedSql = sprintf($sql,
23+
$earthRadius,
24+
cos(deg2rad($latitude)),
25+
$this->getAliasedColName(<?php echo $latitudeColumnConstant ?>),
26+
$this->getAliasedColName(<?php echo $longitudeColumnConstant ?>),
27+
deg2rad($longitude),
28+
sin(deg2rad($latitude)),
29+
$this->getAliasedColName(<?php echo $latitudeColumnConstant ?>)
30+
);
31+
32+
return $this
33+
->withColumn($preparedSql, 'Distance');
34+
}

tests/GeocodableBehaviorTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ public function testObjectMethods()
145145

146146
public function testQueryMethods()
147147
{
148+
$this->assertTrue(method_exists('GeocodedObjectQuery', 'withDistance'));
148149
$this->assertTrue(method_exists('GeocodedObjectQuery', 'filterByDistanceFrom'));
149150
$this->assertTrue(method_exists('GeocodedObjectQuery', 'filterNear'));
150151
}
@@ -224,6 +225,30 @@ public function testIsGeocoded()
224225
$this->assertTrue($obj->isGeocoded());
225226
}
226227

228+
public function testWithDistanceAddsColumn()
229+
{
230+
GeocodedObjectPeer::doDeleteAll();
231+
232+
$geo1 = new GeocodedObject();
233+
$geo1->setName('Aulnat Area');
234+
$geo1->setCity('Aulnat');
235+
$geo1->setCountry('France');
236+
$geo1->save();
237+
238+
$geo2 = new GeocodedObject();
239+
$geo2->setName('Lyon Area');
240+
$geo2->setCity('Lyon');
241+
$geo2->setCountry('France');
242+
$geo2->save();
243+
244+
$object = GeocodedObjectQuery::create()
245+
->withDistance($geo1->getLatitude(), $geo1->getLongitude())
246+
->filterByName('Lyon Area')
247+
->findOne()
248+
;
249+
$this->assertTrue((float)$object->getDistance() > 0);
250+
}
251+
227252
public function testFilterByDistanceFromReturnsNoObjects()
228253
{
229254
GeocodedObjectPeer::doDeleteAll();

0 commit comments

Comments
 (0)