Laravel项目中使用模型自定义方法筛选集合报错咨询
解决Laravel中
Collection::isAvailable不存在的错误 错误原因分析
你遇到的BadMethodCallException问题,根源出在groupBy('categorie.denumire')这个操作上:
当你调用get()后得到的是Eloquent\Collection,每个元素都是单个Produs模型实例;但执行groupBy后,返回的集合结构变成了嵌套集合——外层集合的键是分类名称,对应的值是该分类下所有Produs模型组成的子集合。
所以当你后续调用filter时,$produs参数指向的是子集合对象,而不是单个Produs模型,集合类自然没有你在模型里定义的isAvailable()方法,因此报错。
解决方案
根据你的需求,分两种场景给出处理方式:
场景1:先筛选可用产品,再按分类分组(推荐,性能更优)
如果你的目标是先找出所有符合条件的可用产品,再按分类整理,建议调整操作顺序,先筛选可用产品再分组:
// 先获取集合,筛选可用产品,再做过滤和分组 $models = Produs::with('categorie', 'poza', 'element_extra.extras') ->get() ->where('id_stare', 1) ->filter(function ($produs) { return $produs->isAvailable(); }) ->where('categorie.id_restaurant', $idRestaurant) ->groupBy('categorie.denumire'); $produse = $models->values();
进阶优化:数据库层面筛选(更高效)
上面的方式是在内存中筛选,如果你想进一步提升性能,建议把isAvailable()的逻辑迁移到数据库查询阶段,用查询作用域实现:
在Produs模型中添加查询作用域:
class Produs extends Model { protected $table = "elemente"; public $timestamps = false; // 定义查询作用域,把isAvailable的逻辑转为数据库查询条件 public function scopeAvailable($query) { // 替换成你isAvailable方法里的实际判断逻辑 // 比如原逻辑是检查库存大于0,就写: return $query->where('stoc', '>', 0); } public function isAvailable(){ // ... 原有的判断逻辑 } }
然后控制器中直接调用作用域,在数据库层面完成筛选:
$models = Produs::with('categorie', 'poza', 'element_extra.extras') ->where('id_stare', 1) // 用whereHas过滤关联分类的条件 ->whereHas('categorie', function ($query) use ($idRestaurant) { $query->where('id_restaurant', $idRestaurant); }) ->available() // 调用自定义作用域筛选可用产品 ->get() ->groupBy('categorie.denumire'); $produse = $models->values();
场景2:先分组,再筛选每个分组内的可用产品
如果必须先按分类分组,再筛选每个分组里的可用产品,需要用map遍历每个分组,在分组内部执行筛选:
$models = Produs::with('categorie', 'poza', 'element_extra.extras') ->get() ->where('id_stare', 1) ->where('categorie.id_restaurant', $idRestaurant) ->groupBy('categorie.denumire'); // 遍历每个分类分组,筛选出组内可用的产品,并移除空分组 $produse = $models->map(function ($categoryProducts) { // 筛选当前分类下的可用产品 return $categoryProducts->filter(function ($produs) { return $produs->isAvailable(); })->values(); }) // 过滤掉没有可用产品的空分组 ->filter(function ($filteredProducts) { return $filteredProducts->isNotEmpty(); }) ->values();
内容的提问来源于stack exchange,提问作者Chirica Andrei
相关产品推荐
相关产品推荐

