Laravel中如何借助已定义关联实现HasMany关联的条件筛选?
问题描述
我有三个模型:EmailTemplate、EmailSend、Attendee。EmailSend分别关联Attendee和EmailTemplate,关联定义如下:
class EmailSend extends MyBaseModel { ... public function attendee() { return $this->belongsTo(\App\Modals\Attendee::class); } public function template() { return $this->belongsTo(\App\Modals\EmailTemplate::class); } ... }
反向关联也已定义对应的belongsTo。我不需要EmailTemplate与Attendee之间的hasManyThrough关联。
需求是:在EmailTemplate与EmailSend的HasMany关联中,筛选出关联的Attendee的is_cancelled字段为0的记录。
当前实现如下:
class EmailTemplate extends MyBaseModel { ... public function sends() { return $this->hasMany(\App\Models\EmailSend::class) ->join('attendees', 'email_sends.attendee_id', '=', 'attendees.id') ->where('attendees.is_cancelled', 0); } ... }
该实现可正常运行,但想知道是否有更优雅的方式,利用已定义的关联来实现,而非直接引用表名?
解决方案
当然有更优雅的方式,你可以利用Laravel的whereHas方法,直接基于已定义的attendee关联来筛选,不需要手动写表连接:
class EmailTemplate extends MyBaseModel { ... public function sends() { return $this->hasMany(\App\Models\EmailSend::class) ->whereHas('attendee', function($query) { $query->where('is_cancelled', 0); }); } ... }
这种方式的优势:
- 完全复用已有的
attendee关联定义,无需硬编码表名和外键,契合Laravel的关联设计逻辑 - 代码可读性更强,一眼就能明确是基于关联的筛选规则
- 后续若
Attendee模型的表名或关联键发生变更,只需修改关联定义,不用调整这个筛选逻辑
如果需要更灵活的使用场景,还可以拆分出两个关联:
class EmailTemplate extends MyBaseModel { // 基础关联,不带筛选条件 public function allSends() { return $this->hasMany(\App\Models\EmailSend::class); } // 带筛选的关联,仅返回关联Attendee未取消的记录 public function sends() { return $this->allSends()->whereHas('attendee', function($query) { $query->where('is_cancelled', 0); }); } }
这样就能根据实际需求,选择调用allSends()获取全部记录,或调用sends()获取筛选后的记录。
内容的提问来源于stack exchange,提问作者BattleMetalChris
相关产品推荐
相关产品推荐

