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

时间:2016-04-03 01:46:15

标签: php laravel

我有一个模型Foo,它对应一个包含以下列的表。

ID
说明
USER_ID

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

$foo = new Foo;

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

//...

将$ foo发送到另一个类进行额外处理,但由于该类需要更多信息,我只想将其添加到$ foo模型中。

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

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

$foo->save();  //error

问题出在我$foo->save()时,它抱怨bar不是一列。

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

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

4 个答案:

答案 0 :(得分:2)

我知道为时已晚,但您可以通过覆盖模型中的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));
        }
    });
}

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

优点:您可以批量指定您想要的任何属性而不会对fillableguarded造成伤害。

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

答案 1 :(得分:1)

只需将$bar添加为foo类中的属性即可:

class Foo extends Model
{

  public $bar;
  //...

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


说明:

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

但是,如果尚未为Foo声明这样的属性,则会调用__set()是因为您try to save something in an inaccessible property

您可以签出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);
    }

基本上可以调用

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

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

现在$foo->bar ="xyz"会在$foo->attribute['bar']中变成蜜蜂,这就是save()..this column does not exists..崩溃的原因。

答案 2 :(得分:0)

添加$ 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'.

答案 3 :(得分:0)

我知道这个问题很旧,但是它是最近一次搜索的最高结果,其中我试图解决一个类似的问题,我认为这可能是Laravel访问器/更改器的理想案例。我已经在Laravel 5.6上进行了测试,但相信它可以早在4.2上运行。

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

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;
    }
}

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