0

0

Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】

尼克

尼克

发布时间:2025-12-31 15:54:56

|

324人浏览过

|

来源于php中文网

原创

用hasMany+belongsTo实现无限分类本质是自关联,Category模型需定义children(hasMany)和parent(belongsTo+withDefault)两个关系,配合withChildren递归加载或path路径字段优化查询性能。

laravel如何实现多级无限分类_laravel递归模型关联与树状数据输出【方法】

hasMany + belongsTo 实现父子关联结构

无限分类本质是「自关联」,Laravel 中最直接的方式是让模型同时定义子集关系和父级关系。假设模型叫 Category,数据库有 idnameparent_id(允许为 NULL)三个关键字段。

Category 模型里写两个关联方法:

public function children()
{
    return $this->hasMany(Category::class, 'parent_id');
}

public function parent() { return $this->belongsTo(Category::class, 'parent_id')->withDefault();

注意:withDefault() 能避免根节点调用 $category->parent->name 时抛出 Trying to get property 'name' of non-object 错误。

  • children() 用于向下查子类,支持链式调用如 $category->children()->with('children')
  • parent() 用于向上查父类,建议加 withDefault() 防空指针
  • 不要在迁移中给 parent_id 加外键约束(除非你确定所有数据都严格符合树结构),否则软删除或临时断开关系时容易报错

递归获取完整树状结构(Eloquent 原生方式)

不依赖第三方包,用 Eloquent 的 with + 递归加载即可一次性取出整棵树。适用于层级不深(一般 ≤ 5 层)、数据量不大(几百条以内)的场景。

例如获取全部根节点及其子孙:

$tree = Category::whereNull('parent_id')
    ->with('children.children.children') // 手动展开 3 层
    ->get();

但硬编码层数不灵活。更通用的做法是封装一个递归加载器:

public function scopeWithChildren($query)
{
    return $query->with(['children' => fn ($q) => $q->withChildren()]);
}

然后调用:

$tree = Category::whereNull('parent_id')->withChildren()->get();
  • 该写法会触发 N+1 查询优化后的嵌套查询,Laravel 9+ 支持这种闭包式嵌套加载
  • 深度过大会导致内存占用高,比如单棵树有上千节点,建议改用「预计算路径」方案
  • 如果用了 SoftDeletes,记得在 children() 关联里加 withTrashed() 或过滤逻辑,否则被软删的中间节点会导致树断裂

输出 HTML 树状菜单时避免重复渲染与深度失控

Blade 中递归渲染树最容易出问题的是:模板自己调自己导致无限循环,或没控制层级导致页面卡死。

推荐做法是在控制器中把数据转成扁平化带层级标识的数组,再传给视图;或者在 Blade 中用带深度参数的子视图。

Red Panda AI
Red Panda AI

AI文本生成图像

下载

例如建一个 resources/views/categories/tree.blade.php

@props(['categories', 'depth' => 0])

@foreach($categories as $category)

{{ $category->name }} @if($category->children->isNotEmpty()) @include('categories.tree', ['categories' => $category->children, 'depth' => $depth + 1]) @endif
@endforeach

在主视图中调用:

@include('categories.tree', ['categories' => $tree])
  • 必须传入 $depth 并做递归限制(比如加 @if($depth 判断),防止意外形成环形引用崩溃
  • 不要在循环里反复调用 $category->children,必须提前用 with 加载好,否则变 N+1 查询
  • 若需生成 下拉菜单,建议用 collect($tree)->toTree()(需手动实现)或转成带前缀的扁平数组,比递归渲染更可控

需要高性能或复杂操作时,考虑「路径字段」替代递归查询

当分类数超千、层级深、频繁查询祖先/后代时,Eloquent 递归很快成为瓶颈。这时应放弃纯关系模型,改用「路径存储」方案:在表中加一个 path 字段(如 "0001/0005/0023"),用字符串前缀匹配快速定位上下文。

典型操作示例:

  • 查某节点的所有后代:where('path', 'like', '0001/0005/%')
  • 查某节点的所有祖先:whereRaw("path REGEXP '^([0-9]+/)*0005$')"(或拆分后 in 查询)
  • 移动节点只需更新其自身及所有后代的 path 字段,无需递归更新关系

缺点是写操作变重、路径长度需预估、迁移成本高。但读多写少的后台管理场景下,这是最稳的选择。

真正麻烦的不是怎么实现,而是前期没想清楚:这个分类会不会被前端频繁拖拽排序?会不会导出到其他系统?要不要支持多语言别名?这些需求一旦出现,光靠 parent_id 就撑不住了。

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

1963

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1290

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1196

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

948

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1400

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1229

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1439

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1303

2023.11.13

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 8.1万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 6.9万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号