如果 Laravel Eloquent 在插入期间不在表中,则忽略属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36380752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 13:31:29  来源:igfitidea点击:

Laravel Eloquent ignore attribute if not in table during insert

phplaravel

提问by dangel

I have a model Foo that corresponds to a table with the following columns.

我有一个模型 Foo 对应于具有以下列的表。

id
description
user_id

id
描述
user_id

I'm setting the attributes of the Foo model individually (no mass assignment)

我正在单独设置 Foo 模型的属性(无质量分配)

$foo = new Foo;

$foo->id = 1;
$foo->description = "hello kitty";
$foo->user_id = 55;

//...

$foo is sent to another class for additional processing, but because that class needs a bit more information, I would like to simply add it to the $foo model.

$foo 被发送到另一个类进行额外处理,但因为该类需要更多信息,我想简单地将它添加到 $foo 模型中。

//...
$foo->bar = $additional_information;

Event::fire(DoStuffWithFoo($foo));

$foo->save();  //error

the problem is when I $foo->save(), it complains that barisn't a column.

问题是当 I 时$foo->save(),它抱怨这bar不是一列。

I know I can unset($foo->bar);before saving, but...

我知道unset($foo->bar);在保存之前我可以,但是...

Is it possible to tell Eloquent to simply ignore any non relevant attributes?

是否可以告诉 Eloquent 简单地忽略任何不相关的属性?

回答by Adam

Just add $baras an attribute in your foo class:

只需$bar在你的 foo 类中添加一个属性:

class Foo extends Model
{

  public $bar;
  //...

now you can use save()and Laravel will not try to store barin the DB.

现在您可以使用save()并且 Laravel 不会尝试存储bar在数据库中。



Explanation:

解释:

If you call save()on a model, only those attributes that are in the array $model->attributeswill be saved to the database. If you define $baras an attribute in the class Foo, then $foo->bar ="xyz"will never end up in the array $model->attributes.

如果您调用save()模型,则只有数组中的那些属性$model->attributes才会保存到数据库中。如果你$bar在类中定义为一个属性Foo,那么$foo->bar ="xyz"永远不会出现在数组中$model->attributes

However, if you do not have declared such an attribute for Foo, then __set()is called because you try to save something in an inaccessible property.

但是,如果您没有为 声明这样的属性Foo,则__set()调用它是因为您试图在无法访问的属性中保存某些内容

You may check out Laravel\Illuminate\Database\Eloquent\Model.php:

您可以查看Laravel\Illuminate\Database\Eloquent\Model.php

/**
     * Dynamically set attributes on the model.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return void
     */
    public function __set($key, $value)
    {
        $this->setAttribute($key, $value);
    }

which basically calls

这基本上叫

$this->attributes[$key] = $value;

from Laravel\Illuminate\Database\Eloquent\Concerns\HasAttributes.php.

Laravel\Illuminate\Database\Eloquent\Concerns\HasAttributes.php.

Now $foo->bar ="xyz"will end up beeing in $foo->attribute['bar']and this is why save()crashes with ..this column does not exists...

现在$foo->bar ="xyz"最终会进入$foo->attribute['bar'],这就是为什么会save()..this column does not exists...

回答by pwyg

I understand this question is old but it was in top results for a recent search where I was trying to solve a similar problem and I think that this may be an ideal case for Laravel accessors/mutators. I have tested this on Laravel 5.6 but believe it may work as far back as 4.2.

我知道这个问题很老,但它在最近的搜索结果中名列前茅,我试图解决类似的问题,我认为这可能是 Laravel 访问器/修改器的理想情况。我已经在 Laravel 5.6 上测试过这个,但相信它可以追溯到 4.2。

By creating a mutator and accessor rather than a public property it will allow adding the field to fillable for mass assignment while still excluding it from the internal attributes (thus preventing it from errantly saving to the DB). I understand the original request excluded mass-assignment but that doesn't necessarily exclude this answer. I think an example will help:

通过创建 mutator 和 accessor 而不是公共属性,它将允许将字段添加到可填充以进行批量分配,同时仍将其从内部属性中排除(从而防止它错误地保存到数据库中)。我了解原始请求排除了批量分配,但这并不一定排除此答案。我认为一个例子会有所帮助:

class Foo extends Model
{
    //Allow bar in mass assignment
    protected $fillable = [
            "bar"
        ];

    /**
     * Store bar in protected variable instead of attributes
     * Because bar is not set in attributes, Laravel will not try to save it to database
     */
    protected $bar;

    /**
     * Mutator method to set bar's value
     */
    public function setBarAttribute($value)
    {
        $this->bar = $value;
    }

    /**
     * Accessor method to retrieve bar's value
     */ 
    public function getBarAttribute()
    {
        return $this->bar;
    }
}

When this model is created using mass-assignment the mutator (setBarAttribute) method will be called for bar if it exists in the mass-assigned values. Anytime the bar property is accessed the respective get/set method will be called. Because the mutator does not set the value of bar in the model's internal attributes variable the model will not save bar to the database.

当使用质量分配创建此模型时,如果 bar 存在于质量分配值中,则将为 bar 调用 mutator (setBarAttribute) 方法。无论何时访问 bar 属性,都会调用相应的 get/set 方法。因为 mutator 没有在模型的内部属性变量中设置 bar 的值,所以模型不会将 bar 保存到数据库中。

回答by nrofis

I know it is too late, but you can register the savingoperation by override the bootfunction in your model:

我知道为时已晚,但您可以saving通过覆盖boot模型中的函数来注册操作:

protected static function boot() {
    parent::boot();

    static::saving(function($model) {
        $savable = [...];
        if (count($savable) > 0) {
            $model->attributes = array_intersect_key($model->attributes, array_flip($savable));
        }
    });
}

This is untested code, but the idea is to remove the attributes that have not intersect with the variable savablebefore saving the model. The variable savableis an array of the savable attributes. For example $savable = ['foo', 'bar']will save only the fooand barattributes.

这是未经测试的代码,但其想法是savable在保存模型之前删除与变量不相交的属性。该变量savable是一组可保存的属性。例如$savable = ['foo', 'bar']将只保存foobar属性。

Pros: You can mass assign any attributes that you want without harm to fillableor guarded.

优点:您可以批量分配您想要的任何属性,而不会对fillable或造成伤害guarded

Cons: The attributes that are not marked as savable, will be deleted from the model after saving.

缺点:未标记为 的属性savable将在保存后从模型中删除。

回答by Lance Pioch

Add the $fillable and the model will ignore everything not in it (instead of giving an error). Using the constructor function to fill all the columns is optional.

添加 $fillable ,模型将忽略不在其中的所有内容(而不是给出错误)。使用构造函数填充所有列是可选的。

class Foo extends Model
{
    protected $fillable = ['id', 'description', 'user_id'];
}

$f = new Foo(['id' => 1, 'description' => "hello monkey", 'user_id' => 55, 'bar' => 'wow']); // should work w/o error, but it ignores the 'bar'.