Laravel Eloquent - 如何 return 范围查询内的计算值作为模型列或集合 属性
Laravel Eloquent - How to return a calculated value inside a scope query as a model column or collection property
我正在尝试使用 Laravel 的 Eloquent 获取经过身份验证的用户附近的用户列表以及 return 他们之间的距离。我使用原始 SQL 让它工作,但现在我几乎可以使用 eloquent.
使其正常工作
所以,在用户模型上我有这个方法:
public function getUsersAround($coordinates, $radius = 5)
{
return $this->whereHas('location', function ($query) use ($coordinates, $radius) {
$query->distance($coordinates, $radius);
})->paginate(10);
}
然后在 Location 模型上,我有以下范围:
public function scopeDistance($query, $coordinates, $radius)
{
return $query
->join('profiles', 'profiles.id', '=', 'locations.profile_id')
->having('distance', '<', $radius)
->selectRaw("profile_id,
(6371 * ACOS(COS(RADIANS($coordinates->latitude))
* COS(RADIANS(latitude))
* COS(RADIANS(longitude) - RADIANS($coordinates->coordinates))
+ SIN(RADIANS($coordinates->latitude))
* SIN(RADIANS(latitude)))) AS distance")
->orderBy('distance', 'asc');
}
因此,半径内的所有用户都被正确 returned,但我还想将计算的距离添加到每个 returned 用户。
奇怪的是,如果我 dd($query->distance($coordinates, $radius));
我看到所有用户 + 每个用户对象的新距离 属性(具有正确的值),但如果我只是 return控制器内的查询和 dd(auth()->user()->getUsersAround($coordinates, $radius))
,距离 属性 不存在了。
有没有办法 return 在范围查询内计算出的距离,并在 return 用户列表时将其保存在用户对象上?
谢谢!
那是因为您在范围 内使用 get(),这是不正确的。本地范围旨在定义通用的约束集(例如用于过滤数据)。
查看 local scopes 上的文档了解更多详情。
要向 select 结果添加内容,您可以使用 addSelect.
如果要在结果中包含距离,则需要使用 distance
属性加载 location
关系。由于您已经在 Location 模型的查询范围内 selecting distance
,因此您可以很容易地实现这一点:
public function getUsersAround($coordinates, $radius = 5)
{
return $this->whereHas('location', function ($query) use ($coordinates, $radius) {
$query->distance($coordinates, $radius);
})->with([
'location' => function ($query) use ($coordinates, $radius) {
$query->select('locations.*')->distance($coordinates, $radius);
}
])->paginate(10);
}
注意 with('location')
,它急切地加载 Location 模型。我添加了一个 select('locations.*')
以便 location
关系将具有自己的属性,并且 distance($coordinates, $radius)
也将 select profile_id
和 distance
属性。
因此,当您在控制器中调用 auth()->user()->getUsersAround($coordinates, $radius)
时,您可以使用 $user->location->distance
:
访问 distance
属性
$users = auth()->user()->getUsersAround($coordinates, $radius);
foreach ($users as $user) {
$distance = $user->location->distance;
}
我正在尝试使用 Laravel 的 Eloquent 获取经过身份验证的用户附近的用户列表以及 return 他们之间的距离。我使用原始 SQL 让它工作,但现在我几乎可以使用 eloquent.
使其正常工作所以,在用户模型上我有这个方法:
public function getUsersAround($coordinates, $radius = 5)
{
return $this->whereHas('location', function ($query) use ($coordinates, $radius) {
$query->distance($coordinates, $radius);
})->paginate(10);
}
然后在 Location 模型上,我有以下范围:
public function scopeDistance($query, $coordinates, $radius)
{
return $query
->join('profiles', 'profiles.id', '=', 'locations.profile_id')
->having('distance', '<', $radius)
->selectRaw("profile_id,
(6371 * ACOS(COS(RADIANS($coordinates->latitude))
* COS(RADIANS(latitude))
* COS(RADIANS(longitude) - RADIANS($coordinates->coordinates))
+ SIN(RADIANS($coordinates->latitude))
* SIN(RADIANS(latitude)))) AS distance")
->orderBy('distance', 'asc');
}
因此,半径内的所有用户都被正确 returned,但我还想将计算的距离添加到每个 returned 用户。
奇怪的是,如果我 dd($query->distance($coordinates, $radius));
我看到所有用户 + 每个用户对象的新距离 属性(具有正确的值),但如果我只是 return控制器内的查询和 dd(auth()->user()->getUsersAround($coordinates, $radius))
,距离 属性 不存在了。
有没有办法 return 在范围查询内计算出的距离,并在 return 用户列表时将其保存在用户对象上?
谢谢!
那是因为您在范围 内使用 get(),这是不正确的。本地范围旨在定义通用的约束集(例如用于过滤数据)。 查看 local scopes 上的文档了解更多详情。
要向 select 结果添加内容,您可以使用 addSelect.
如果要在结果中包含距离,则需要使用 distance
属性加载 location
关系。由于您已经在 Location 模型的查询范围内 selecting distance
,因此您可以很容易地实现这一点:
public function getUsersAround($coordinates, $radius = 5)
{
return $this->whereHas('location', function ($query) use ($coordinates, $radius) {
$query->distance($coordinates, $radius);
})->with([
'location' => function ($query) use ($coordinates, $radius) {
$query->select('locations.*')->distance($coordinates, $radius);
}
])->paginate(10);
}
注意 with('location')
,它急切地加载 Location 模型。我添加了一个 select('locations.*')
以便 location
关系将具有自己的属性,并且 distance($coordinates, $radius)
也将 select profile_id
和 distance
属性。
因此,当您在控制器中调用 auth()->user()->getUsersAround($coordinates, $radius)
时,您可以使用 $user->location->distance
:
distance
属性
$users = auth()->user()->getUsersAround($coordinates, $radius);
foreach ($users as $user) {
$distance = $user->location->distance;
}