DEV Community

JohnDivam
JohnDivam

Posted on

Laravel Scope to get locations nearest the user location

In many web applications, particularly those that involve mapping or location-based services, it is crucial to retrieve and display locations closest to a user's current position .

When dealing with geographical coordinates, calculating the distance between two points on the Earth's surface can be complex due to the spherical nature of the Earth. The Haversine formula is commonly used for this purpose. It calculates the distance between two points on a sphere given their longitudes and latitudes.

Setting Up the Scope

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Farm extends Model
{

    public function scopeClosest($query, $lat, $long)
    {
        $distanceQuery = "
            ( 6371 * acos( cos( radians(?) ) *
            cos( radians( farms.lat ) )
            * cos( radians( farms.long ) - radians(?) )
            + sin( radians(?) ) *
            sin( radians( farms.lat ) ) ) )
            AS distance
        ";

        return $query->select('farms.*')
            ->selectRaw($distanceQuery, [$lat, $long, $lat])
            ->orderBy('distance', 'asc');
    }
}
Enter fullscreen mode Exit fullscreen mode

Breaking Down the Scope

SQL Query: The Haversine formula is used within a raw SQL query to calculate the distance.
6371 is the Earth's radius in kilometers. If you need the distance in miles, replace it with 3959.
radians(?) converts degrees to radians for the latitude and longitude.
selectRaw: This method allows us to include raw expressions in our query. The placeholders (?) are replaced with the provided latitude and longitude values.
orderBy: Finally, we sort the results by the calculated distance in ascending order, so the closest farms appear first.

Using the Scope

$lat = 37.7749;  // User's latitude or use $request->lat
$long = -122.4194;  // User's longitude or use $request->long

$nearestFarm = Farm::closest($lat, $long)->first();
Enter fullscreen mode Exit fullscreen mode

This query will return a collection of Farm models ordered by their proximity to the user's location.

Top comments (2)

Collapse
 
ionbazan profile image
Ion Bazan

You can simplify these calculations with ST_Distance_Sphere which returns the distance in km or miles/feet: dev.mysql.com/doc/refman/8.4/en/sp...
Make sure you have an spatial index in your table if you want to sort by it.

Collapse
 
benyaminrmb profile image
BenyaminRmb

nice