You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 15:42:03