在Laravel 12中实现基于parent_id的树状数组

在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)。
  • 灵活扩展:可轻松添加排序逻辑或在资源中定制返回字段。
  • 避免循环:树状结构默认无循环,但存在循环引用时需额外处理。

此方法适用于大多数树状结构需求,如分类目录、组织架构等场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值