aim*_*mme 8 php arrays laravel eloquent laravel-query-builder
如何将具有层次结构自引用模型、树集合的集合展平为单维集合。我有一个有父母和孩子的自引用模型。
我希望结果返回一个雄辩的集合,而不是一个简单的集合或数组。数组已用作结果结果以方便演示
关系是这样声明的。
public function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
public function parentRecursive()
{
return $this->parent()->with('parentRecursive');
}
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
public function childrenRecursive()
{
return $this->children()->with('childrenRecursive');
}
Run Code Online (Sandbox Code Playgroud)
所以当我调用model->childrenRecursive它时,它会按原样返回集合。像这样。我对其进行了更改toArray()以使其易于阅读。
array:1 [
0 => array:6 [
"id" => 5
"name" => "I am a child of 1"
"parent_id" => "1"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => array:1 [
0 => array:6 [
"id" => 6
"name" => "I am child of 5"
"parent_id" => "5"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => array:2 [
0 => array:6 [
"id" => 7
"name" => "I am child of 6"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => []
],
1 => array:6 [
"id" => 8
"name" => "I am child of 6 too"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => []
]
]
]
]
]
]
Run Code Online (Sandbox Code Playgroud)
我想要实现的是单维集合。这是toArray()该集合的外观。
array:4 [
0 => array:6 [
"id" => 5
"name" => "I am a child of 1"
"parent_id" => "1"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
],
1 => array:6 [
"id" => 6
"name" => "I am child of 5"
"parent_id" => "5"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
],
2 => array:6 [
"id" => 7
"name" => "I am child of 6"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
],
3 => array:6 [
"id" => 8
"name" => "I am child of 6 too"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
]
]
Run Code Online (Sandbox Code Playgroud)
我试过很多收集方法类似filter,flatMap,flatten和多阵列的方法。但还没有找到合适的解决方案。
我也没有在Laravel集合中找到任何内置方法。您可以尝试这样的事情(将其用作全局函数或专用类方法,这取决于您。这是想法):
function flatten($array) {
$result = [];
foreach ($array as $item) {
if (is_array($item)) {
$result[] = array_filter($item, function($array) {
return ! is_array($array);
});
$result = array_merge($result, flatten($item));
}
}
return array_filter($result);
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它:
// When available into global scope as a function
$flattenArray = flatten($arrayFromTheCollection);
Run Code Online (Sandbox Code Playgroud)
有点晚了,但我将发布我希望在我最终自己编写之前能够找到的内容。
与原始帖子类似,我的表中有一个递归父/子关系categories(但这适用于任何带有自引用parent_id列的表)。您可以像这样设置模型:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model {
// Relationships
public function parent()
{
return $this->belongsTo('App\Models\Category', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Models\Category', 'parent_id');
}
public function nested_ancestors()
{
return $this->belongsTo('App\Models\Category', 'parent_id')->with('parent');
}
public function nested_descendants()
{
return $this->hasMany('App\Models\Category', 'parent_id')->with('children');
}
// Attributes
public function getFlatAncestorsAttribute()
{
return collect(flat_ancestors($this));
}
public function getFlatDescendantsAttribute()
{
return collect(flat_descendants($this));
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的应用程序的某个地方,你需要有一个地方来放置一些全局辅助函数。您可以按照此处找到的说明进行操作,然后粘贴以下辅助函数:
function flat_ancestors($model) {
$result = [];
if ($model->parent) {
$result[] = $model->parent;
$result = array_merge($result, flat_ancestors($model->parent));
}
return $result;
}
function flat_descendants($model) {
$result = [];
foreach ($model->children as $child) {
$result[] = $child;
if ($child->children) {
$result = array_merge($result, flat_descendants($child));
}
}
return $result;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码将允许您使用$category->flat_ancestors,这将生成所有类别祖先的平面集合,无论有多少。类似地, using$category->flat_descendants将产生所有子类别和孩子的子类别的平面集合,依此类推,直到所有后代类别都被考虑在内。
需要注意的一些事项:
Category 1引用Category 2作为其母公司,再Category 2有Category 1是其父母。请注意父母/子女的关系是无乱伦的 :-)flat_descendants函数,数据库查询的数量在每一代级别都呈指数增长。这将递归地展平。但是它并不能防止重复,因此如果这是一个问题,您需要将它们过滤掉。
在你的AppServiceProvider::boot方法中
use Illuminate\Support\Collection;
//...
Collection::macro('flattenTree', function ($childrenField) {
$result = collect();
foreach ($this->items as $item) {
$result->push($item);
if ($item->$childrenField instanceof Collection) {
$result = $result->merge($item->$childrenField->flattenTree($childrenField));
}
}
return $result;
});
Run Code Online (Sandbox Code Playgroud)
然后
$flattened = $myCollection->flattenTree('childrenRecursive');
// or in the case of the question
$flattened = $model->childrenRecursive->flattenTree('childrenRecursive');
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6738 次 |
| 最近记录: |