2017-05-31 215 views
2

我在我的模型中创建了一个范围,它创建一个别名,我需要执行它的位置,我明白MySql不允许这样做。在Laravel中计算坐标距离

标准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'))); 
} 

在我的控制器:

\App\Profile::distance($latitude, $longitude)->where('distance', '<', 50); 

回答

3

首先,不要忘记在函数调用神奇静态看Profile::distance呼叫删除static关键字,Laravel交易。

以下是解决相同问题的两种不同选项,无论哪种情况,您都可以从控制器中拨打\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; 
    }); 
} 

选项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(); 
}