在Eloquent中使用预先加载的查询和过滤计算列

mdk*_*mdk 4 laravel eloquent

我目前有三个模型,其中有一个使用预先加载的Eloquent查询.我的模型有这些关系:

class Template extends Eloquent {
    public function user() {
        return $this->belongsTo('User');
    }
}

class User extends Eloquent implements UserInterface, RemindableInterface {
    public function profiles() {
        return $this->hasMany('Profile');
    }
    public function templates() {
        return $this->hasMany('Template');
    }
}

class Profile extends Eloquent {
    public function user() {
        return $this->belongsTo('User');
    }
}
Run Code Online (Sandbox Code Playgroud)

我的工作查询如下所示:

$templates = Template::with('user', 'user.profiles')
    ->where('public', '=', true)
    ->whereIn('type', $search_types)
    ->where('user_id', '!=', $user->id)
    ->paginate(8);
Run Code Online (Sandbox Code Playgroud)

这似乎工作得很好,但我还需要补充一点,这对我来说很难做到.我需要更改此查询,以使用表中的现有列latlong列来考虑模板用户与当前用户的距离user.我只希望查询返回用户在当前用户25英里范围内的模板(理想情况是按距离排序,但该部分是可选的).

我试图将自定义计算列添加到用户关系中,如下所示:

$templates = Template::with(array('user' => function($query) use($user) {
        $query->select('*')->selectRaw('(3959 * acos(cos(radians(?)) * cos(radians(lat)) * cos(radians(long) - radians(?)) + sin(radians(?)) * sin(radians(lat)))) AS distance', array($user->lat, $user->long, $user->lat));
    }, 'user.profiles' => function($query) {
        $query
    }))
    ->where('public', '=', true)
    ->whereIn('type', $search_types)
    ->where('user_id', '!=', $user->id)
    ->having('distance', '<=', 25)
    ->orderBy('distance')
    ->paginate(8);
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为通过急切加载,distance初始查询中不存在该列,导致该having子句失败.如果我将该部分移动到匿名函数并删除顺序,它不会立即失败,但它只是忽略模板查询的距离,然后只抓取25英里内的相关用户,这似乎不是很有帮助.

使用Eloquent获取我追踪的数据的正确方法是什么?

mdk*_*mdk 5

我最终得到了以下(没有可选的排序),这似乎运作得很好:

$templates = Template::with('user', 'user.profiles')
    ->where('public', '=', true)
    ->whereIn('type', $search_types)
    ->where('user_id', '!=', $user->id)
    ->whereHas('user', function($query) use($user, $distance) {
        $query->whereRaw('(3959 * acos(cos(radians(?)) * cos(radians(location_lat)) * cos(radians(location_long) - radians(?)) + sin(radians(?)) * sin(radians(location_lat)))) <= ?', array($user->location_lat, $user->location_long, $user->location_lat, $distance));
    })
    ->paginate(8);
Run Code Online (Sandbox Code Playgroud)