Skip to content

Instantly share code, notes, and snippets.

@fhferreira
Last active January 19, 2021 14:44
Show Gist options
  • Save fhferreira/9081607 to your computer and use it in GitHub Desktop.
Save fhferreira/9081607 to your computer and use it in GitHub Desktop.
Haversine Method for model Laravel.
<?php
/*
* find the n closest locations
* @param Model $query eloquent model
* @param float $lat latitude of the point of interest
* @param float $lng longitude of the point of interest
* @param float $max_distance distance in miles or km
* @param string $units miles or kilometers
* @param Array $fiels to return
* @return array
*/
public static function haversine($query, $lat, $lng, $max_distance = 25, $units = 'miles', $fields = false )
{
if(empty($lat)){
$lat = 0;
}
if(empty($lng)){
$lng = 0;
}
/*
* Allow for changing of units of measurement
*/
switch ( $units ) {
case 'miles':
//radius of the great circle in miles
$gr_circle_radius = 3959;
break;
case 'kilometers':
//radius of the great circle in kilometers
$gr_circle_radius = 6371;
break;
}
/*
* Support the selection of certain fields
*/
if( ! $fields ) {
$fields = array( 'users.*', 'users_profile.*', 'users.username as user_name' );
}
/*
* Generate the select field for disctance
*/
$distance_select = sprintf(
"
ROUND(( %d * acos( cos( radians(%s) ) " .
" * cos( radians( lat ) ) " .
" * cos( radians( lng ) - radians(%s) ) " .
" + sin( radians(%s) ) * sin( radians( lat ) ) " .
" ) " .
")
, 2 ) " .
"AS distance
",
$gr_circle_radius,
$lat,
$lng,
$lat
);
$data = $query->select( DB::raw( implode( ',' , $fields ) . ',' . $distance_select ) )
->having( 'distance', '<=', $max_distance )
->orderBy( 'distance', 'ASC' )
->get();
//echo '<pre>';
//echo $query->toSQL();
//echo $distance_select;
//echo '</pre>';
//die();
//
//$queries = DB::getQueryLog();
//$last_query = end($queries);
//var_dump($last_query);
//die();
return $data;
}
@vesper8
Copy link

vesper8 commented Feb 18, 2018

works like a charm!

$results = $mapHelpers->haversine(new Place(), $user->place->lat, $user->place->lng, 1000, 'kilometers', ['places.*']);

However I would like to know how to use this if I want to get the "nearest users" and the user table itself does not contain lat/lng values but instead there is a relation between User and Place on place_id field

How would I use this with such a relation in place?

@cimons
Copy link

cimons commented May 29, 2018

How can I use paginate()

@fhferreira
Copy link
Author

How can I use paginate()

change the ->get() for ->paginate(15) it should works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment