Laravel嵌套集合搜索

时间:2019-03-08 20:00:44

标签: php laravel collections

我已经坚持了好几天。我有一堆需要迭代的“规则”,与使用一堆数据库调用相比,使用集合要有意义得多。问题是我似乎无法获得我见过的任何解决方案。

下面是我尝试搜索的“规则”的示例。 tagId是我要寻找的结果。我们有一组标签,在groupRules和tagRules上都有一个AND或OR运算符。

本质上,在下面的列表中id:17会显示如下内容:

(225存在且235存在)或(232存在且231存在)

我一生都无法解决如何查询除每个数组的第一级以外的任何内容。

下面的功能可以正常工作,但是当我尝试深入了解tagRules甚至groupRules时,它告诉我无法找到关键的groupRules。

$tagCollection = collect($tmp)
                        ->recursive()
                        ->where('tagType','!=',null);

[

    {
        "id": 17,
        "tagType": "CombinateTag",
        "name": "test1",
        "groupOperator": "OR",
        "groupRules": [
            {
                "tagOperator": "AND",
                "tagRules": [
                    {
                        "tagId": 225,
                        "hasTag": 1
                    },
                    {
                        "tagId": 235,
                        "hasTag": 1
                    }
                ]
            },
            {
                "tagOperator": "AND",
                "tagRules": [
                    {
                        "tagId": 232,
                        "hasTag": 0
                    },
                    {
                        "tagId": 231,
                        "hasTag": 0
                    }
                ]
            }
        ]
    },
    {
        "id": 18,
        "tagType": "Composite",
        "name": "test1a",
        "groupOperator": "OR",
        "groupRules": [
            {
                "tagOperator": "AND",
                "tagRules": [
                    {
                        "tagId": 225,
                        "hasTag": 1
                    },
                    {
                        "tagId": 235,
                        "hasTag": 1
                    }
                ]
            },
            {
                "tagOperator": "AND",
                "tagRules": [
                    {
                        "tagId": 232,
                        "hasTag": 0
                    },
                    {
                        "tagId": 231,
                        "hasTag": 0
                    }
                ]
            }
        ]
    }

]

1 个答案:

答案 0 :(得分:0)

这是一个好人!我花了一段时间,但我想我明白了。

希望我了解您想要什么,如果没有,这可能会帮助您。这很丑陋,但是您可以理解要点。

所以我的第一步是从您的json进行收集:

$tmp = json_decode('[

{
    "id": 17,
    "tagType": "CombinateTag",
    "name": "test1",
    "groupOperator": "OR",
    "groupRules": [
        {
            "tagOperator": "AND",
            "tagRules": [
                {
                    "tagId": 225,
                    "hasTag": 1
                },
                {
                    "tagId": 235,
                    "hasTag": 0
                }
            ]
        },
        {
            "tagOperator": "AND",
            "tagRules": [
                {
                    "tagId": 232,
                    "hasTag": 0
                },
                {
                    "tagId": 231,
                    "hasTag": 0
                }
            ]
        }
    ]
},
{
    "id": 18,
    "tagType": "Composite",
    "name": "test1a",
    "groupOperator": "AND",
    "groupRules": [
        {
            "tagOperator": "AND",
            "tagRules": [
                {
                    "tagId": 225,
                    "hasTag": 1
                },
                {
                    "tagId": 235,
                    "hasTag": 1
                }
            ]
        },
        {
            "tagOperator": "AND",
            "tagRules": [
                {
                    "tagId": 232,
                    "hasTag": 1
                },
                {
                    "tagId": 231,
                    "hasTag": 1
                }
            ]
        }
    ]
}

]', true);

$tmp = collect($tmp)->recursiveCollect();

与此:

 \Illuminate\Support\Collection::macro('recursiveCollect', function () {
        return $this->map(function ($value) {
            if (is_array($value)) {
                return collect($value)->recursiveCollect();
            }
            if (is_object($value)) {
                return collect($value)->recursiveCollect();
            }

            return $value;
        });
    });

然后我为您的数据创建了一个宏:

\Illuminate\Support\Collection::macro('roleFilter', function ($operator = '') {
        $property = '';
        if ($this->has('groupRules')) { //Check if the collection has more levels
            $operator = $this['groupOperator']; //set the operator
            $property = 'groupRules'; //Set the property aside
        }
        $res = false;
        if ($property === 'groupRules') { //Check if needs more digging
            $res = $this[$property]->roleFilter($operator);
        } else {
            if ($operator === 'OR') { //validate for OR between groupRules
                $res = false;
                $this->each(function ($val) use (&$res) {
                    $has = 0;
                    $val['tagRules']->each(function ($v) use (&$has) {
                        if ($v['hasTag'] == 1) {
                            $has++;
                        }
                    });
                    if ($val['tagOperator'] === 'OR') { //validate for OR between tagRules
                        $res = $res || $has > 0;
                    } elseif ($val['tagOperator'] === 'AND') { //validate for AND between tagRules
                        $res = $res || $val['tagRules']->count() == $has;
                    }
                });
            } elseif ($operator === 'AND') {  //validate for AND between groupRules
                $res = true;
                $this->each(function ($val) use (&$res) {
                    $has = 0;
                    $val['tagRules']->each(function ($v) use (&$has) {
                        if ($v['hasTag'] == 1) {
                            $has++;
                        }
                    });
                    if ($val['tagOperator'] === 'OR') { //validate for OR between tagRules
                        $res = $res && $has > 0;
                    } elseif ($val['tagOperator'] === 'AND') { //validate for AND between tagRules
                        $res = $res && $val['tagRules']->count() == $has;
                    }
                });
            }
        }
        return $res;
    });

您可以检查以下角色:

$alloweds = $tmp->filter(function ($value) {
        return $value->roleFilter();
    });