How to use named bindings with laravel's query builder?

时间:2016-08-31 17:13:16

标签: php sql laravel eloquent

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?

2 个答案:

答案 0 :(得分:1)

我相信你的意思是使用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]);
    }
}

用法:

$latitude = 0.0;
$longitude = 180.0;
MyModel::sqlDistanceTo($latitude, $longitude)->get();

答案 1 :(得分:0)

tl; dr 如果可能,请使用Skysplit's solution

这是我想出的。另一个复杂因素是默认情况下laravel disables pdo的仿真模式。这导致无法在语句中多次使用同名的命名参数标记。

$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);
}