2016-08-31 8 views
3

私は、次の操作を実行したいと思います:laravelのクエリビルダで名前付きバインディングを使用するにはどうすればよいですか?

sql_distance_to()はいくつかの複雑なSQL式を返し
MyModel::where(MyModel::sql_distance_to(), ['lat' => '...', 'lng' => '...'])->get(); 

。しかし、私は見ることができますが、クエリビルダーは名前付きバインディングをサポートしていません。これは本当ですか?回避策はありますか?

答えて

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

良い点。しかし、DB :: rawで式を囲む必要はありません。 –

+0

@ x-yuriああ、もちろん! :) あなたが正しい。大きなものではありませんが、変わる価値があります。ありがとう! – Skysplit

0

TL; DR使用Skysplit's solutionを、可能な場合。

ここで私が思いついたのです。さらに複雑な問題の1つは、デフォルトでlaravelがdisablespdoのエミュレーションモードです。同じ名前の名前付きパラメーター・マーカーをステートメント内で複数回使用することはできません。

$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); 
} 
関連する問題