Написать рекурсивный запрос функции со всеми подчиненными

У меня есть эта функция в laravel 9

private function userDirectSubordinates($user_id, $company_id) 
{
    return User::select(['users.id', 'users.name as label', 'avatar', 'departments.name as department'])
        ->join('department_user', 'users.id', '=', 'department_user.user_id')
        ->join('departments', 'departments.id', '=', 'department_user.department_id')
        ->where('departments.company_id', $company_id)
        ->whereIn('users.id', function($query) use($user_id) {
            $query->select('user_id')
                ->from('company_user')
                ->where('superior_id', $user_id);
        })
        ->get();
}

Эта функция возвращает прямых подчиненных для пользователя с id $user_id из выбранной компании $company_id. Пример:

[
    ["id" => 880, 'label' => 'User 880', 'avatar' => null, 'department' => 'IT'],
    ["id" => 41, 'label' => 'User 41', 'avatar' => null, 'department' => 'Finance'],
    ...
]

Как мне сделать рекурсивную функцию для получения от каждого пользователя из directSubordinates... всех подчиненных. Окончательный массив должен выглядеть так:

[
    ["id" => 880, 'label' => 'User 880', 'avatar' => null, 'department' => 'IT',
        'children' => [
            ["id" => 32, 'label' => 'User 32', 'avatar' => null, 'department' => 'IT', 'children' => []],
            ["id" => 56, 'label' => 'User 56', 'avatar' => null, 'department' => 'IT',
                'children' => [
                    ["id" => 21, 'label' => 'User 21', 'avatar' => null, 'department' => 'Maintenance', 'children' => []],
                    ["id" => 687, 'label' => 'User 687', 'avatar' => null, 'department' => 'Development',
                        'children' => [
                            ["id" => 334, 'label' => 'User 334', 'avatar' => null, 'department' => 'Development', 'children' => []],
                            ["id" => 335, 'label' => 'User 335', 'avatar' => null, 'department' => 'Development', 'children' => []],
                        ]
                    ]
                ],
            ]
        ],
    ],
   ...  
];
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Что нового в PHP 8.1?
Что нового в PHP 8.1?
Если вы все еще используете PHP 7, то эта статья для вас. В PHP 8, а именно в PHP 8.1, встроены некоторые очень востребованные функции, которые вам...
Разработка LMS на заказ для повышения эффективности работы и обучения
Разработка LMS на заказ для повышения эффективности работы и обучения
За последние годы в образовании произошла большая революция, и сегодня почти все учебные заведения делают упор на эксклюзивное управление учебным...
0
0
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предположительно, вы используете MySQL 8 с Laravel 9, что означает, что вы можете сделать это (рекурсивно с синтаксисом):

SQL:

select users.id, users.username as username, departments.name as dept, company_user.superior_id as superior_id
FROM users
INNER JOIN department_user on users.id = department_user.user_id
INNER JOIN departments on departments.id = department_user.department_id
INNER JOIN company_user on company_user.user_id = users.id
WHERE
    departments.company_id = 1
    AND
    users.id IN (
      with recursive cte (user_id) as (
        select     user_id
        from       company_user
        where      superior_id = 1
        union all
        select     parent.user_id
        from       company_user parent
        inner join cte
        on parent.superior_id = cte.user_id
      )
      select * from cte
    )

Лично я бы не стал использовать для этого конструктор запросов Laravel (просто используйте raw).

В результате вы получите что-то вроде:

enter image description here

обратите внимание, что родитель (целевой пользователь) отсутствует, и вы должны сначала получить его.

теперь вы можете перебрать данные и добавить дочерние элементы к их родителям в PHP и создать дерево:

$user = User::find($user_id);
$subordinates = DB::select($query)->get();

function buildTree(array &$subordinates, $parentId) {

    $branch = array();

    foreach ($subordinates as &$subordinate) {

        if ($subordinate['superior_id'] == $parentId) {
            $children = buildTree($subordinates, $subordinate['id']);
            if ($children) {
                $subordinate['children'] = $children;
            }
            $branch[] = $subordinate;
            unset($subordinate);
        }
    }
    return $branch;
}

$user['children'] = buildTree($subordinates, $user['id']);

Я проверил ваш sql, но.... согласно моему запросу.. прямых подчиненных для Superior_id 1 равно 16. По вашему запросу я получаю прямых подчиненных только 5

calin24 09.04.2022 19:21

Поскольку у меня нет ваших данных, я не могу проверить, что мое решение неверно. Это сработало с набором данных, который я создал для тестирования. Может, мне как-то дать конкретные данные для тестирования?

Ali Rahimi 09.04.2022 20:22

Ваше решение в порядке. Я делал что-то не так :-) Я пытался внести некоторые изменения (отредактировать), но это не позволяет (.... Предложенная очередь редактирования заполнена...)... в любом случае вам нужно добавить дополнительное условие в главное где WHERE departments.company_id = 1 AND company_user.company_id = 1. Вторая ошибка: DB::select($query); без get(). Третье: при вызове $subordinate['superior_id'] (нельзя использовать объект типа stdClass в качестве массива) должно быть так: $subordinate->superior_id. Еще раз спасибо за информацию ;)

calin24 10.04.2022 14:18

Другие вопросы по теме