I have a model Foo that corresponds to a table with the following columns.
id
description
user_id
I'm setting the attributes of the Foo model individually (no mass assignment)
$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->bar = $additional_information; Event::fire(DoStuffWithFoo($foo)); $foo->save(); //error
the problem is when I $foo->save()
, it complains that bar
isn't a column.
I know I can unset($foo->bar);
before saving, but...
Is it possible to tell Eloquent to simply ignore any non relevant attributes?
Just add $bar
as an attribute in your foo class:
class Foo extends Model { public $bar; //...
now you can use save()
and Laravel will not try to store bar
in the DB.
Explanation:
If you call save()
on a model, only those attributes that are in the array $model->attributes
will be saved to the database. If you define $bar
as an attribute in the class Foo
, then $foo->bar ="xyz"
will never end up in the array $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.
You may check out 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
.
Now $foo->bar ="xyz"
will end up beeing in $foo->attribute['bar']
and this is why save()
crashes with ..this column does not exists..
.
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.
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With