Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bwrigley's avatar

Adding data to a model in a query scope

I'm sure I'm going about this all the wrong way so happy to be told the right way!

I have two model User and Address. One to Many.

I have a query that returns me all Users in a certain area by finding all Users attached to an Address in that area. Great.

Now I want those results ordered by the nearest first. Obviously the User and the Address don't have a convenient ->distance property to order by because that depends on the search.

I'm wondering if the best thing to do would be, somehow, somewhere, add a temporary property to the results that are returned. This means calculating the actual distance of each match and adding it somehow.

This must have been done loads of times before, but I'm not finding it, which means I'm asking the question wrong :)

0 likes
8 replies
cmdobueno's avatar

If it were me, Id geolocate with google maps api or something similar to get the lat longs. From there you could use one of the multiple solutions here

https://stackoverflow.com/questions/1006654/fastest-way-to-find-distance-between-two-lat-long-points

Using a bit of a custom query you could probably append this data on to your results. Cant really type out a full solution right now, but that should hopefully get you started. (As long as I understood the question and your intent)

bwrigley's avatar

Yes all understood except its the appending to the results I can't figure out.

The rest I have working :)

martinbean's avatar
Level 80

@bwrigley You either need to do the distance calculation (using the haversine formula) in the query, or sort your collection after retrieving your results:

$addresses = Address::all()->sortBy(function ($address) use ($latitude, $longitude) {
    // Calculate and return distance here
});

You probably want to query addresses, group by user, and then grab the users from those results:

class Address extends Model
{
    public function scopeOrderByDistanceFrom($query, $latitude, $longitude)
    {
        $latitude = (float) $latitude;
        $longitude = (float) $longitude;

        return $query->addSelect(DB::raw("(3959 * acos(cos(radians({$latitude})) * cos(radians(lat)) * cos(radians(lng) -
 radians({$longitude})) + sin(radians({$latitude})) * sin(radians(lat)))) as distance"))
            ->having('distance', '<', 25);
    }
}
$addresses = Address::orderByDistanceFrom($latitude, $longitude)
                    ->groupBy('user_id')
                    ->get();

// Return a collection of users, sorted by address distance
$users = $addresses->pluck('user');
1 like
zion's avatar

If you want to add something by default you can create an accessor and append it.

Define a protected $appends['something']; in your model and create an accessor for it;

public function getSomethingAttribute()
{
    // Do something
}
bwrigley's avatar

Thank you.

@getupkid and @zion

If I understand correctly an accessor can't take additional arguments? If that's not the case, how do you pass arguments in?

@martinbean

So you would come from the Address model and look up the Users and bypass laravel's orm?

martinbean's avatar

So you would come from the Address model and look up the Users and bypass laravel's orm?

@bwrigley I’m not sure I follow. Yes, I’d go through the Address model (because that’s the entity that’ll have the latitude and longitude values to compare) but the Address model is an Eloquent model, so there’s no “bypassing” of Laravel’s ORM.

bwrigley's avatar

Sorry I phrased that badly. I meant bypass what Laravel seem to say about running the search through the parent model.

e.g. I want to find all Users who have an Address with a proximity to y. I thought the Laravel way was to find Users whereHas() matching Address?

Please or to participate in this conversation.