Laravel关系具有嵌套结构时的位置

时间:2019-11-18 09:41:38

标签: php laravel eloquent

这个问题与编程方法更相关,但是由于它利用的是Eloquent模型关系,而我的问题实际上是试图简化Eloquent的已执行查询,因此我决定将其与Laravel标签一起发布。

在我正在使用的Laravel 5.8应用程序中,我的Item和Category模型之间存在如下关系:

项目模型

public function category() {
    return $this->belongsTo(Category::class);
}

类别模型

public function items() {
    return $this->hasMany(Item::class);
}

我的项目模型具有一个称为“活动”的布尔属性,因此要获取所有具有活动项目的类别,我可以使用一条语句

Category::whereHas('items', function ($query) {
                            $query->active();
                        })->get();

现在,类别结构是嵌套的,这意味着每个类别可以有一个父类别。父类别ID在类别模型中可用作“ parent_id”属性,如果类别是最高级别,则为NULL。因此,类别模型中的这种关系看起来像

public function parent_category() {
    return $this->belongsTo(Category::class, 'parent_id');
}

public function subcategories() {
    return $this->hasMany(Category::class, 'parent_id', 'id');
}

最后,让我提出我的问题。如何获得包含活动项目(包括子类别)的所有类别而无需分别查询每个类别是否具有活动项目的最佳方法?例如,如果我有以下数据

Category 1     (id=1,   parent_id=NULL, no active items)
Category 1.1   (id=11,  parent_id=1,     1 active item)
Category 2     (id=2,   parent_id=NULL, no active items)
Category 2.1   (id=21,  parent_id=2,    no active items)
Category 2.1.1 (id=211, parent_id=21,    1 active item)
Category 3     (id=3,   parent_id=NULL, no active items)
Category 3.1   (id=3.1, parent_id=3,    no active items)

我想获得所有顶级类别,即使其中一个嵌套子类别也有一个活动项目。在上述情况下,我希望将“类别1”和“类别2”作为结果。

现在,我必须获取所有类别的列表,然后遍历其每个子类别(然后再遍历每个子类别的子类别,直到我没有找到任何子类别),并确定它们是否为活动项。是否有一种优雅的方法可以解决此问题,或者我正在做的已经是最好的方法?

谢谢。

注意:我知道我可以有一个额外的数据库字段来存储每个类别中活动项目的数量,并在每次该项目的活动状态发生任何更改时都进行更新(如果类别中有一个父项,则还要更新父类别的字段类别)。但是上面提到的“活动”字段只是一个例子,例如,我需要查找诸如stock之类的可变字段,我可能需要获取所有股票均高于10的类别,并且这种方法在那儿行不通。

1 个答案:

答案 0 :(得分:0)

尝试以下查询:

$categories = Category::whereNotNull('parent_id')->whereHas('subcategories', function ($query) {
        $query->whereHas('items', function ($q) {
            $q->active();
        });
    })->with('parent_category')->get();