计算Laravel中的坐标距离

use*_*482 5 php mysql laravel eloquent laravel-5

我的模型中有一个范围,它创建了一个别名,我需要在其上执行where,我知道MySql不允许这样做.

标准SQL不允许您引用WHERE子句中的列别名.施加此限制是因为当执行WHERE代码时,可能尚未确定列值.

但是,我想知道是否有可能的laravel工作?我的范围创建了别名距离,我想检查距离.

public static function scopeDistance($query, $lat, $long)
{
    return $query->select(array('*',\DB::raw('( 3959 * acos( cos( radians(' . $lat . ') ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(' . $long . ') ) + sin( radians(' . $lat .') ) * sin( radians(latitude) ) ) ) AS distance')));
} 
Run Code Online (Sandbox Code Playgroud)

在我的控制器中:

\App\Profile::distance($latitude, $longitude)->where('distance', '<', 50);
Run Code Online (Sandbox Code Playgroud)

Dov*_*ski 5

首先,不要忘记static从函数调用中删除关键字,Laravel 处理神奇的静态 Profile::distance调用。

以下是解决同一问题的 2 个不同选项,无论哪种情况,您都可以\App\Profile::distance($latitude, $longitude, 50)从控制器进行调用。

选项1

您可以在内存中进行计算,而不用处理子查询。

public function scopeDistance($query, $lat, $long, $distance) {
    return Profile::all()->filter(function ($profile) use ($lat, $long, $distance) {
        $actual = 3959 * acos(
            cos(deg2rad($lat)) * cos(deg2rad($profile->latitude))
            * cos(deg2rad($profile->longitude) - deg2rad($long))
            + sin(deg2rad($lat)) * sin(deg2rad($profile->latitude))
        );
        return $distance < $actual;
    });
}
Run Code Online (Sandbox Code Playgroud)

选项2

您可以执行 SQL 子查询,请确保使用以下命令结束调用get()

public function scopeDistance($query, $lat, $long, $distance) {
    return $query->having('distance', '<', $distance)
             ->select(DB::raw("*,
                     (3959 * ACOS(COS(RADIANS($lat))
                           * COS(RADIANS(latitude))
                           * COS(RADIANS($long) - RADIANS(longitude))
                           + SIN(RADIANS($lat))
                           * SIN(RADIANS(latitude)))) AS distance")
             )->orderBy('distance', 'asc')
              ->get();
}
Run Code Online (Sandbox Code Playgroud)