Я пытаюсь использовать сводную переменную родительского отношения внутри красноречивого метода withCount().
Задний план:
Существует приложение с отношением ManyToMany между пользователями и кластерами. Пользователи могут отправлять сообщения внутри кластера. Чтобы отслеживать количество непрочитанных сообщений для пользователя в определенном кластере, я отслеживаю идентификатор последнего прочитанного сообщения в таблице соединений, например:
table: cluster_user
cluster_id | user_id | last_read_message_id
-------------------------------------------
1 | 59 | 3
2 | 62 | 8
User() имеет связь belongsToMany() с моделью Cluster().Cluster() имеет связь belongsToMany() с моделью User().Cluster() имеет связь hasMany() с моделью Messages().Message() имеет связь belongsTo() с моделью Cluster().Теперь я хотел бы перечислить все кластеры аутентифицированного пользователя, включая количество непрочитанных сообщений.
В настоящее время я застрял на этом:
$clusters = Auth::user()->clusters()->withCount(['messages' => function ($query) {
$query->where('messages.id', '>', '???');
}])->get();
Я уже пробовал:
$clusters = Auth::user()->clusters()->withCount(['messages' => function ($query) {
$query->where('messages.id', '>', 'cluster_user.last_read_message_id');
}])->get();
Но это дает мне общее количество всех сообщений вместо сообщений с идентификатором выше x. Если я жестко закодирую идентификатор, например:
$clusters = Auth::user()->clusters()->withCount(['messages' => function ($query) {
$query->where('messages.id', '>', '3');
}])->get();
Затем я получаю правильный счетчик непрочитанных сообщений.
Так может ли кто-нибудь сказать мне, как использовать сводную переменную 'last_read_message_id' отношения user()->cluster() внутри функции обратного вызова withCount(), имея в виду следующее:
ClusterResource, например:return ClusterResource::collection($clusters);
который включает количество непрочитанных сообщений.
class ClusterResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'name' => $this->name,
'unread_messages_count' => $this->whenPivotLoaded('cluster_user', $this->messages_count)
];
}
}
Спасибо!
@cbaconnier интересно! и грустно :( Хотя, когда я вывожу getQueryLog(), я получаю следующий запрос: select 'clusters'.*, (select count(*) from 'messages' where 'clusters'.'id' = 'messages'.'cluster_id' and 'messages'.'id' > ?) as 'messages_count', blablabla from 'clusters' inner join 'cluster_user' on 'clusters'.'id' = 'cluster_user'.'cluster_id' where 'cluster_user'.'user_id' = ? (заменил кусок на blablabla, чтобы сократить его). Если я заменю первый вопросительный знак на cluster_user.last_read_message_id, результат будет правильным, так что это не кажется быть совершенно отдельно в этом случае!
@cbaconnier нашел решение благодаря вашему комментарию! DB::raw('cluster_user.last_read_message_id') у меня работает.
Ууууу! тогда я рада за вас :)
я тоже посмотрю на твой вопрос






Хороший вопрос! Я думаю, вы должны иметь возможность использовать метод withPivot в своих отношениях, а затем использовать атрибут pivot в своем запросе.
Например, в вашей модели Cluster, где вы определяете связь cluster_user, выполните следующие действия:
function cluster_user() {
return $this->belongsToMany('App\User')
->withPivot('last_read_message_id');
}
А затем в своем запросе вы можете использовать whereColumn для сравнения столбцов. Что-то вроде этого:
$clusters = Auth::user()
->clusters()
->withCount(['messages' => function ($query) {
$query->whereColumn('messages.id', '>',
'pivot.last_read_message_id');
}])
->get();
Найдите «Извлечение столбцов промежуточной таблицы» в Документация по красноречивым отношениям для получения дополнительной информации.
Спасибо @Delena Malan за ваш ответ, но отношение в модели Cluster уже объявлено следующим образом: return $this->belongsToMany(User::class)->withPivot('last_read_message_id');
Ах, да, я только что понял, что он будет принимать значение как pivot.last_read_message_id вместо фактического значения столбца. Вы можете поиграть с whereColumn. Он должен работать аналогично DB::raw.
Нашел ответ благодаря комментарию @cbaconnier.
Размещение DB::raw('cluster_user.last_read_message_id') на месте работает. Я не опрятный, но это работает.
Полный пример:
$clusters = Auth::user()
->clusters()
->withCount(['messages' => function ($query) {
$query->where('messages.id', '>', DB::raw('cluster_user.last_read_message_id'));
}])
->get();
Вчера я получил в основном тот же вопрос, и ответ был: вы не можете .. :( stackoverflow.com/questions/54444858/… Если вы найдете способ, мне все равно будет интересно.