雄辩的递归关系

时间:2020-01-08 15:26:29

标签: php laravel eloquent

我遇到一个问题,我试图获取一个对象的所有后代,并仅保留具有特定属性的对象。

我有这些关系:

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

    public function allChildren()
    {
        return $this->getChildren()->with('allChildren');
    }

例如,我得到这种类型的数组:

$array = [
           0 => ['name' => 'aaa', 'type' => 0, 'parent' => null, 'children' => [
                 1 => ['name' => 'bbb', 'type' => 1, 'parent' => null, 'children' => []], 
                 2 => ['name' => 'ccc', 'type' => 0, 'parent' => null, 'children' => [
                       3 => ['name' => 'ddd', 'type' => 1, 'parent' => 2, 'children' => []]
                        ]]
                    ]],
           4 => ['name' => 'eee', 'type' => 0, 'parent' => null, 'children' => []]
];

对于此示例,我想删除所有type 1的对象,并获得一个仅包含这些对象的干净数组。

我不太了解为什么可以获取一个对象的所有后代,但无法通过条件。

谢谢。

2 个答案:

答案 0 :(得分:1)

仅收集解决方案就是这样(将自定义宏放在应用程序的服务提供商中):

Collection::macro('whereDeep', function ($column, $operator, $value, $nested) {
    return $this->where($column, $operator, $value)->map(function ($x) use ($column, $operator, $value, $nested) {
        return $x->put($nested, $x->get($nested)->whereDeep($column, $operator, $value, $nested));
    });
});

然后在需要的地方致电:

$yourArray->whereDeep('type', '!=', 1, 'children');

在您的示例中,宏的工作方式如下:

  1. 过滤所有元素,其中:type != 1
    (因为两个项目都有type => 0,所以外部数组将保持不变)
  2. 对于当前数组的每个元素:
    • 检索children属性,并从本指令的第一点开始,对该子数组应用相同的过滤。
    • 用刚刚过滤的新子级属性替换children属性。

无论如何,您应该尝试深入探究为什么关系过滤不起作用。如果正确优化,该解决方案将更加有效。

答案 1 :(得分:0)

我找到了一个很好的解决方案,其中不需要所有此类递归或任何这些关系调用,因此可以与我分享:

使用:"gazsp/baum"


// get your object with roots method

$contents = Content::roots()->get();

// and simply run through the object and get whatever you need 
// thanks to getDescendantsAndSelf method

$myArray = [];

foreach($contents as $content) {
 $myArray[] = $content->getDescendantsAndSelf()->where('type', '!=', 1)->toHierarchy();
}

return $myArray;

对我来说,此方法与上述其他方法相同。