82 lines
3.1 KiB
PHP
82 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Messaging;
|
|
|
|
use App\Models\Conversation;
|
|
use App\Models\ConversationParticipant;
|
|
use App\Models\Message;
|
|
use App\Models\User;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
|
|
class UnreadCounterService
|
|
{
|
|
public function applyUnreadCountSelect(Builder $query, User|int $user, string $participantAlias = 'cp_me'): Builder
|
|
{
|
|
$userId = $user instanceof User ? (int) $user->id : (int) $user;
|
|
|
|
return $query->addSelect([
|
|
'unread_count' => Message::query()
|
|
->selectRaw('count(*)')
|
|
->whereColumn('messages.conversation_id', 'conversations.id')
|
|
->where('messages.sender_id', '!=', $userId)
|
|
->whereNull('messages.deleted_at')
|
|
->where(function ($nested) use ($participantAlias) {
|
|
$nested->where(function ($group) use ($participantAlias) {
|
|
$group->whereNull($participantAlias . '.last_read_message_id')
|
|
->whereNull($participantAlias . '.last_read_at');
|
|
})->orWhereColumn('messages.id', '>', $participantAlias . '.last_read_message_id')
|
|
->orWhereColumn('messages.created_at', '>', $participantAlias . '.last_read_at');
|
|
}),
|
|
]);
|
|
}
|
|
|
|
public function unreadCountForConversation(Conversation $conversation, User|int $user): int
|
|
{
|
|
$userId = $user instanceof User ? (int) $user->id : (int) $user;
|
|
|
|
$participant = ConversationParticipant::query()
|
|
->where('conversation_id', $conversation->id)
|
|
->where('user_id', $userId)
|
|
->whereNull('left_at')
|
|
->first();
|
|
|
|
if (! $participant) {
|
|
return 0;
|
|
}
|
|
|
|
return $this->unreadCountForParticipant($participant);
|
|
}
|
|
|
|
public function unreadCountForParticipant(ConversationParticipant $participant): int
|
|
{
|
|
$query = Message::query()
|
|
->where('conversation_id', $participant->conversation_id)
|
|
->where('sender_id', '!=', $participant->user_id)
|
|
->whereNull('deleted_at');
|
|
|
|
if ($participant->last_read_message_id) {
|
|
$query->where('id', '>', $participant->last_read_message_id);
|
|
} elseif ($participant->last_read_at) {
|
|
$query->where('created_at', '>', $participant->last_read_at);
|
|
}
|
|
|
|
return (int) $query->count();
|
|
}
|
|
|
|
public function totalUnreadForUser(User|int $user): int
|
|
{
|
|
$userId = $user instanceof User ? (int) $user->id : (int) $user;
|
|
|
|
return (int) Conversation::query()
|
|
->select('conversations.id')
|
|
->join('conversation_participants as cp_me', function ($join) use ($userId) {
|
|
$join->on('cp_me.conversation_id', '=', 'conversations.id')
|
|
->where('cp_me.user_id', '=', $userId)
|
|
->whereNull('cp_me.left_at');
|
|
})
|
|
->where('conversations.is_active', true)
|
|
->get()
|
|
->sum(fn (Conversation $conversation) => $this->unreadCountForConversation($conversation, $userId));
|
|
}
|
|
}
|