Reputation: 18873
I'd like to do the following:
MyModel::where(MyModel::sql_distance_to(), ['lat' => '...', 'lng' => '...'])->get();
Where sql_distance_to()
returns some complex sql expression. But from what I can see, query builder doesn't support named bindings. Is this true? Any workaround?
Upvotes: 3
Views: 2913
Reputation: 1943
I belive you mean using Query Scopes
class MyModel extends Model
{
public function scopeSqlDistanceTo($query, $lat, $lon)
{
// Previously DB::raw(expr) was here.
// No need since we're using whereRaw()
$whereRaw = 'lat = ? AND lon = ?';
return $query->whereRaw($whereRaw, [$lat, $lon]);
}
}
Usage:
$latitude = 0.0;
$longitude = 180.0;
MyModel::sqlDistanceTo($latitude, $longitude)->get();
Upvotes: 1
Reputation: 18873
tl;dr Use Skysplit's solution, if possible.
Here's what I came up with. One additional complication is that laravel by default disables pdo
's emulation mode. Which results in being unable to use a named parameter marker of the same name more than once in a statement.
$q = MyModel::whereRaw(MyModel::sql_distance_to() . ' < :dist');
run_query_with_params(MyModel::class, $q,
array_merge(MyModel::sql_distance_to_params($lat, $lng), [
'dist' => 10,
]));
class MyModel {
static function sql_distance_to() {
return 'ACOS(
SIN(RADIANS(lat)) * SIN(RADIANS(:lat1))
+ COS(RADIANS(lat)) * COS(RADIANS(:lat2))
* COS(RADIANS(:lng - lng))
) * 6371';
}
static function sql_distance_to_params($lat, $lng) {
return [
'lat1' => $lat,
'lat2' => $lat,
'lng' => $lng,
];
}
}
function run_query_with_params($class, $q, $params)
{
$r = \DB::select($q->toSql(), $params);
return call_user_func([$class, 'hydrate'], $r);
}
Upvotes: 0