在Laravel中实现基于parent_id的树状数组,可以通过预加载所有节点并在内存中递归构建树结构来完成。以下是具体步骤和代码示例:
1. 创建模型及数据库迁移
迁移文件:
// 创建节点表
Schema::create('nodes', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('parent_id')->nullable();
$table->string('name');
$table->timestamps();
});
模型:
// app/Models/Node.php
class Node extends Model
{
protected $fillable = ['parent_id', 'name'];
// 子节点关系
public function children()
{
return $this->hasMany(Node::class, 'parent_id');
}
// 父节点关系
public function parent()
{
return $this->belongsTo(Node::class, 'parent_id');
}
}
2. 获取所有节点并构建树
控制器方法:
use App\Models\Node;
public function getTree()
{
$nodes = Node::all();
$groupedNodes = $nodes->groupBy('parent_id');
$buildTree = function ($parentId = null) use (&$buildTree, $groupedNodes) {
$result = [];
if ($groupedNodes->has($parentId)) {
foreach ($groupedNodes->get($parentId) as $node) {
$node->children = $buildTree($node->id);
$result[] = $node;
}
}
return $result;
};
$tree = $buildTree();
return response()->json($tree);
}
3. 使用API资源格式化输出(可选)
创建资源:
php artisan make:resource NodeResource
定义资源结构:
// app/Http/Resources/NodeResource.php
class NodeResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'children' => NodeResource::collection($this->children),
];
}
}
更新控制器:
use App\Http\Resources\NodeResource;
public function getTree()
{
$nodes = Node::all();
$groupedNodes = $nodes->groupBy('parent_id');
$buildTree = function ($parentId = null) use (&$buildTree, $groupedNodes) {
return collect($groupedNodes->get($parentId, []))->map(function ($node) use ($buildTree) {
$node->children = $buildTree($node->id);
return $node;
});
};
$tree = $buildTree();
return NodeResource::collection($tree);
}
4. 结果示例
生成的树状结构JSON如下:
[
{
"id": 1,
"name": "Root 1",
"children": [
{
"id": 3,
"name": "Child 1-1",
"children": [
{
"id": 5,
"name": "Child 1-1-1",
"children": []
}
]
},
{
"id": 4,
"name": "Child 1-2",
"children": []
}
]
},
{
"id": 2,
"name": "Root 2",
"children": []
}
]
说明
- 高效查询:仅需一次数据库查询获取所有节点,减少IO开销。
- 内存构建:通过
groupBy
按父ID分组,递归构建树结构,时间复杂度为O(n)。 - 灵活扩展:可轻松添加排序逻辑或在资源中定制返回字段。
- 避免循环:树状结构默认无循环,但存在循环引用时需额外处理。
此方法适用于大多数树状结构需求,如分类目录、组织架构等场景。在Laravel中实现基于parent_id的树状数组,可以通过预加载所有节点并在内存中递归构建树结构来完成。以下是具体步骤和代码示例:
1. 创建模型及数据库迁移
迁移文件:
// 创建节点表
Schema::create('nodes', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('parent_id')->nullable();
$table->string('name');
$table->timestamps();
});
模型:
// app/Models/Node.php
class Node extends Model
{
protected $fillable = ['parent_id', 'name'];
// 子节点关系
public function children()
{
return $this->hasMany(Node::class, 'parent_id');
}
// 父节点关系
public function parent()
{
return $this->belongsTo(Node::class, 'parent_id');
}
}
2. 获取所有节点并构建树
控制器方法:
use App\Models\Node;
public function getTree()
{
$nodes = Node::all();
$groupedNodes = $nodes->groupBy('parent_id');
$buildTree = function ($parentId = null) use (&$buildTree, $groupedNodes) {
$result = [];
if ($groupedNodes->has($parentId)) {
foreach ($groupedNodes->get($parentId) as $node) {
$node->children = $buildTree($node->id);
$result[] = $node;
}
}
return $result;
};
$tree = $buildTree();
return response()->json($tree);
}
3. 使用API资源格式化输出(可选)
创建资源:
php artisan make:resource NodeResource
定义资源结构:
// app/Http/Resources/NodeResource.php
class NodeResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'children' => NodeResource::collection($this->children),
];
}
}
更新控制器:
use App\Http\Resources\NodeResource;
public function getTree()
{
$nodes = Node::all();
$groupedNodes = $nodes->groupBy('parent_id');
$buildTree = function ($parentId = null) use (&$buildTree, $groupedNodes) {
return collect($groupedNodes->get($parentId, []))->map(function ($node) use ($buildTree) {
$node->children = $buildTree($node->id);
return $node;
});
};
$tree = $buildTree();
return NodeResource::collection($tree);
}
4. 结果示例
生成的树状结构JSON如下:
[
{
"id": 1,
"name": "Root 1",
"children": [
{
"id": 3,
"name": "Child 1-1",
"children": [
{
"id": 5,
"name": "Child 1-1-1",
"children": []
}
]
},
{
"id": 4,
"name": "Child 1-2",
"children": []
}
]
},
{
"id": 2,
"name": "Root 2",
"children": []
}
]
说明
- 高效查询:仅需一次数据库查询获取所有节点,减少IO开销。
- 内存构建:通过
groupBy
按父ID分组,递归构建树结构,时间复杂度为O(n)。 - 灵活扩展:可轻松添加排序逻辑或在资源中定制返回字段。
- 避免循环:树状结构默认无循环,但存在循环引用时需额外处理。
此方法适用于大多数树状结构需求,如分类目录、组织架构等场景。