Laravel Eloquent Polymorphic模型

时间:2018-04-30 19:41:44

标签: php laravel eloquent polymorphism

我遇到了一个情况,我需要一个Eloquent模型来动态地融入一个特定的类,扩展我的“普通”雄辩模型。这是一个基于典型电子设备的通用布局:

数据对象:

['id', 'model_type', 'name', 'serial',...]
  • 模型
    • 型号A
    • 型号B

如果数据全部在一个表(MySQL)中,Laravel实际上没有办法直接将这些数据作为多态转换。您可以将关系变为多态,但不能直接模型化。

基本上,对此的推理是将可能与某种类型有关的逻辑分开,而不是另一种类型。例如,Model Type AModel Type B都可以实现描述其功能的接口,但A的特定逻辑不需要污染B。

2 个答案:

答案 0 :(得分:3)

我的解决方案是覆盖模型上的newFromBuilder方法(Laravel 5.6)。像这样:

应用\方案\ BaseScheme

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

应用\方案\ ElectronicTypeA

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

应用\方案\ ElectronicTypeB

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

应用\模型\电子

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 :(得分:0)

有解决方案。

您可以使用此库: Parental

composer require "calebporzio/parental=0.9"

并使用The 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");
     });
 }
}