Laravel中Rate模型自定义查询:本地作用域VS静态函数最佳实践
在Laravel封装查询逻辑的场景里,**本地作用域(Local Scopes)**绝对是你的最佳选择,原因如下:
1. 遵循Laravel的设计约定与最佳实践
本地作用域是Laravel官方专门为封装可复用查询逻辑设计的特性,完全契合框架的查询构建器(Query Builder)生态。其他熟悉Laravel的开发者看到scope开头的方法,立刻就能明白这是可复用的查询约束,维护成本更低。
顺便提一句:你写的本地作用域代码参数顺序有误——Laravel要求本地作用域的第一个参数必须是$query(查询构建器实例),正确的写法应该是:
public function scopeForRateable($query, $type, $id) { return $query->where('rateble_type', $type)->where('rateble_id', $id); }
我把方法名改成了scopeForRateable,因为它的职责更通用——只筛选指定关联类型和ID的评分,后续你可以基于这个作用域做更多操作,而不只是求平均。
2. 支持灵活的链式调用
本地作用域返回的是查询构建器实例,这意味着你可以和其他查询约束链式组合,扩展性极强。比如你之后需要给评分加一个“已审核”的过滤条件,只需再定义一个作用域,然后链式调用:
// 新增一个审核状态的作用域 public function scopeApproved($query) { return $query->where('is_approved', true); } // 控制器中组合调用 $average = Rate::approved()->forRateable($type, $id)->avg('star');
而你写的静态方法直接返回avg()的结果(一个数值),无法再和其他查询条件组合,灵活性大打折扣。
3. 更好的复用性与关注点分离
把通用的查询约束封装在本地作用域后,你不仅可以用它求平均,还能用来统计评分数量、获取最新评分等:
// 获取指定关联的评分总数 $totalRates = Rate::forRateable($type, $id)->count(); // 获取指定关联的最新5条评分 $latestRates = Rate::forRateable($type, $id)->latest()->take(5)->get();
静态方法的逻辑相对固定,如果后续需要其他基于相同筛选条件的查询,你得重复写where条件,或者重构代码,效率很低。
什么时候用静态函数?
如果某个方法的逻辑完全脱离查询构建器,比如只是基于模型数据做一些计算或者格式化,静态函数是合适的。但在你的场景里,核心是封装查询筛选逻辑,本地作用域显然是更优的选择。
控制器调用示例
基于修正后的本地作用域,控制器里的调用会非常简洁:
// 求指定关联的平均评分 $averageStar = Rate::forRateable($type, $id)->avg('star');
内容的提问来源于stack exchange,提问作者zahra_oveyedzade

