如何使用搜索函数显示具有最近long/lat值的商店-Laravel 5雄辩


How to show stores with nearest long/lat values using search function - Laravel 5 eloquent

理想情况下,我正在寻找与Laravel 5相关的答案。我正在尝试制作一个商店定位器应用程序。我正试图将一对纬度/经度坐标(根据用户在搜索框中输入的地址计算)与数据库中最近的(半径100公里以内)坐标/现有存储进行匹配。

用户输入一个地址,该地址被转换(使用地理编码)为lat和lng坐标。这些都被发送到我的"文章"页面,其中有一个商店和商店的列表;谷歌地图。我使用了一个关于范围搜索的简单教程,根据它们的文本"地址"来显示我的文章/商店。但这显然不适用于两个坐标。我有一张名为文章的表格,上面有:id,地址,lat,lng,网站,标题等

我需要这样或这样的东西,但要用雄辩。

当前文章模型:

    public function scopeSearch($query, $search){
    return $query->where('address', 'LIKE', "%$search%" );
   }

物品管理员

 public function index(Request $request)
{
     $query = $request->get('q');
     $articles = $query
    ? Article::search($query)->get()
    : Article::all();
    return view('articles.index', compact('categories'))->withArticles($articles);
}

当前形式/地理编码:

    {!! Form::open(['method' => 'GET', 'id' => 'searchForm', 'name' => 'searchForm', 'route' => 'articles_path']) !!}
      {!! Form::input('search', 'q', null, ['placeholder' => 'LOCATION', 'class' => 'locationSearch', 'id' => 'searchInput'])!!}
      {!! Form::hidden('lat', null, ['id' => 'lat'])!!}
      {!! Form::hidden('lng', null, ['id' => 'lng'])!!}
      {!! Form::submit('MAKE ME HAPPY', array('id' => 'submitButton')) !!}
    {!! Form::close() !!}
 <script>
$('#submitButton').on('click', function(event){
    event.preventDefault();
    var address = $('#searchInput').val();
    geocoder = new google.maps.Geocoder();
    geocoder.geocode({
        'address': address
    }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
             var lat = results[0].geometry.location.lat();
             var lng = results[0].geometry.location.lng();
             $('#lat').val(lat);
             $('#lng').val(lng);
          $('#searchForm').submit();
        } else {
            alert("Geocode was not successful");
        }
    });
});
</script>  

我最终遵循了这个建议。我不知道这是否是一种"雄辩"的方式,但它有效。我只是不确定"距离"以及在那里该用什么。

文章型号:

public static function getByDistance($lat, $lng, $distance)
{
  $results = DB::select(DB::raw('SELECT id, ( 3959 * acos( cos( radians(' . $lat . ') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(' . $lng . ') ) + sin( radians(' . $lat .') ) * sin( radians(lat) ) ) ) AS distance FROM articles HAVING distance < ' . $distance . ' ORDER BY distance') );
  return $results;
}

物品管理员

    public function index(Request $request)
{
$lat = $request->get('lat');
$lng = $request->get('lng');
$distance = 1;
$query = Article::getByDistance($lat, $lng, $distance);
    if(empty($query)) {
      return view('articles.index', compact('categories'));
    }
    $ids = [];
    //Extract the id's
    foreach($query as $q)
    {
      array_push($ids, $q->id);
    }
    // Get the listings that match the returned ids
    $results = DB::table('articles')->whereIn( 'id', $ids)->orderBy('rating', 'DESC')->paginate(3);        
    $articles = $results;
    return view('articles.index', compact('categories'))->withArticles($articles);
}

更好的解决方案是将此函数用作作用域。比如:

文章模型:

public static function scopeGetByDistance($query,$lat, $lng, $distance)
{
  $results = DB::select(DB::raw('SELECT id, ( 3959 * acos( cos( radians(' . $lat . ') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(' . $lng . ') ) + sin( radians(' . $lat .') ) * sin( radians(lat) ) ) ) AS distance FROM articles HAVING distance < ' . $distance . ' ORDER BY distance') );
    if(!empty($results)) {
        $ids = [];
        //Extract the id's
        foreach($results as $q) {
           array_push($ids, $q->id);
        }
        return $query->whereIn('id',$ids);
    }
    return $query;
 }

物品管理员:

public function index(Request $request) {
    $lat = $request->get('lat');
    $lng = $request->get('lng');
    $distance = 1;
    $articles= Article::scope1()->scope2()->scope3()->GetByDistance($lat, $lng, $distance);
   return $articles; 
}

mySQL显然有一个本机函数来处理这个问题!https://tighten.co/blog/a-mysql-distance-function-you-should-know-about

public function scopeCloseTo(Builder $query, $latitude, $longitude)
{
    return $query->whereRaw("
       ST_Distance_Sphere(
            point(longitude, latitude),
            point(?, ?)
        ) * .000621371192 < delivery_max_range
    ", [
        $longitude,
        $latitude,
    ]);
}