Laravel中基于其他模型记录过滤数据(实现用户拉黑功能)
问题分析与解决方案
原代码逻辑方向错误,导致无法过滤拉黑关系的用户。whereDoesntHave('blocklist', ...) 是检查待查询用户的拉黑记录(即该用户作为拉黑者的blocklist条目),但你传入的条件是user_id = auth()->id(),这和需求完全不符,因此会返回所有用户。
以下是两种可行的修复方案:
方法一:直接用子查询排除目标用户
通过两个子查询分别过滤掉「当前用户拉黑的用户」和「拉黑当前用户的用户」:
use App\Models\User; use Illuminate\Support\Facades\Auth; $currentUserId = Auth::guard('sanctum')->id(); $users = User::query() // 排除当前用户拉黑的用户 ->whereNotIn('id', function ($query) use ($currentUserId) { $query->select('blockable_id') ->from('blocklist') ->where('user_id', $currentUserId) ->where('blockable_type', User::class); }) // 排除拉黑当前用户的用户 ->whereNotIn('id', function ($query) use ($currentUserId) { $query->select('user_id') ->from('blocklist') ->where('blockable_id', $currentUserId) ->where('blockable_type', User::class); }) ->get();
方法二:优化模型关联后使用whereDoesntHave
先在User模型中添加两个语义化关联,让查询更清晰:
// app/Models/User.php use App\Models\Blocklist; // 自己拉黑的用户 public function blockedUsers() { return $this->hasManyThrough( User::class, Blocklist::class, 'user_id', // Blocklist表中关联当前用户的字段(拉黑者ID) 'id', // 被拉黑用户表的主键 'id', // 当前用户表的主键 'blockable_id' // Blocklist表中关联被拉黑用户的字段 )->where('blocklist.blockable_type', User::class); } // 拉黑自己的用户 public function blockedByUsers() { return $this->hasManyThrough( User::class, Blocklist::class, 'blockable_id', // Blocklist表中关联当前用户的字段(被拉黑者ID) 'id', // 拉黑者用户表的主键 'id', // 当前用户表的主键 'user_id' // Blocklist表中关联拉黑者的字段 )->where('blocklist.blockable_type', User::class); }
然后在控制器中通过关联过滤:
$currentUser = Auth::guard('sanctum')->user(); $users = User::query() // 排除被当前用户拉黑的用户 ->whereDoesntHave('blockedByUsers', fn($query) => $query->where('users.id', $currentUser->id)) // 排除拉黑当前用户的用户 ->whereDoesntHave('blockedUsers', fn($query) => $query->where('users.id', $currentUser->id)) ->get();
内容的提问来源于stack exchange,提问作者3m1n3nc3
相关产品推荐
相关产品推荐

