Laravel 11 中推荐用自关联模型+内存递归构建无限级分类树:定义 children/parent 关系,预加载后通过 buildTree 方法转为 JSON 树结构,并用 keyBy 优化性能。

在 Laravel 11.x 中实现无限级分类并返回树形 JSON,核心是利用模型的「父子关系」+ 「递归构建」,推荐使用 Eloquent 的嵌套集合(Nested Set)或自关联(Self-Relationship)两种方式。对大多数业务场景(如文章分类、商品类目),**自关联 + 递归转数组**更轻量、易维护,且兼容性好。
✅ 使用自关联模型 + 递归构造树结构
假设分类表 categories 包含字段:id、name、parent_id(为 null 表示顶级)。
1. 定义模型关系(app/Models/Category.php):
注意:Laravel 11 默认启用强制类型和严格模式,确保 parent_id 允许 null(数据库字段设为 nullable)
- 添加
children()关系(一对多) - 添加
parent()关系(一对一,用于反查)
```php
class Category extends Model
{
protected $fillable = ['name', 'parent_id'];
public function children()
{
return $this->hasMany(Category::class, 'parent_id');
}
public function parent()
{
return $this->belongsTo(Category::class, 'parent_id');
}
}
✅ 控制器中构建并返回树形 JSON
不建议在视图或响应中实时递归查询(N+1 问题),应先获取全部分类,再内存中构建树。
在控制器方法中(例如 CategoryController@index):
- 用
with('children')预加载所有子项(一层深度) - 通过
whereNull('parent_id')获取所有根节点 - 编写辅助方法
buildTree($categories)递归扁平转树
示例代码片段:
```php
public function index()
{
$all = Category::with('children')->get();
$roots = $all->whereNull('parent_id');
$tree = $this->buildTree($roots, $all);
return response()->json($tree);
}
protected function buildTree($nodes, $all)
{
return $nodes->map(function ($node) use ($all) {
$children = $all->where('parent_id', $node->id);
return $node->merge([
'children' => $this->buildTree($children, $all)
]);
})->values();
}
✅ 优化:避免重复遍历,用 ID 建索引提升性能
当分类数量较大(如 >500 条)时,上述 $all->where(...) 会多次遍历集合。可提前构建哈希映射:
- 用
$map = $all->keyBy('id')构建 ID → 模型映射 - 递归时用
$map->get($parentId)快速查找,O(1) - 同时过滤出 children 时用
$all->filter(...)或直接用集合操作
这样即使上千条分类,构建树也仅需毫秒级。
✅ 可选:使用 spatie/laravel-nestedset(适合深度操作)
若需频繁移动节点、获取祖先链、判断层级等,推荐安装 spatie/laravel-nestedset:
- 自动维护
lft/rgt字段 - 一行代码获取整棵树:
Category::defaultOrder()->get()->toTree() - 返回的就是已组织好的嵌套集合,直接
json_encode即可
注意:需迁移新增字段,并在模型中 use HasNestedSets trait。











