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
相关产品推荐
相关产品推荐

