Laravel树形结构菜单对象转数组求助,树形菜单实现遇阻
我之前在Laravel项目里也碰到过一模一样的需求——把带parent_id的树形菜单数据表转成嵌套数组,结合你的表结构,给你两个亲测好用的方案:
第一步:先给模型配置关联
首先得在你的菜单模型(假设叫Menu)里定义父级和子级的关联,这是Laravel处理树形结构的基础:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Menu extends Model { protected $fillable = ['title', 'slug', 'parent_id']; // 关联父级菜单 public function parent(): BelongsTo { return $this->belongsTo(Menu::class, 'parent_id'); } // 关联子菜单,顺便按标题排序 public function children(): HasMany { return $this->hasMany(Menu::class, 'parent_id')->orderBy('title'); } }
方案一:模型内封装递归方法(最直观)
直接在模型里写静态方法,把树形转数组的逻辑封装起来,调用起来特别方便:
// 在Menu模型里添加这两个方法 public static function toTreeArray(): array { // 先获取所有顶级菜单(parent_id=0),预加载子菜单避免N+1查询 $topMenus = self::where('parent_id', 0)->with('children')->get(); return self::buildTree($topMenus); } private static function buildTree($menus): array { $tree = []; foreach ($menus as $menu) { // 先把菜单对象转成基础数组 $item = $menu->toArray(); // 如果当前菜单有子菜单,递归处理子菜单 if ($menu->children->isNotEmpty()) { $item['children'] = self::buildTree($menu->children); } $tree[] = $item; } return $tree; }
调用方式也很简单,在控制器或者任何地方直接用:
$menuTree = Menu::toTreeArray(); // 打印看看结果 dd($menuTree);
方案二:利用Laravel集合操作(更灵活)
如果你不想把逻辑写在模型里,或者需要更灵活的处理(比如自定义字段),可以用集合的方法来实现:
// 在控制器里写这段代码 use App\Models\Menu; public function getMenuTree() { // 获取所有菜单,用id做键名方便快速查找 $allMenus = Menu::all()->keyBy('id'); // 筛选出顶级菜单,然后递归构建子菜单 $menuTree = $allMenus->filter(function ($menu) { return $menu->parent_id === 0; })->map(function ($menu) use ($allMenus) { return $this->buildMenuItem($menu, $allMenus); })->values()->toArray(); return $menuTree; } // 辅助方法:递归构建单个菜单项 private function buildMenuItem($menu, $allMenus): array { $item = $menu->toArray(); // 查找当前菜单的所有子菜单 $children = $allMenus->filter(function ($child) use ($menu) { return $child->parent_id === $menu->id; }); if ($children->isNotEmpty()) { $item['children'] = $children->map(function ($child) use ($allMenus) { return $this->buildMenuItem($child, $allMenus); })->values()->toArray(); } return $item; }
这两种方案都能完美把你的树形菜单转成嵌套数组,第一种更适合复用,第二种更灵活,你可以根据自己的需求选~
内容的提问来源于stack exchange,提问作者Ryan Den
相关产品推荐
相关产品推荐

