Laravel 5 Eloquent:关联User模型时添加计算距离列失败
解决User模型关联Teacher时距离计算失效的问题
嗨,我懂你遇到的麻烦了——直接查Teacher模型能正常算出到学校的距离,但通过User模型关联查询时这逻辑就失效了。核心原因很简单:你直接查Teacher的时候主动加了距离计算的逻辑,但用User的with('userable')关联时,并没有把这个计算逻辑同步带到关联的Teacher查询里,所以结果里自然没有距离字段。
下面给你两种实用的解决方案,按需选择就行:
方案一:在关联查询闭包里嵌入距离计算逻辑
这种方法保留Eloquent关联的特性,通过with的闭包给关联的Teacher查询补上计算逻辑:
$query = User::where('userable_type', 'App\Teacher'); // 先校验学校经纬度是否有效,避免无效计算报错 if (!empty($school->latitude) && !empty($school->longitude)) { $schoolLat = $school->latitude; $schoolLng = $school->longitude; // 给userable关联的Teacher查询添加距离计算 $query->with(['userable' => function ($teacherQuery) use ($schoolLat, $schoolLng) { // 这里用MySQL空间函数计算球面距离,替换成你原来用的计算逻辑就行 $teacherQuery->selectRaw( '*, ST_Distance_Sphere(POINT(longitude, latitude), POINT(?, ?)) AS distance', [$schoolLng, $schoolLat] )->orderBy('distance'); // 按需添加距离排序 }]); } else { \Session::flash('warning', '学校经纬度未设置,无法计算教师到学校的距离'); $query->with('userable'); // 不计算距离,仅关联Teacher基础数据 } // 获取最终结果 $users = $query->get();
之后你就能通过$user->userable->distance拿到计算好的距离值了。
方案二:通过Join直接关联User与Teacher表
如果不需要懒加载特性,也可以直接Join两张表,在主查询里直接计算距离:
$query = User::where('userable_type', 'App\Teacher'); if (!empty($school->latitude) && !empty($school->longitude)) { $schoolLat = $school->latitude; $schoolLng = $school->longitude; $query->join('teachers', 'users.userable_id', '=', 'teachers.id') ->selectRaw( 'users.*, teachers.*, ST_Distance_Sphere(POINT(teachers.longitude, teachers.latitude), POINT(?, ?)) AS distance', [$schoolLng, $schoolLat] )->orderBy('distance'); } else { \Session::flash('warning', '学校经纬度未设置,无法计算教师到学校的距离'); $query->with('userable'); } $users = $query->get();
这种方式下,距离字段会直接挂载在User模型结果上,你可以通过$user->distance直接获取。
补充:兼容不支持空间函数的数据库
如果你的数据库不支持ST_Distance_Sphere,可以用经典的Haversine公式计算距离(单位为公里,换成英里就把6371改成3956),把selectRaw内容替换为:
users.*, teachers.*, (6371 * acos(cos(radians(?)) * cos(radians(teachers.latitude)) * cos(radians(teachers.longitude) - radians(?)) + sin(radians(?)) * sin(radians(teachers.latitude)))) AS distance
对应的参数是[$schoolLat, $schoolLng, $schoolLat]。
内容的提问来源于stack exchange,提问作者user3467896
相关产品推荐
相关产品推荐

