Laravel 转换现有用户系统多类型

Posted

技术标签:

【中文标题】Laravel 转换现有用户系统多类型【英文标题】:Laravel Converting Existing User System Multi-Type 【发布时间】:2019-12-20 05:43:54 【问题描述】:

我最近接手了一个拥有现有用户系统的项目(标准 Laravel 5.7 make:auth 设置)。我已经确定的是,由于系统中用户类型的不同,用户表中有大量的 mysql 数据库列是空白或 NULL。出于本示例的目的,假设他们是管理员、父母、儿童。但在当前的应用程序中,除了一个名为“type”的列之外,没有明确的区别用户是什么,对于孩子来说是 NULL,对于 ADMINISTRATOR 是 'admin',对于 PARENTS 是 'parent'。

我希望能够将所有这些列分开以与适当的用户类型相关联,同时保持相同的身份验证方法(这是我目前的思考过程,不是一成不变的)。

根据我收集到的信息,我应该研究一种多态关系,其中用户模型与每个用户类型都具有“可类型化”的变形关系。我还读到这需要在用户模型上有一个“typeable_type”和“typeable_id”列,其中“type”指的是模型——在这种情况下是“App\Models\Admin”、“App\Models\Parent”, “应用\模型\儿童”。

对于其中的每一个,我都会做这样的事情:

class User extends Model


    public function typeable()
    
        return $this->morphTo();
    


class Admin extends Model

    public function user()
    
        return $this->morphMany('App\User', 'typeable');
    


class Parent extends Model

    public function user()
    
        return $this->morphMany('App\User', 'typeable');
    


class Child extends Model

    public function user()
    
        return $this->morphMany('App\User', 'typeable');
    

我的问题是 - 我如何在“类型”类中创建可以使用父用户 ID 作为任何关系的外键/基础的关系?

例如,Parent 可能在数据库中有订阅,而 Admin 可能没有。订阅表通过“user_id”列引用当前用户。

传统上,用户只是通过正常关系引用订阅。

class User extends Model


    public function subscription()
    
        return $this->hasOne(App\Models\Subscription::class);
    


class User extends Model


    public function subscription()
    
        return $this->hasMany(App\Models\User::class);
    

如何在“父”类拥有该关系的架构中检索它。请记住,我正在使用我继承的旧版应用程序,因此目前所有内容都围绕用户和 user_id。

长话短说,我希望能够根据用户类型提取不同类型的信息,但仍将每种用户类型视为传统意义上的“用户”。一个理想的系统是每个用户类型拥有的信息被“扁平化”到标准用户中以供使用。

【问题讨论】:

【参考方案1】:

我认为使用关系并不是你真正想要的。

我设置它的方式是创建一个User 类(扩展Model),然后让三个模型扩展User 类(ParentChildAdmin)。

User 基类中,您将添加适用于所有用户的所有代码。

然后,我将在 ParentChildAdmin 类中添加一个 global scope(例如,我使用了匿名全局范围,但如果您可以使用普通范围希望):

class Admin extends Users

    protected static function boot()
    
        parent::boot();

        static::addGlobalScope('user_type', function (Builder $builder) 
            $builder->where('type', '=', 'admin');
        );
    

然后您可以将任何相关方法添加到三个类中的每一个中,例如,您的订阅关系如下所示:

class Admin extends User

    public function subscription()
    
        return $this->hasOne(Subscription::class);
    


class Subscription extends Model

    public function admins()
    
        return $this->hasMany(Admin::class);
    

然后您可能还需要使用 protected $table = 'users' 在三个类中的每一个中设置表 - 但我不确定这一点。

如果当时只为您提供了一个 user 类,并希望将该用户转换为特定的基类之一,您可以向该类添加这样的函数:

class User extends Model

    public function getUserType() // Or whatever you would like the name to be
    
        // NOTE: I've made this function load without having to do any database calls
        // but if you don't mind an additional call, it might be easier to just change
        // the switch to return Admin::find($this->id);

        $class = null;
        switch($this->type) 
            case "admin":
                $class = new Admin($this->attributesToArray());
                break;
            case "parent":
                $class = new Parent($this->attributesToArray());
                break;
            case "child":
                $class = new Child($this->attributesToArray());
                break;
        

        if(is_null($class)) 
            // Throw error, return null, whatever you like
            return $class;
        

        // Perform any additional initialisation here, like loading relationships
        // if required or adding anything that isn't an attribute

        return $class;
    

【讨论】:

感谢您在回复中花费的时间,这听起来是我应该考虑的合法途径,老实说,可以相对快速且零碎地迁移。形象地说,我只是想将用户扩展到不同的类型,这是一个切实的实现。理想情况下,我想听听是否有围绕这个概念的任何其他范例——特定于 Laravel——但总的来说,这是一个可靠的解决方案。有了这个,您是否只需拥有特定于用户类型的表,这些表只是通过 user_id 作为标准用户引用它们?一个admin_meta表,parent_meta表…… 如果您想了解每种数据存储方式的优缺点,请阅读本文***.com/questions/3579079/… @radiantstatic 我不相信有任何 Laravel 特定的范例,唯一特别是 Laravel 的是Gates and Policies。我个人会避开元表,因为它们可能会导致数据重复。如果你想要 Laravel 特定的东西,我会研究政策。通常(如果不是 Laravel)我建议实现一个 role 表(idname),一个 permissions 表(idpermission)和一个 role_permissions 表(@ 987654346@, permission_id) 并使用角色检查权限是否存在。 @NickClark - 所以(暂时)我真的不太关心它的权限方面 - 尽管我理解它的重要性。举个例子,假设大多数人都可以做任何事情,但不改变不适用于他们的数据。在 Wouter Van Damme 的回应中——我认为“类表继承”是最适用的场景。显然它的语义称为元 - 但你仍然不同意这种模式吗? @radiantstatic 这个问题并没有真正的错误解决方案,它只取决于您将来(或当前)是否要拥有可自定义的权限以及您希望权限存在的位置(在数据库或应用程序代码中)。正如我之前提到的,我看到使用元表的唯一真正问题是数据库中数据重复的可能性——但这将是一件非常小的事情,所以如果你觉得元表最舒服,那就使用它们

以上是关于Laravel 转换现有用户系统多类型的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 和 WordPress 前端

Laravel sanctum 获得合适的用户

我想自学laraver,请诸位前辈给一些建议,谢谢

larave学习笔记1-安装配置

laraver框架学习------工厂模型填充测试数据

Laravel Sanctum - 登录用户最佳实践