Laravel collection multi level groupBy 插入新项目而不检查每个级别的键

Laravel collection multi level groupBy insert new items without checking each level's key

Laravel 集合现在内置了一个很棒的多级 groupBy 函数,但我正在努力寻找一种插入新项目的合理方法。

例如:

$this->myCollection = EloquentModel::all()->groupBy(['key1','key2','key3','key4']);

非常好,易于设置和访问。对于这个例子,我假设每个键都是一个数字

$this->myCollection[1][2][3][4] = new EloquentModel([insert => stuffHere]);

如果嵌套位置 [1]、[2] 和 [3] 中已经有项目,那么我可以添加新项目或覆盖 [4] 处的现有项目,但如果任何嵌套位置1 到 3 丢失我得到一个错误

Undefined offset: 1   (or 2 or 3 depending upon which is missing)

目前我正在使用以下函数调用插入结构函数:

if (!$this->myCollection->has()) {
    $this->myCollection[] = new Collection;
}
if (!$this->myCollection[]->has()) {
    $this->myCollection[][] = new Collection;
}
if (!$this->myCollection[][]->has()) {
    $this->myCollection[][][] = new Collection;
}
$this->myCollection[][][][] = $itemFor4;

我发现 groupBy 嵌套非常有用,除了不能干净地处理我的插入。

一些示例数据 - 请假设有 > 100k 条这样的记录:

['username'=> 'a user name', 'course', => 'a coursename', 'activity_type' => 'one of 100s of activity names', 'reporting_week' => 23 // One of 52 weeks, [lots more data]]
['username'=> 'another user name', 'course', => 'another coursename', 'activity_type' => 'one of 100s of activity names', 'reporting_week' => 23 // One of 52 weeks, [lots more data]]
['username'=> 'a user name', 'course', => 'another coursename', 'activity_type' => 'one of 100s of activity names', 'reporting_week' => 24 // One of 52 weeks, [lots more data]]
['username'=> 'another user name', 'course', => 'a coursename', 'activity_type' => 'one of 100s of activity names', 'reporting_week' => 24 // One of 52 weeks, [lots more data]]

代替现实生活中的用户名和课程,它将是代表该特定用户和该课程的代码。

数据将包括 activity 的分钟数、activity 的计数、activity 的等级、activity 的早晚等。

我认为您可以 extend the collection,添加自定义 insertDeep 函数。

一个想法:

Collection::macro('insertDeep', function (array $path, $value) {
    $key = array_shift($path);
   
    if (count($path) === 0) {
        $this->put($key, $value);
        return $this;
    }

    if (!$this->has($key)) {
        $this->put($key, new Collection());
    }

    return $this->get($key)->insertDeep($path, $value);
});

然后你可以简单地在你的集合上调用这个方法:

$this->myCollection->insertDeep([, , , ], $itemFor4);

我刚刚试了一下,它应该可以正常工作:

$coll = new Collection();
$coll->insertDeep(['a', 'b', 'c', 'd'], 'test');

$coll->toArray();
// Result
   [
     "a" => [
       "b" => [
         "c" => [
           "d" => "test",
         ],
       ],
     ],
   ]

免责声明:如果您指定一个键已存在但其值不是集合的路径,此函数将失败