Laravel 多级分层用户系统

Posted

技术标签:

【中文标题】Laravel 多级分层用户系统【英文标题】:Laravel Multi-level hierarchical user system 【发布时间】:2015-11-05 04:35:12 【问题描述】:

我有一个应用程序使用 Laravel 作为后端 API,AngularJS 作为前端,具有多层用户树,用户“拥有”其他用户组。

例如,可能有一个所有者拥有主管,而主管又拥有员工。

员工有“墙”,上面有帖子和 cmets。只有员工有墙。树分支中的任何用户都可以在他的墙上查看/发布/评论 - 因此他的直接主管和所有者可以访问他的墙。

我希望将来可以扩展它以在两者之间添加更多“角色”,因此我不希望为每种用户类型设置单独的表。

我查看了自我反映模型,其中 users 表有一个 parent_id 列。我遇到了困难,因为 Auth::user->with('children') 正在返回所有用户,而忽略了模型中设置的关系:

public function children() 
  return $this->hasMany('User', 'parent_id');


public function parent() 
  return $this->belongsTo('User', 'parent_id');

问题是 - 是否有可用的包允许我通过这些分层用户关系自动确定查询范围?

或者您对这样的用户范例有什么建议?我尝试过的所有搜索和查看过的包裹都无处可寻。我认为使用嵌套集包对于这项任务来说太复杂了。我看过的所有身份验证包都没有真正适合这种范式。它们允许角色和权限,但不根据父子关系确定权限范围。

【问题讨论】:

很难理解你所问的真正要求。您是否不只是有一个包含角色的表,然后是一个 user_role 数据透视表,它允许您查询用户是否是员工、主管等?然后,您可以为此添加“查询范围”。如果我有误解,请告诉我,因为我讨厌在截止日期前在一个问题上空白,所以我很乐意提供帮助! 我已经实现了角色和权限。角色定义为职务,权限基于资源,允许在系统中为每个资源独立分配创建、读取、更新或删除。问题在于确定结果集的范围。并非每个主管都可以查看每个员工的数据 - 他们只能查看分配给他们的员工的数据。角色和权限部分正确地使主管数据远离员工,但不会缩小每个主管的员工范围。我的问题是除了角色和权限之外,如何定义这个层次结构 好的,所以在我发布答案之前 - 如果我理解正确 - 如果我是主管并且我有 x 个孩子,并且其中一些孩子也有 x 个孩子,我可以查看我的所有孩子及其子孩子及其子孩子的孩子的数据集? 是的,完全正确 - 暂时设置了子级的数量,但将来它必须是可扩展的。例如,将来可能会在主管和员工之间创建一个“团队领导”职位。如果在数据库中定义了关系并且以后添加到层次结构中不需要编辑代码(即客户可以随意更改它),则可以加分 我感觉有一些自反查询(用户表中的 parent_id)和特征/查询范围的组合来解决这个问题,但我希望有一些优雅的东西! 【参考方案1】:

目前,一种可行的硬编码解决方案是向 User 模型添加子关系:

public function children() 
  return $this->hasMany('User', 'parent_id');

...在 AuthController 中(我希望孩子们返回的地方):

$children = Auth::user()->children()->with('children', 'children.children')->get();

这提供了 3 个级别,并且可以通过添加“children.children.children”轻松扩展(尽管不仅仅是添加到数据库中)。

我还可以通过以下方式检查它是否是员工(层次结构的最低级别):

if(empty($children->toArray()) 

【讨论】:

你能再解释一下吗?在哪里使用这个? if(empty($children->toArray()) 由于特定的用例,第一层和第二层(分别是祖父母和父母)保证有孩子,所以我可以确定用户是否是第三层(孙子,员工在例如)通过验证它没有自己的孩子。它可以用于控制器或其他地方来验证用户的角色。但是,它实际上只在这种确切类型的用例中有用。如果任何祖父母或父母记录可能没有孩子,那么这个检查是没有用的。【参考方案2】:

请尝试以下方法 - 仅供儿童使用 - 未经测试!

将此添加到您的 User 模型类

public function scopeBelongingTo($query, $parentId)

    return $query->whereHas('parent', function($query) use ($parentId)
    
        $query->where('id', $parentId);
        $query->orWhereHas('parent', function($query) use ($parentId)
        
           $query->where('id', $parentId);
            $query->orWhereHas('parent', function($query) use ($parentId)
            
               $query->where('id', $parentId);
                $query->orWhereHas('parent', function($query) use ($parentId)
                
                   $query->where('id', $parentId);
                    $query->orWhereHas('parent', function($query) use ($parentId)
                    
                       $query->where('id', $parentId);
                    );
                );
            );
        );
    );

要查找孩子(以及孙辈、孙辈等),请尝试以下操作:

$idOfParent = 1; // Replace this with the ID of a parent you wish to query their children sub children
$users = User::belongingTo($idOfParent)->get();
dd($users->toArray()); // Should output the parent's childrens in the entire hierarchy down to tier 5...

如果这不起作用返回错误,我们会从那里看到。

重要 - 此特定示例仅适用于 5 个级别。要提高级别,我们必须包含 whereHas。在关系中可能有一种方法可以做到这一点,但只要您的应用程序很好地分离,就应该很容易将其换掉。

【讨论】:

没有错误,只是一个空数组。我有用户记录:id parent_id 1 null 2 1 3 1 4 2 5 2 6 3 7 3 (抱歉都是内联的,cmets不会保存换行符?)没有错误,只是一个空数组。我有一个 parent_id 为 null 的所有者,两个 parent_id=1 的主管(所有者)和四个员工,一对指向每个主管。无论我尝试使用哪个 id,我都会得到一个空的结果集。我还尝试对其进行修改以仅返回一个子级并且仍然得到一个空的结果数组。 我想这应该可行。当我有时间时,我会设置一个虚拟机并自己测试它,但这听起来是一个很好的临时解决方案。我确实理解让这个更清洁的愿望 - 如果它可以用于这个,它真的会更适合雄辩的关系,并且从逻辑上我可以看到它应该工作。【参考方案3】:

通过将方法添加到自身,选择的答案会更好 -->with('children') 这样每个子结果都会有它的子结果(使其递归)。无需使用点符号,这在某些情况下可能是不可能的。

public function children() 
   return $this->hasMany('User', 'parent_id')->with('children');

您的 AuthController 将是:

$children = Auth::user()->children()->get();

【讨论】:

以上是关于Laravel 多级分层用户系统的主要内容,如果未能解决你的问题,请参考以下文章

获取多级相关记录 laravel

Laravel Eloquent 中的多级深度 hasMany 关系

laravel 多级关联

使用 Laravel 模型保存多级数组

Laravel 多级关系

Laravel 多级菜单不起作用