Laravel中User、Discipline、WorkHours模型Eloquent关系合理性咨询
问题:Laravel Eloquent模型关系设计咨询
我正在为所属俱乐部开发一款基于Laravel/Vue/Inertia的管理工具,需要为三个模型设计合理的Eloquent关系,业务场景如下:
- 俱乐部划分为多个Discipline(部门/领域),每位成员每年需完成一定时长的志愿工时
- 成员提交工时需填写Discipline、日期、时长,由该Discipline的负责人或指定审批人确认
- 创建WorkHours记录时,需填写日期、工时数、Discipline及对应审批人
- 注意:一个用户可同时作为某Discipline的审批人及提交WorkHours的成员,但同一条记录中不能兼具两种身份
我的初步设计如下:
模型关系逻辑
- Discipline与User为多对多关系(一个Discipline可拥有多个审批人,一个用户可成为多个Discipline的审批人)
- 一条WorkHours记录仅属于一个用户(user_id)且仅对应一个审批人(approver_id)
- 一个用户可拥有多条WorkHours记录,且可属于多个Discipline
模型定义
- Discipline模型:包含
name字段,关联方法:public function approvers() { return $this->belongsToMany(User::class); } - WorkHours模型:包含
date、hours字段,关联方法:public function member() { return $this->belongsTo(User::class); // 对应user_id } public function discipline() { return $this->belongsTo(Discipline::class); } public function approver() { return $this->hasOne(User::class); // 对应approver_id } - User模型:关联方法:
public function disciplines() { return $this->belongsToMany(Discipline::class); } public function workHours() { return $this->hasMany(WorkHours::class); }
数据库表结构
work_hours表:id、user_id、approver_iddisciplines表:id、nameusers表:id、name- 中间表
disciplines_users:user_id、discipline_id
请问该设计是否正确?是否有更优的关系定义方式?
回答
一、初步设计的问题点
- WorkHours的approver关联错误:
approver()方法应该用belongsTo(User::class)而非hasOne(User::class)。因为一条WorkHours记录属于一个审批人(approver_id是外键指向users表),hasOne是反向关联的用法,这里逻辑完全颠倒。 - 数据库表缺失字段:
work_hours表缺少discipline_id字段,模型里定义了discipline()关联但表结构无对应字段,会导致关联无法正常工作。 - 中间表扩展性不足:当前
disciplines_users仅存关联ID,若未来需区分用户在Discipline中的角色(如负责人/普通审批人),会缺少扩展空间。
二、优化后的模型关系设计
1. 模型关联修正
WorkHours模型:修正关联逻辑,明确外键对应关系:
public function member() { return $this->belongsTo(User::class, 'user_id'); } public function discipline() { return $this->belongsTo(Discipline::class, 'discipline_id'); } public function approver() { return $this->belongsTo(User::class, 'approver_id'); }User模型:补充审批记录关联,便于查询审批人处理的所有工时:
public function disciplines() { return $this->belongsToMany(Discipline::class); } public function submittedWorkHours() { return $this->hasMany(WorkHours::class, 'user_id'); } public function approvedWorkHours() { return $this->hasMany(WorkHours::class, 'approver_id'); }Discipline模型:补充该领域下的工时记录关联:
public function approvers() { return $this->belongsToMany(User::class); } public function workHours() { return $this->hasMany(WorkHours::class); }
2. 数据库表修正
work_hours表新增discipline_id字段,最终结构:id (主键) user_id (外键,关联users.id) discipline_id (外键,关联disciplines.id) approver_id (外键,关联users.id) date (日期类型) hours (数值类型,如decimal) created_at, updated_at (Laravel时间戳,可选)- 可选优化:给
disciplines_users中间表新增role字段(如approver/member),用于区分用户在Discipline中的身份,提升扩展性。
3. 业务规则代码实现
针对“同一条记录中提交人不能是审批人”的规则,在WorkHours的验证逻辑中添加校验:
// 在WorkHours的store/update请求验证中加入 'approver_id' => [ 'required', Rule::exists('users', 'id'), function ($attribute, $value, $fail) { // 禁止审批自己的工时 if ($value == auth()->id()) { $fail('不能审批自己提交的工时记录'); } // 可选:验证审批人属于当前选中的Discipline $disciplineId = request()->input('discipline_id'); if (!Discipline::find($disciplineId)->approvers()->where('user_id', $value)->exists()) { $fail('该审批人不属于所选的Discipline'); } }, ],
三、额外优化建议
给work_hours表添加status字段(如pending/approved/rejected),用于记录工时的审批状态,完善流程闭环。
内容的提问来源于stack exchange,提问作者wonder95
相关产品推荐
相关产品推荐

