
本文介绍在 Laravel 中通过 Eloquent 关系优雅地获取所有用户及其对应的角色名称(而非原始中间表数据),避免返回冗余的 user_role 中间记录,实现清晰、可读性强的 JSON 响应结构。
本文介绍在 laravel 中通过 eloquent 关系优雅地获取所有用户及其对应的角色名称(而非原始中间表数据),避免返回冗余的 `user_role` 中间记录,实现清晰、可读性强的 json 响应结构。
在 Laravel 中,若数据库包含 users、roles 和中间表 role_user(注意:Laravel 社区惯例命名通常为 role_user 而非 user_role,下文按标准命名说明),要获取「每个用户及其实际角色名称」而非中间表原始字段,关键在于正确定义多对多关系并使用 with() 预加载 + select() 或 map() 映射优化响应结构,而非依赖第三方包。
✅ 正确做法:利用 Eloquent 多对多关系
首先,确保模型关系定义正确:
// app/Models/User.php
class User extends Authenticatable
{
public function roles()
{
return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');
}
}
// app/Models/Role.php
class Role extends Model
{
protected $fillable = ['name', 'slug'];
}
⚠️ 注意:中间表名应为
role_user(按字母顺序),字段为user_id和role_id;若实际表名为user_role,需在belongsToMany()第二个参数中显式指定。
? 获取用户及角色名称的推荐方式
在控制器中,使用预加载 + API 资源或 map() 构建结构化响应:
// 示例:UserController@allWithRoles
public function allWithRoles()
{
$users = User::with('roles:id,name') // 只加载 role 的 id 和 name 字段,减少冗余
->get()
->map(function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
'roles' => $user->roles->map(function ($role) {
return [
'id' => $role->id,
'role' => $role->name, // ✅ 满足需求:输出 "role": "admin" 而非 role_id
];
})->values(),
];
});
return response()->json(['users' => $users]);
}
✅ 输出效果(符合预期):
{
"users": [
{
"id": 1,
"name": "abc",
"roles": [
{ "id": 1, "role": "admin" },
{ "id": 2, "role": "editor" }
]
}
]
}
? 为什么不推荐直接用 laratrust 或 laravel-permission?
虽然 spatie/laravel-permission(原 larapermission)功能强大,但本需求仅涉及基础多对多数据组装,无需引入权限策略、守卫、缓存等复杂能力。过度依赖包会增加维护成本、学习曲线和潜在兼容性风险。Eloquent 原生关系已完全胜任。
? 进阶建议
- 使用 API Resources 提升可维护性:
// app/Http/Resources/UserWithRolesResource.php class UserWithRolesResource extends JsonResource { public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'roles' => RoleResource::collection($this->whenLoaded('roles')), ]; } } - 对于大数据量,添加分页与索引优化:
$users = User::with('roles:id,name')->paginate(20);
✅ 总结
核心要点有三:
1️⃣ 正确定义 belongsToMany 关系(注意中间表名与外键);
2️⃣ 使用 with('roles:id,name') 预加载并精简字段;
3️⃣ 通过 map() 或 API Resource 组织最终 JSON 结构,将 roles 数组中的对象由 role_id → role: "xxx"。
无需额外包,Laravel 原生能力即可简洁、高效、可扩展地达成目标。











