Laravel Eloquent 多态模型

4
我遇到了这样一种情况:我需要将一个Eloquent模型动态地转化为一个特定的类,该类扩展了我的“普通”Eloquent模型。以下是一个基于典型电子产品松散的通用布局:
数据对象:
['id', 'model_type', 'name', 'serial',...]
  • 模型
    • 模型类型A
    • 模型类型B

如果数据都在一个表(MySQL)中,Laravel实际上没有直接将该数据作为多态性提取的方法。您可以使用多态性关系,但不能直接使用模型进行多态性处理。

基本上,这样做是为了分离可能涉及一种类型而不涉及另一种类型的逻辑。例如,模型类型A模型类型B都可以实现描述其能力的接口,但A的特定逻辑不需要污染B。

2个回答

6

我的解决方案是在模型上覆盖newFromBuilder方法(Laravel 5.6)。如下:

App\Schemes\BaseScheme

abstract class BaseScheme extends Electronic
{
    // abstract methods to implement
    // ...
}

App\Schemes\ElectronicTypeA

class ElectronicTypeA extends BaseScheme
{
    // Electronic Type A logic
}

App\Schemes\ElectronicTypeB

class ElectronicTypeB extends BaseScheme
{
    // Electronic Type B logic
} 

应用程序\Models\电子

use Illuminate\Database\Eloquent\Model;

class Electornic extends Model
{
    public function newFromBuilder($attributes = [], $connection = null)
    {
        if (!class_exists($attributes->model_type)) {
            throw new \Exception("Invalid Scheme ({$attributes->model_type})"); 
        }

        $class = $attributes->model_type;
        $model = new $class;

        if (!$model instanceof \App\Schemes\BaseScheme) {
            throw new \Exception("Scheme class is invalid ({$attributes->model_type})");
        }

        $model->exists = true;

        $model->setRawAttributes((array) $attributes, true);

        $model->setConnection($connection ?: $this->getConnectionName());

        $model->fireModelEvent('retrieved', false);

        return $model;
    }

\App\Schemes\BaseScheme 是所有逻辑模型都继承的抽象类。同时,\App\Schemes\BaseScheme 也是原始 Eloquent 模型的扩展。

最棒的部分在于它可以作用于返回的数据集合上。这意味着你可以像普通模型一样与该模型进行交互,但实际上你正在与特定的类(typeA、typeB)进行交互。


1

有一个解决方案。

您可以使用这个库: Parental

composer require "calebporzio/parental=0.9"

使用 Trait 扩展子模型,然后可以创建 Laravel Scope 来查询子模型。以下是示例:
//parent model
class RoleUser extends Model{
}

并且对于儿童模型:
class Expert extends RoleUser
 {
 use \Parental\HasParent;
 public static function boot()
 {
     parent::boot();
     static::addGlobalScope("role", function ($query) {
         $query->where("role_type", "App\Expert");
     });
 }
}

1
不错!是的,看起来像是一个已经构建好的包,遵循了 https://dev59.com/fKvka4cB1Zd3GeqPmgWX#50107149 中提到的类似方法。 - zerodahero
是的。这个包处理表名解析,以及子模型中的关系,并使用Trait使代码整洁。 - Abilogos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接