Laravel按层级分类筛选集合的实现问题及报错排查
解决Laravel层级分类下的Collection筛选问题
问题原因
你当前的代码报错是因为:在orWhereHas('category.parent')的闭包中,$query是Category模型的查询构造器,而ofCategory是定义在Collection模型里的scope方法,两者不属于同一模型,自然找不到该方法。
解决方案
正确的思路是先获取目标分类及其所有子分类的ID集合,再用这些ID筛选对应的Collection。
步骤1:在Category模型中实现获取所有子分类ID的方法
推荐使用Laravel 9+支持的递归CTE(性能更优),也可以用递归函数兼容低版本:
// app/Models/Category.php use Illuminate\Support\Facades\DB; class Category extends Model { // 定义父分类关联 public function parent() { return $this->belongsTo(Category::class, 'parent_id'); } // 定义子分类关联 public function children() { return $this->hasMany(Category::class, 'parent_id'); } // 获取当前分类及其所有子分类的ID(递归CTE版,性能更优) public static function getDescendantIds($categoryId) { $category = static::withRecursive(['descendants' => function ($query) { $query->select('id', 'parent_id') ->from('categories') ->whereRaw('parent_id = categories.id'); }]) ->where('id', $categoryId) ->first(); return $category ? $category->descendants->pluck('id')->prepend($categoryId)->toArray() : []; } // 兼容低版本Laravel的递归函数版(层级过深时性能较差) // public static function getDescendantIds($categoryId) // { // $ids = static::where('id', $categoryId) // ->orWhere('parent_id', $categoryId) // ->pluck('id') // ->toArray(); // foreach ($ids as $id) { // $childIds = static::getDescendantIds($id); // $ids = array_merge($ids, $childIds); // } // return array_unique($ids); // } }
步骤2:修改Collection模型的scope方法
直接用获取到的分类ID集合做筛选:
// app/Models/Collection.php public function scopeOfCategory($query, $categoryId) { if (!$categoryId) { return $query; } $categoryIds = \App\Models\Category::getDescendantIds($categoryId); return $query->whereIn('category_id', $categoryIds); }
使用示例
// 筛选Music分类(ID为1)及其所有子分类下的Collection $collections = Collection::ofCategory(1)->get();
内容的提问来源于stack exchange,提问作者Nashwan
相关产品推荐
相关产品推荐

