You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 18:32:27