Laravel技术问题:如何过滤morphOne或hasOne关联关系?
实现多态关联(morphOne/hasOne)的过滤操作
没问题,针对你给出的模型结构,咱们可以从定义关联时预设过滤和查询时动态过滤两个场景来实现需求,下面一步步来:
一、在关联定义时直接添加过滤条件
如果你希望latestStatus这个关联默认就只返回符合特定条件的StatusHistory记录(比如只关联状态为"已交付"的记录),可以直接在morphOne链式调用里追加过滤逻辑:
class Shipment extends Model { public function latestStatus() { return $this->morphOne('App\StatusHistory', 'model') ->latest() // 过滤关联的Status记录,比如只取name为"delivered"的状态 ->whereHas('status', function($query) { $query->where('name', 'delivered'); }); } }
这样每次调用$shipment->latestStatus时,只会返回符合条件的最新状态历史记录,如果没有匹配项则返回null。
二、查询时动态过滤关联
如果需要根据不同场景动态调整过滤条件,可以在查询过程中对关联进行筛选:
1. 筛选符合特定最新状态的Shipment实例
比如要找出所有最新状态为"已发货"的运单:
$shippedShipments = Shipment::whereHas('latestStatus', function($query) { $query->whereHas('status', function($subQuery) { $subQuery->where('name', 'shipped'); }); })->get();
2. 单个模型实例动态过滤关联
如果已经拿到了某个Shipment实例,想要单独获取它符合特定条件的最新状态历史:
$shipment = Shipment::find(1); // 获取该运单最新的"待处理"状态记录 $pendingLatestStatus = $shipment->latestStatus() ->whereHas('status', function($q) { $q->where('name', 'pending'); }) ->first();
三、进阶:自定义特定过滤的关联方法
如果某些过滤逻辑会频繁使用,建议直接在Shipment模型里定义专属的关联方法,提高代码复用性:
class Shipment extends Model { // 通用的最新状态关联 public function latestStatus() { return $this->morphOne('App\StatusHistory', 'model')->latest(); } // 专门返回最新的"已交付"状态 public function latestDeliveredStatus() { return $this->morphOne('App\StatusHistory', 'model') ->latest() ->whereHas('status', fn($q) => $q->where('name', 'delivered')); } // 专门返回最新的"异常"状态 public function latestExceptionStatus() { return $this->morphOne('App\StatusHistory', 'model') ->latest() ->whereHas('status', fn($q) => $q->where('name', 'exception')); } }
注意事项
morphOne和hasOne的过滤逻辑完全通用,所有适用于hasOne的查询条件(比如where、whereIn、join等)都可以直接套用到morphOne上- 如果过滤后没有匹配的记录,关联会返回
null,使用时记得做非空判断(比如if ($shipment->latestStatus))
内容的提问来源于stack exchange,提问作者Felipe Peña
相关产品推荐
相关产品推荐

