Laravel中如何在morphTo关联中使用whereHas?
在Laravel多态关联中使用whereHas查询的解决方案
嘿,针对你这个基于Product和Favorite多态关联的whereHas查询问题,我给你梳理清楚具体用法和示例,直接就能用!
首先先明确我们的关联关系:
- Product模型通过
favorites()方法和Favorite建立morphMany关联(一个Product可以被多次收藏) - Favorite模型通过
favoritable()方法实现morphTo关联(收藏可以指向不同类型的模型,这里是Product)
下面分两种常见场景给你示例:
场景1:从Product出发,查询满足自身条件且关联收藏记录的商品
比如你要搜索名称包含$q的商品,并且这些商品被特定用户(比如ID=1)收藏过,代码可以这么写:
$q = $param['q']; $query = Product::query() // 先过滤Product自身的条件:名称包含$q ->where('name', 'like', "%{$q}%") // 关联查询收藏记录,限定收藏者是用户ID=1 ->whereHas('favorites', function ($subQuery) { $subQuery->where('user_id', 1); }) ->get();
这里要注意:因为我们是从Product模型调用whereHas('favorites'),Eloquent会自动帮我们处理多态关联的匹配条件(即favoritable_type = Product::class和favoritable_id = products.id),不需要手动写这些!
如果要查询没有被任何用户收藏的商品,只需要把whereHas换成whereDoesntHave即可,用法完全一致。
进阶:查询收藏次数超过N次的商品
如果想找被收藏超过5次,且描述包含$q的商品,可以利用whereHas的第三个参数来做统计:
$q = $param['q']; $query = Product::query() ->where('description', 'like', "%{$q}%") // 第三个参数是比较运算符,第四个是数值,这里表示关联的收藏记录数>5 ->whereHas('favorites', function ($subQuery) { // 这里可以加额外的收藏记录条件,比如只算近30天的收藏 $subQuery->where('created_at', '>=', now()->subDays(30)); }, '>', 5) ->get();
场景2:从Favorite出发,查询关联的Product满足特定条件
比如你要找用户ID=1收藏的所有商品,且商品名称包含$q,可以这么写:
$q = $param['q']; $query = Favorite::query() ->where('user_id', 1) // 关联查询favoritable(这里限定是Product类型),并过滤商品名称 ->whereMorphTo('favoritable', Product::class, function ($subQuery) use ($q) { $subQuery->where('name', 'like', "%{$q}%"); }) ->with('favoritable') // 预加载关联的Product,避免N+1查询 ->get();
这里用whereMorphTo可以更简洁地限定多态关联的类型,替代手动写where('favoritable_type', Product::class)的写法,代码更清晰。
内容的提问来源于stack exchange,提问作者moses toh
相关产品推荐
相关产品推荐

