与主数据的多态关系

Polymorphic relationship with pivot data

我想解决以下问题:

我有多个模型,例如:

每个模型应该能够有一个或多个 Fields 数据透视表。

Field:

示例:

Product 有一个名为 video_url 的字段,type 应该是 string 包含 pivothttp://youtube.com/....

Customer 有一个名为 external_id 的字段,type 应该是 integer 包含 pivot242.

字段应由用户动态添加。用户应该能够决定该字段是否变形为 ProductCustomer(或更晚)。

也许这有助于理解:

我现在在做什么

目前我为每个创建了一个新模型,productcustomer

对于客户:

class CustomerField extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\belongsToMany
     */
    public function customers()
    {
        return $this->belongsToMany(Customer::class)->withPivot('value');
    }
}

对于产品:

class ProductField extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\belongsToMany
     */
    public function products()
    {
        return $this->belongsToMany(Product::class)->withPivot('value');
    }
}

目前这个问题解决了,但当然,这不是解决它的最优雅的方法。

我的问题

是否有可能将字段动态变形为 ProductCustomer 并附加 pivot

最佳做法是使用单独的 table 来保存元信息,以便您可以根据需要轻松 add/remove "columns"

例如,您可以这样设置元数据 table:

create table `ProductField` (
    products_id int(11),
    column_name varchar(255),
    value varchar(255),
)

然后在您的产品模型中,添加获取、插入、检查是否存在等功能

public function getMeta($column) {
    $meta =  DB::table('ProductField ')
        ->select('column_name', 'value')
        ->where('products_id', '=', $this->id)
        ->where('column_name', '=', $column)
        ->get();

    if (!$meta->isEmpty()) {
        return $meta;
    } else {
        return null;
    }
}

public function addMeta($column, $value) {
    DB::table('ProductField ')->insert(
       [
        'products_id' => $this->id,
        'column_name' => $column, 
        'value' => $value,
       ]
    );
}

同样,您也可以为客户实现动态特性。

你也可以使用数组存储字段,然后动态添加到模型中

foreach ($request->input('cost') as $key=>$cost) {

    Price::create([
        'product_id' => $request->product_id[$key],
        'date' => Carbon::now(),
        'cost' => $cost,
        'trend' => 0
    ]);
}

如果您提前知道只会有某些动态字段,您可以选择为它们创建accessor methods

我想这就是你想要的Polymorphic:Many-to-Many

您不需要添加 ProductFieldCustomerField 模型,

您只需添加 ProductCustomerField 模型。

这些字段将 动态属于产品或客户 fieldable_type。即使您有更多模型,它也会将模型名称存储到此 fieldable_type.

你需要像下面这样创建 tables:

fieldables table 有 fieldable_idfieldable_type;

fieldable_type 会自动设置您的型号名称,例如 App\Product,您可以在 AppServiceProvider:

中自行自定义
Relation::morphMap([
    'products' => 'App\Product',
    'customers' => 'App\Customer',
]);

在产品型号中:

class Product extends Model
{
    /**
     * Get all of the fields for the product.
     */
    public function fields()
    {
        return $this->morphToMany('App\Field', 'fieldable')->withPivot('value');
    }
}

在客户模型中:

class Customer extends Model
{
    /**
     * Get all of the fields for the customer.
     */
    public function fields()
    {
        return $this->morphToMany('App\Field', 'fieldable')->withPivot('value');
    }
}

现场模型:

class Field extends Model
{
    /**
     * Get all of the products that are assigned this field.
     */
    public function products()
    {
        return $this->morphedByMany('App\Product', 'fieldable');
    }

    /**
     * Get all of the customers that are assigned this field.
     */
    public function customers()
    {
        return $this->morphedByMany('App\Customer', 'fieldable');
    }
}

具有枢轴值的 CRUD:

之后,您可以轻松地创建、获取、更新、删除数据透视值,例如:

Field::first()->products; # return the products with pivot value
Field::first()->customers; # return the customers with pivot value
Customer::first()->fields;

$field = Field::first();
# create new relationship with pivot value between customer and fields:
Customer::first()->fields()->attach($field, ['value' => 'customer new value field']);
# update pivot with value:
Customer::first()->fields()->sync([$field->id => ['value' => 'update customer value field']]);
# Delete pivot
Customer::first()->fields()->detach($field->id);