首页 > 解决方案 > Laravel 类策略设计模式 -> 多态关系

问题描述

在 Laravel 中实现这一目标的最佳方法是什么?我特别提到 Laravel 是因为我对 Laravel 还是很陌生。我正在尝试在其中实现它,并且我确信 Laravel 有一个我不熟悉的方面可以优雅地解决这个问题。

让我用一个简单的例子来澄清:

原始设计

假设你有一个汽车模型:

class Car extends Model
{
    protected $fillable = [
        'manufacturer',
        'model',
        'engine', //json field emulating a table
    ]
}

非规范化的“引擎”字符串字段包含 json。json 将始终具有“类型”属性,但从那里它会向各个方向发展。示例(使用我对汽车发动机的不完整知识):

用例

Car 模型将有一个 Vue 页面,其中包含各种引擎类型的下拉列表。在选择时,将显示特定于引擎类型的组件及其各自的属性。

我的解决方案

  1. 保持原样

我使用引擎JsonResource来模拟控制器和页面之间通信的模型。

  1. 具有动态添加属性的单个引擎模型,然后将其注入Car模型中。我只是推测了这一点。构造函数中添加的属性不会反映。但它的要点是:
class Engine extends Model
{
    public function __construct(array $attributes=[])
    {
        parent::__construct($attributes);

        foreach ($this->attributes()->get() as $attr) {
            $name = $attr->name;

            $this->append($name)->$name = $attr->value;
            $this->fillable[] = $name;
        }
    }

    public function attributes() {
        return $this->hasMany(EngineAttribute::class);
    }
}

class EngineAttribute extends Model
{
    protected $fillable = [
        'name',
        'value',
    ];
}

木头和树木

迄今为止,第一个解决方案效果最好,但违反了 1NF 并且无法正确扩展。第二种解决方案在应用程序中进一步引入了可怕的复杂性,我宁愿避免它。

建议、替代解决方案、对我的问题的建议修改或一般照明将不胜感激。

(编辑:修复 JSON 示例)

更新

dung ta van:再次感谢您的回答,伙计。但我看到了你的 Laravel 风格,我用更 Laravel 风格的东西来养育你。这是一段艰辛的旅程。充满了奇怪的特征和可怕的枢轴扩展连接模型,这些模型由可怕的连接表生成,通过它们的真实类名捕获许多模型的灵魂。但幸运的是,我带着一丝理智安全返回,并为我们带来了这个奖品: 多态关系 我将我发现的这个奇怪的魔法应用于你已经很好的代码,瞧!它开始转变为:

<?php

class EngineType extends Model {
    public function attributes() 
    {
        return $this->morphMany(
            EngineAttribute::class,
            'attributable'
        );
    }
}

class EngineAttribute extends Model {
    public function attributable()
    {
        return $this->morphTo();
    }
}

class Car extends Model {

    public function engineType() {
        return $this->hasOne(EngineType::class);
    }
}

我在上面提到的奥特威尔的大部头包含了其余的咒语,但这种未经检验的炼金术将提供这个想法。

标签: design-patternsdatabase-designlaravel-8

解决方案


在我看来,选项 2nd 更好,它更清晰和可扩展,但我们可以改进一点,我们可以删除Engine

php风格

class EngineType {
    public $id;
    public $typeName;
}

class EngineAttribute {
    public $cardId;
    public $engineTypeId;
    public $name;
    public $value;
}

class Car {
    public $id;
    public $manufacturer;
    public $model;
    public $engineTypeId;
}

在 laravel 风格中:

class EngineType extends Model {
}

class EngineAttribute extends Model {
}

class Car extends Model {

    public function engineType() {
        return $this->hasOne(EngineType::class);
    }

    public function attributes() {
        return $this->hasManyThrough(EngineAttribute::class, EngineType::class, 'card_id', 'engine_type_id', 'id', 'id');
    }

    public function toJson() {
        return json_encode($this);
    }
}

推荐阅读