Laravel 将现有用户系统转换为多类型
Laravel Converting Existing User System Multi-Type
我最近接手了一个现有用户系统(标准 Laravel 5.7 make:auth 设置)的项目。我已经确定的是,由于系统中的用户类型不同,用户 table 中有大量 MySQL 数据库列为空白或 NULL。出于本示例的目的,假设他们是 ADMINISTRATOR、PARENTS 和 CHILDREN。目前,在该应用程序中,除了名为 "type" 的列之外,没有明确区分用户是什么,该列对于儿童为 NULL,对于 ADMINISTRATOR 为 'admin',对于 PARENTS 为 'parent' .
我希望能够将所有这些列分开,以便与适当的用户类型相关联,同时保持相同的身份验证方法(这是我当前的思考过程,并非一成不变)。
根据我收集到的信息,我应该查看多态关系,其中用户模型与每个用户类型具有 "typeable" 变形关系。我还读到这需要在用户模型上有一个 "typeable_type" 和 "typeable_id" 列,其中 "type" 指的是模型 - 在这种情况下 "App\Models\Admin", "App\Models\Parent", "App\Model\Child".
对于其中的每一个,我都会做这样的事情:
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');
}
}
我的问题是 - 如何在 "type" classes 中创建可以使用父用户 ID 作为任何关系的外键/基础的关系?
例如,家长可能在数据库中有订阅,而管理员可能没有。订阅 table 通过 "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);
}
}
我如何在该关系由 "Parent" class 拥有的体系结构中检索它。请记住,我在我继承的遗留应用程序中工作,所以目前一切都围绕着用户 & user_id.
长话短说,我希望能够根据用户类型提取不同类型的信息,但仍将每种用户类型视为传统意义上的 "User"。一个理想的系统应该是每个用户类型拥有的信息"flattened"进入标准用户使用。
我不认为使用关系是你真正想要的。
我的设置方式是创建一个 User
class(扩展 Model
),然后让三个模型扩展 User
class(Parent
、Child
和 Admin
)。
在 User
基础 class 中,您将添加适用于所有用户的所有代码。
然后我会在每个 Parent
、Child
和 Admin
class 中添加一个 global scope(例如,我已经使用匿名全局作用域,但如果您愿意,也可以使用普通作用域):
class Admin extends Users
{
protected static function boot()
{
parent::boot();
static::addGlobalScope('user_type', function (Builder $builder) {
$builder->where('type', '=', 'admin');
});
}
}
然后您可以将任何相关方法添加到三个 class 中的每一个中,例如,您的订阅关系如下所示:
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'
在三个 class 中的每一个中设置 table - 但我不确定这一点。
如果您当时只获得了 user
class 并且想要将该用户转换为特定基础 class 之一,您可以将这样的功能添加到class:
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 5.7 make:auth 设置)的项目。我已经确定的是,由于系统中的用户类型不同,用户 table 中有大量 MySQL 数据库列为空白或 NULL。出于本示例的目的,假设他们是 ADMINISTRATOR、PARENTS 和 CHILDREN。目前,在该应用程序中,除了名为 "type" 的列之外,没有明确区分用户是什么,该列对于儿童为 NULL,对于 ADMINISTRATOR 为 'admin',对于 PARENTS 为 'parent' .
我希望能够将所有这些列分开,以便与适当的用户类型相关联,同时保持相同的身份验证方法(这是我当前的思考过程,并非一成不变)。
根据我收集到的信息,我应该查看多态关系,其中用户模型与每个用户类型具有 "typeable" 变形关系。我还读到这需要在用户模型上有一个 "typeable_type" 和 "typeable_id" 列,其中 "type" 指的是模型 - 在这种情况下 "App\Models\Admin", "App\Models\Parent", "App\Model\Child".
对于其中的每一个,我都会做这样的事情:
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');
}
}
我的问题是 - 如何在 "type" classes 中创建可以使用父用户 ID 作为任何关系的外键/基础的关系?
例如,家长可能在数据库中有订阅,而管理员可能没有。订阅 table 通过 "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);
}
}
我如何在该关系由 "Parent" class 拥有的体系结构中检索它。请记住,我在我继承的遗留应用程序中工作,所以目前一切都围绕着用户 & user_id.
长话短说,我希望能够根据用户类型提取不同类型的信息,但仍将每种用户类型视为传统意义上的 "User"。一个理想的系统应该是每个用户类型拥有的信息"flattened"进入标准用户使用。
我不认为使用关系是你真正想要的。
我的设置方式是创建一个 User
class(扩展 Model
),然后让三个模型扩展 User
class(Parent
、Child
和 Admin
)。
在 User
基础 class 中,您将添加适用于所有用户的所有代码。
然后我会在每个 Parent
、Child
和 Admin
class 中添加一个 global scope(例如,我已经使用匿名全局作用域,但如果您愿意,也可以使用普通作用域):
class Admin extends Users
{
protected static function boot()
{
parent::boot();
static::addGlobalScope('user_type', function (Builder $builder) {
$builder->where('type', '=', 'admin');
});
}
}
然后您可以将任何相关方法添加到三个 class 中的每一个中,例如,您的订阅关系如下所示:
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'
在三个 class 中的每一个中设置 table - 但我不确定这一点。
如果您当时只获得了 user
class 并且想要将该用户转换为特定基础 class 之一,您可以将这样的功能添加到class:
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;
}
}