You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent如何获取当前用户与指定用户的有序聊天消息

Laravel聊天应用:消息范围筛选与排序优化

我基于Laravel开发聊天应用,当前功能可正常运行,但存在一个问题:会获取当前用户与所有用户的收发消息,需要调整为仅获取当前用户与指定聊天对象之间的消息,同时保证消息排序符合聊天逻辑。

相关数据表说明:

  • Chats表:存储发送者ID(sender_id)、接收者ID(recipient_id)
  • Messages表:存储消息内容,通过chat_id关联到Chats表

现有代码片段

Users Model

public function chats() 
{
        return $this->hasMany(Chat::class, 'recipient_id')
        ->orWhere(function($query) {
            $query->where('sender_id', '<>', $this->id)
            ->where('recipient_id', $this->id);
        })
        ->orWhere(function($query) {
            $query->where('sender_id', $this->id)
            ->where('recipient_id', '<>', $this->id);
        })->orderBy('created_at', 'asc');
}

Chats Model

public function users() 
{
        return $this->belongsTo(User::class);
}

public function messages()
{
        return $this->hasMany(Message::class, 'chat_id');
}

Messages Model

public function chats()
{
        return $this->belongsTo(Chat::class, 'chat_id');
}

Messages Controller

public function getMessages($username) {
        $host = User::where('username', $username)->first();
        $user = Auth::user();

        if($username !== $user->username && !Abilities::isBlocked($username) && Abilities::canBlock($username)) {
            $messages = $host->chats()
            ->with(['messages' => function ($query) {
                $query->orderBy('created_at', 'desc');
            }])
            ->where('recipient_id', $user->id)
            ->get()
            ->each(function($chat) {
                $chat->status = $chat->sender_id === Auth::user()->id ? "sent" : "received";
            });
            
            return response()->json([
                "messages" => $messages,
            ]);
        }
        
        return response()->json(["messages" => "Unauthorized access."]);
}

解决方案

1. 修正Users模型的聊天关联逻辑

简化关联查询,确保仅关联当前用户参与的聊天(作为发送者或接收者):

public function chats()
{
    return $this->hasMany(Chat::class)
        ->where(function($query) {
            $query->where('sender_id', $this->id)
                  ->orWhere('recipient_id', $this->id);
        })
        ->orderBy('created_at', 'asc');
}

2. 优化Chats模型的用户关联

原users关联未明确外键,改为两个清晰的关联,方便后续查询:

public function sender()
{
    return $this->belongsTo(User::class, 'sender_id');
}

public function recipient()
{
    return $this->belongsTo(User::class, 'recipient_id');
}

public function messages()
{
    return $this->hasMany(Message::class, 'chat_id');
}

3. 重构Messages控制器的消息查询逻辑

调整查询条件,仅获取当前用户与指定对象的聊天消息,同时修正排序逻辑:

public function getMessages($username) {
    $host = User::where('username', $username)->firstOrFail();
    $user = Auth::user();

    // 先判断权限,不满足直接返回
    if($username === $user->username || Abilities::isBlocked($username) || !Abilities::canBlock($username)) {
        return response()->json(["messages" => "Unauthorized access."]);
    }

    // 筛选当前用户与指定用户之间的所有聊天记录(双向)
    $chats = Chat::where(function($query) use ($user, $host) {
            $query->where('sender_id', $user->id)
                  ->where('recipient_id', $host->id);
        })
        ->orWhere(function($query) use ($user, $host) {
            $query->where('sender_id', $host->id)
                  ->where('recipient_id', $user->id);
        })
        ->with(['messages' => function($query) {
            // 按消息创建时间正序排列,符合常规聊天界面的旧消息在上、新消息在下的逻辑
            $query->orderBy('created_at', 'asc');
        }])
        ->orderBy('created_at', 'asc')
        ->get()
        ->each(function($chat) use ($user) {
            $chat->status = $chat->sender_id === $user->id ? "sent" : "received";
        });

    return response()->json(["messages" => $chats]);
}

关键说明

  • 权限判断逻辑提前,代码可读性更高
  • 聊天记录筛选采用双向条件,覆盖“当前用户发往指定用户”和“指定用户发往当前用户”两种场景
  • 消息排序改为正序,若需要最新消息在顶部,可将orderBy('created_at', 'asc')改为desc,或由前端处理排序

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 01:13:22