简体   繁体   English

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

[英]Laravel Converting Existing User System Multi-Type

I recently took over a project that has an existing user system in place (standard Laravel 5.7 make:auth setup).我最近接手了一个已有用户系统的项目(标准 Laravel 5.7 make:auth 设置)。 What I've come to identify is that there is a significant amount of MySQL database columns within the user table that are blank or NULL as a result of the varied user types within the system.我发现用户表中有大量 MySQL 数据库列由于系统中的用户类型不同而为空或 NULL。 For the purpose of this example, let's say they are ADMINISTRATOR, PARENTS, CHILDREN.出于本示例的目的,假设他们是管理员、父母、儿童。 Within the app currently though, there are no clear distinctions as to what a user is other than a column called "type" which is either NULL for children, 'admin' for ADMINISTRATOR, and 'parent' for PARENTS.但是,在当前的应用程序中,除了名为“type”的列之外,没有明确的区分用户是什么,该列对于孩子是 NULL,对于 ADMINISTRATOR 是 'admin',对于 PARENTS 是 'parent'。

I want to be able to seperate all these columns out to be associated with the appropriate user type while maintining the same authentication method (that is my current thought process, not set in stone).我希望能够将所有这些列分开以与适当的用户类型相关联,同时维护相同的身份验证方法(这是我当前的思考过程,并非一成不变)。

From what I've gathered, I should be looking at a polymorphic relationship in which the User model has a "typeable" morph relationship to each of the user types.从我收集到的信息来看,我应该查看一个多态关系,其中 User 模型与每个用户类型都具有“可键入”的变形关系。 I've also read that that entails having a "typeable_type" and "typeable_id" column on the user model where "type" refers to the model - in this case "App\\Models\\Admin", "App\\Models\\Parent", "App\\Model\\Child".我还读到,这需要在用户模型上有一个“typeable_type”和“typeable_id”列,其中“type”是指模型——在这种情况下是“App\\Models\\Admin”、“App\\Models\\Parent”, “应用\\模型\\孩子”。

For each of these I would do something like this:对于这些,我会做这样的事情:

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');
    }
}

My question is - how can I create relationships within the "type" classes that can use the parent User ID as the foreign key / basis of any relationship?我的问题是 - 如何在可以使用父用户 ID 作为任何关系的外键/基础的“类型”类中创建关系?

For instance, a Parent might have a subscription in the database that perhaps a Admin doesn't.例如,父级可能在数据库中有一个订阅,而管理员可能没有。 The subscription table references the current user via a "user_id" column.订阅表通过“user_id”列引用当前用户。

Traditionally, the User would just reference the subscription through a normal relationship.传统上,用户只会通过正常关系引用订阅。

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);
    }
}

How would I retrieve that in an architecture where that relationship is owned by the "Parent" class.我将如何在“父”类拥有该关系的体系结构中检索它。 Take in mind, I'm working within a legacy app that I inherited, so everything currently revolves around the user & user_id.请记住,我在继承的遗留应用程序中工作,因此当前所有内容都围绕用户和 user_id。

Long story short, I want to be able to pull different types of info depending on user type but still treat each of the user types as a "User" in the traditional sense.长话短说,我希望能够根据用户类型提取不同类型的信息,但仍将每种用户类型视为传统意义上的“用户”。 An ideal system would be where the information that each user type possesses is "flattened" into the standard user for use.一个理想的系统是每个用户类型拥有的信息被“扁平化”到标准用户中以供使用。

I don't think using a relationship is what you're really after here.我不认为使用关系是你真正想要的。

The way I would set it up is the create a User class (that extends Model ) and then have three models extend the User class ( Parent , Child and Admin ).我设置它的方法是创建一个User类(扩展Model ),然后让三个模型扩展User类( ParentChildAdmin )。

In the User base class you would add all code that applies to all users.User基类中,您将添加适用于所有用户的所有代码。

I would then add a global scope to each of the Parent , Child and Admin classes (for the example, I've used an anonymous global scope, but you can use a normal scope if you wish):然后,我将为ParentChildAdmin类中的每一个添加一个全局范围(例如,我使用了匿名全局范围,但如果您愿意,您可以使用普通范围):

class Admin extends Users
{
    protected static function boot()
    {
        parent::boot();

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

You would then add any relevant methods into each of the three classes, for example, your subscription relationship would look like this:然后,您可以将任何相关方法添加到三个类中的每一个中,例如,您的订阅关系如下所示:

class Admin extends User
{
    public function subscription()
    {
        return $this->hasOne(Subscription::class);
    }
}

class Subscription extends Model
{
    public function admins()
    {
        return $this->hasMany(Admin::class);
    }
}

You then might also need to set the table in each of the three classes by using protected $table = 'users' - but I'm not certain on this.然后,您可能还需要使用protected $table = 'users'在三个类中的每一个中设置表 - 但我不确定这一点。

If you were then provided just a user class and wanted to convert that user into one of the specific base classes, you could add a function like this to the class:如果您当时只提供了一个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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM