查找子部门中的员工-PHP

查找子部门中的员工-PHP,php,mysql,codeigniter,recursion,activerecord,Php,Mysql,Codeigniter,Recursion,Activerecord,我正在使用Codeigniter+MySQL+Active Record构建一个具有组织结构图的项目 有列为组织树的部门、用于人员信息的员工、员工角色和我存储匹配的员工部门: 部门-员工-角色 您可以看到以下结构: 部门(父id用于构建树) 员工(原始员工信息) 员工角色(权重最低,层级最高) 员工部门(在哪个部门-谁-什么角色) 在以后的阶段中,一名员工可能属于两个或多个具有不同角色的部门。这就是为什么我对多对多部门使用单独的表格。在这种情况下,让我们保持简单,并假设1名员工属于1个部

我正在使用Codeigniter+MySQL+Active Record构建一个具有组织结构图的项目

有列为组织树的部门、用于人员信息的员工、员工角色和我存储匹配的员工部门: 部门-员工-角色

您可以看到以下结构:

部门(父id用于构建树)

员工(原始员工信息)

员工角色(权重最低,层级最高)

员工部门(在哪个部门-谁-什么角色)

在以后的阶段中,一名员工可能属于两个或多个具有不同角色的部门。这就是为什么我对多对多部门使用单独的表格。在这种情况下,让我们保持简单,并假设1名员工属于1个部门

我想做什么:

  • 部门经理(角色权重=0 | |角色id=1)可以查看在其部门工作的员工(员工和主管)和属于其部门子部门的所有员工(员工和主管)。这棵树的深度不得而知
  • 主管可以查看仅在其部门工作的员工(仅限员工)
  • 员工只能查看自己
  • 对于主管和员工来说,这个过程很简单,所以我认为我可以接受。对于管理者来说,我可能必须做一些递归的事情,但每次我开始编写一些代码时,我都会感到很挣扎

    我的想法是在我的控制器中有一个函数find_related_staff($staff_id){},我将传递登录人员的id,它将返回一个包含其相关人员id的数组。我得到的唯一信息是登录员工的ID

    如果经理返回其部门相关的经理、主管和员工的ID,以及 他所在部门的儿童部门

    如果主管仅返回其部门相关主管和员工的ID

    如果员工返回其ID


    你知道如何做到这一点吗

    是的,要完成它,必须使用递归过程。(我正在使用MySQL 5.6.19)

    我在存储过程之前创建了一些测试数据:

  • 基于您的问题要求的样本数据:

    create table departments
    (
        id int not null primary key auto_increment,
        parent_id int,
        department_name varchar(100)
    );
    
    insert into departments (id,parent_id,department_name)
    values
    (1,0,'Test A'),
    (2,1,'Test B'),
    (3,2,'Test C');
    
    
    create table staff
    (
        id int not null primary key auto_increment,
        ip_address varchar(100),
        username varchar(100)
    );
    
    insert into staff values
    (1,'127.0.0.1','ats'),
    (2,'127.0.0.1','admin'),
    (3,'127.0.0.1','george'),
    (4,'127.0.0.1','jhon')
    ;
    
    create table staff_roles
    (
        role_id int not null primary key auto_increment,
        role_name varchar(100),
        role_height int
    );
    
    insert into staff_roles values
    (1,'Manager',0),
    (2,'Supervisor',1),
    (3,'Employee',2)
    ;
    
    create table staff_departments
    (
        staff_department_id int not null primary key auto_increment,
        department_id int,
        staff_id int,
        role_id int
    );
    
    insert into staff_departments values
    (1,1,2,1),
    (2,2,1,2),
    (3,3,3,3),
    (4,3,4,3);
    
  • 现在是创建存储过程的时候了:

    • find_related_staff
      是接收
      staff_id
      参数的过程,根据该值将在
      staff_departments
      表中查找
      角色id

      变量
      @result
      将最终结果累加为逗号分隔的值

    • find_recursive
      是在子部门中搜索并将员工id放入
      @result
      变量的过程

    程序代码:

    delimiter $$
    drop procedure if exists find_related_staff$$
    create procedure  find_related_staff(p_id int)
    begin
        declare p_role_id int;
        declare p_department_id int;
        declare p_return varchar(255) default '';
        declare p_role varchar(100);
    
        select d.role_id, d.department_id, r.role_name
            into p_role_id,p_department_id, p_role
            from staff_departments d
            inner join staff_roles r on d.role_id = r.role_id
            where d.staff_id = p_id
            limit 1;
    
        case p_role_id
        when 3 then -- employee (return the same id)
                set @result = p_id;
    
            when 2 then -- supervisor 
    
                select group_concat(s.staff_id)
            into @result
            from staff_departments s
            where 
                  s.role_id = 3
                  and s.department_id in 
                     ( select d.id 
                       from departments d
                       where d.parent_id = p_department_id )
                  and s.role_id <> p_id;
    
    
            when 1 then -- manager (complex recursive query)
    
                select coalesce(group_concat(s.staff_id),'')
                  into @result
                from staff_departments s
                where 
                  s.department_id =  p_department_id
                  and s.staff_id <>  p_id;
    
               -- here we go!
               call find_recursive(p_department_id);
        end case;
    
        select @result as result, p_role as role;
    end $$
    delimiter ;
    
    delimiter $$
    drop procedure if exists find_recursive$$
    create procedure  find_recursive(p_dept_id int)
    begin
        declare done int default false;
        declare p_department int default false;
    
        declare tmp_result varchar(255) default '';
        -- cursor for all depend departments
        declare c_departments cursor for
            select s.department_id
            from staff_departments s
            where 
                  s.department_id in 
              ( select d.id 
                    from departments d
                    where d.parent_id = p_dept_id );
    
        declare continue handler for not found set done = true;
    
    
        -- getting current departmens
        set tmp_result = 
            (select coalesce(group_concat(s.staff_id),'')
                from staff_departments s
                where 
                  s.department_id in 
                  ( select d.id 
                    from departments d
                    where d.parent_id = p_dept_id ));
    
    
        if length(tmp_result) > 0 then
    
            if length(@result) > 0 then
                set @result = concat(@result,',',tmp_result);
            else
                set @result = tmp_result;
            end if;
    
            open c_departments;
    
            read_loop: loop
                fetch c_departments into  p_department;
                if done then
                  leave read_loop;
                end if;
    
            call find_recursive(p_department);
    
            end loop;
            close c_departments;            
    
        end if;
    
    end $$
    delimiter ;
    
    现在,我们在您的
    staff\u departments
    表上有以下配置:

    +---------------------+---------------+----------+---------+
    | staff_department_id | department_id | staff_id | role_id |
    +---------------------+---------------+----------+---------+
    |                   1 |             1 |        2 |       1 |
    |                   2 |             2 |        1 |       2 |
    |                   3 |             3 |        3 |       3 |
    |                   4 |             3 |        4 |       3 |
    +---------------------+---------------+----------+---------+
    
    运行每个案例:

    call find_related_staff(2);
    +--------+---------+
    | result | role    |
    +--------+---------+
    | 1,3,4  | Manager |
    +--------+---------+
    
    
    
    call find_related_staff(1);
    +--------+------------+
    | result | role       |
    +--------+------------+
    | 3,4    | Supervisor |
    +--------+------------+
    
    
    call find_related_staff(3);
    +--------+----------+
    | result | role     |
    +--------+----------+
    |      3 | Employee |
    +--------+----------+
    
    call find_related_staff(4);
    +--------+----------+
    | result | role     |
    +--------+----------+
    |      4 | Employee |
    +--------+----------+
    
  • 享受吧


  • 好的,我认为,为了让事情更容易理解,我们需要把你的问题分解成小块(我只关注你说你真的需要帮助的部分:经理的递归)

    首先,我们获得与用户关联的当前部门的身份验证。正如您所说,您只有当前签名的员工的ID,因此我们将从该ID开始。假设用户id被分配给变量$user\u id

    $user_department = $this->db->get_where('staff_departments', ['staff_id' => $user_id])->row();
    
    现在我们有了这个部门,我们检查一下用户在这个部门中的角色是什么。我们将把该信息添加到$user\u department对象:

    $user_department->role = $this->db->get_where('staff_roles', ['role_id' => $user_department->role_id])->row();
    
    让我们检查一下用户角色的权重,好吗?如果为0,我们知道它是该部门的经理,因此我们将递归查找嵌套的部门及其员工信息。根据您的逻辑,我们可以在此处检查用户是否是主管,并在必要时上报。像这样:

    if ($user_department->role->role_weight <= 1) {
        // the user is a supervisor OR a manager, but both those can see, at least, the current department's staff information
        $user_department->staff = $this->db->get_where('staff_departments', ['department_id' => $user_department->department_id]);
    
        // now is the user a manager? If so, let's find nested departments
        if ($user_department->role->role_weight === 0) {
            $user_department->childs = $this->getChildDepartmentsAndStaffOf($user_department->department_id);
        }
    }
    
    现在,你有了你想要的结构。我知道这可能会被重构,但我认为这足以让你得到答案,并为你指明正确的道路


    希望我能帮点忙。

    我认为关系数据库中分层数据最强大的模式是

    给定
    部门
    表的示例数据:

    +---------------------+---------------+----------+---------+
    | staff_department_id | department_id | staff_id | role_id |
    +---------------------+---------------+----------+---------+
    |                   1 |             1 |        2 |       1 |
    |                   2 |             2 |        1 |       2 |
    |                   3 |             3 |        3 |       3 |
    |                   4 |             3 |        4 |       3 |
    +---------------------+---------------+----------+---------+
    
    department_id | parent_id | department_name
    --------------|-----------|----------------
    1 | 0 |测试A
    2 | 1 |测试B
    3 | 2 |测试C
    
    您的闭包表(我们称之为
    departments\u tree
    )如下所示:

    super_id | sub_id
    ---------|-------
    1 |      1
    1 |      2
    1 |      3
    2 |      2
    2 |      3
    3 |      3
    
    读作:
    super\u id
    =上级部门id<代码>子部门id=下属部门id

    假设登录用户是部门id为2的部门经理,则获取所有“受监督”员工的查询为:

    选择不同的s*
    来自部门
    在sd.department\u id=t.sub\u id上加入stuff\u departments sd
    在s.id=sd.staff\u id上加入员工
    其中t.super_id=2
    
    可以使用触发器填充和更新闭包表

    插入触发器:

    分隔符//
    为每行的“departments”在“departments”上插入后创建触发器“departments”
    插入到部门树(超级id、子id)
    选择new.department\u id、new.department\u id
    联合所有
    选择super\u id、new.department\u id
    从树上
    其中sub_id=new.parent_id;
    结束//
    定界符;
    
    删除触发器:

    分隔符//
    在删除之前创建触发器'departments\u\u delete''
    
    public function getChildDepartmentsAndStaffOf($department_id)
    {
        $child_departments = $this->db->get_where('departments', ['parent_id' => $department_id]);
    
        if (! $child_departments) {
            return null;
        }
    
        foreach ($child_departments as &$department) {
            $department->staff = $this->db->get_where('staff_departments', ['department_id' => $department->department_id]);
    
            $department->childs = $this->getChildDepartmentsAndStaffOf($department->department_id);
        }
    
        return $child_departments;
    }
    
    class DB {
        private $servername = "127.0.0.1";
        private $username = "root";
        private $password = "root";
        private $dbname = "test";
        private $port = '3306';
    
        public function getRecursiveDepts($deptIds) {
            if (!is_array($deptIds)) {
                $deptIds = array($deptIds);
            }
            $sql = "SELECT id FROM Departments WHERE parentId IN (";
            $sql .= implode(', ', $deptIds);
            $sql .= ")";
    
            $conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname, $this->port);
            if ($conn->connect_error) {
                die("Connection failed: " . $conn->connect_error);
            }
            $result = $conn->query($sql);
            if ($result->num_rows > 0) {
                $newDept = array();
                while($row = $result->fetch_assoc()) {
                    array_push($newDept, $row['id']);
                }
                $conn->close();
                $moreDepts = $this->getRecursiveDepts($newDept);
                if (is_null($moreDepts)) {
                    $finalIds = array_unique(array_merge($deptIds, $newDept));
                } else {
                    $finalIds = array_unique(array_merge($deptIds, $newDept, $moreDepts));
                }
                return $finalIds;
            } else {
                $conn->close();
                return null;
            }
        }
    
        public function getRoles($empId) {
            $sql = "SELECT role_id, department_id FROM staff_departmen_role WHERE staff_id = '$empId' GROUP BY role_id, department_id";
            $conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname, $this->port);
            if ($conn->connect_error) {
                die("Connection failed: " . $conn->connect_error);
            }
            $result = $conn->query($sql);
            if ($result->num_rows > 0) {
                $emp = array();
                while($row = $result->fetch_assoc()) {
                    if (!array_key_exists($row['role_id'], $emp)) {
                        $emp[$row['role_id']] = array();
                    }
                    array_push($emp[$row['role_id']], $row['department_id']);
                }
            }
            $conn->close();
            return $emp;
        }
    
        public function getEmpDetails($empId) {
            $sql = "SELECT role_id, department_id FROM staff_departmen_role WHERE staff_id = '$empId' GROUP BY role_id, department_id";
            $conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname, $this->port);
            if ($conn->connect_error) {
                die("Connection failed: " . $conn->connect_error);
            }
            $result = $conn->query($sql);
            if ($result->num_rows > 0) {
                $emp = array();
                while($row = $result->fetch_assoc()) {
                    if (!array_key_exists($row['role_id'], $emp)) {
                        $emp[$row['role_id']] = array();
                    }
                    array_push($emp[$row['role_id']], $row['department_id']);
                }
            }
            $conn->close();
            return $emp;
        }
    }
    
    <?php
    include_once 'db.php';
    
    $objDB = new DB();
    
    $empId = 2;
    
    $emps = $objDB->getRoles($empId);
    foreach ($emps as $roleId => $deptIds) {
        switch ($roleId) {
            case 1:
                $allDeptIds = $objDB->getRecursiveDepts($deptIds);
                break;
    
            case 2://Supervisor GetEmpIds of current dept role >= 2
    
                break;
    
            case 3://Employee GetEmpIds of current dept role >= 2
                $emp = $objDB->getEmpDetails($empId);
                break;
    
            default:
                # code...
                break;
        }
    }
    $data = $objDB->getRecursiveDepts($empId);
    print_r($data);
    ?>