如何在Laravel 9中编写递归函数获取用户的全层级下属
递归获取Laravel中用户的多级下属嵌套结构
你已经有了获取直接下属的方法,要实现多级嵌套的层级结构其实很简单,我们可以基于现有的userDirectSubordinates方法写一个递归函数来完成这个需求。
基础递归实现(简单直接)
先看最直观的实现方式,直接在递归里复用你已有的代码:
private function getUserHierarchy($user_id, $company_id) { // 先获取当前用户的直接下属 $subordinates = $this->userDirectSubordinates($user_id, $company_id); // 遍历每个下属,递归获取他们的所有层级下属 foreach ($subordinates as &$subordinate) { // 给当前下属添加children字段,值为该下属的下属层级 $subordinate['children'] = $this->getUserHierarchy($subordinate['id'], $company_id); } // 转成数组返回,完全符合你要的格式 return $subordinates->toArray(); }
调用方式
在控制器或业务逻辑中直接传入目标用户ID和公司ID即可:
// 示例:获取ID为1的用户在公司2中的完整下属层级 $fullHierarchy = $this->getUserHierarchy(1, 2);
这个方法逻辑清晰、上手快,但要注意:如果下属层级很深或者用户量很大,这种方式会触发N+1次数据库查询(每个层级都要查一次),性能会受影响。
优化版本(减少数据库查询)
如果担心性能问题,我们可以用Laravel支持的递归CTE(公共表表达式),一次性把所有层级的下属数据查出来,再转换成嵌套结构,这样只需要一次数据库查询:
private function getUserHierarchyOptimized($user_id, $company_id) { // 使用递归CTE查询所有层级的下属数据 $flatHierarchy = DB::withRecursive('user_hierarchy', function ($recursive) use ($company_id, $user_id) { // 第一步:获取初始用户的直接下属 $recursive->select( 'users.id', 'users.name as label', 'users.avatar', 'departments.name as department', 'company_user.superior_id' ) ->join('department_user', 'users.id', '=', 'department_user.user_id') ->join('departments', 'departments.id', '=', 'department_user.department_id') ->join('company_user', 'users.id', '=', 'company_user.user_id') ->where('departments.company_id', $company_id) ->where('company_user.superior_id', $user_id); // 第二步:递归获取下属的下属,直到没有更下层的用户 $recursive->unionAll(function ($query) use ($company_id) { $query->select( 'users.id', 'users.name as label', 'users.avatar', 'departments.name as department', 'company_user.superior_id' ) ->join('department_user', 'users.id', '=', 'department_user.user_id') ->join('departments', 'departments.id', '=', 'department_user.department_id') ->join('company_user', 'users.id', '=', 'company_user.user_id') ->join('user_hierarchy', 'company_user.superior_id', '=', 'user_hierarchy.id') ->where('departments.company_id', $company_id); }); }) ->select('id', 'label', 'avatar', 'department', 'superior_id') ->get(); // 把扁平的查询结果转换成嵌套结构 return $this->buildNestedHierarchy($flatHierarchy, $user_id); } // 辅助函数:将扁平数组转为嵌套的层级结构 private function buildNestedHierarchy($flatUsers, $parentId) { $children = []; foreach ($flatUsers as $user) { if ($user->superior_id == $parentId) { $userArray = $user->toArray(); // 递归查找当前用户的子级 $userArray['children'] = $this->buildNestedHierarchy($flatUsers, $user->id); $children[] = $userArray; } } return $children; }
调用方式
和基础版本一致,直接传入参数即可:
$fullHierarchy = $this->getUserHierarchyOptimized(1, 2);
这个版本的优势是只需要一次数据库查询,性能更优,适合用户量较大或者层级较深的场景。
两种方式都能生成你需要的带children字段的嵌套数组结构,你可以根据自己的业务场景选择合适的实现~
内容的提问来源于stack exchange,提问作者calin24
相关产品推荐
相关产品推荐

