In my MySQL table, I have some columns with default values. If I create new model (with Model::create($attributes), the unfilled attributes are retrieved from database (in the model that create method returns).
I have a observer for the model, and when I call Model::create($attributes), the fields with default in database and not provided, are not in the instance passed to the observer's created method.
I have a observer with this code:
class MasterObserver
{
public function created(Master $master)
{
Log::info('Observer. ' . $master->toJson());
$master->refresh();
Log::info('Observer. ' . $master->toJson());
dispatch(new SyncSlavesJob($master));
}
}
I gets this lines printed in the logs:
[2018-02-16 13:52:24] dev.INFO: Observer. {"protocol":"https","host":"example.com","key_password":"secret","is_blocked":false,"id":2}
[2018-02-16 13:52:24] dev.INFO: Observer. {"id":2,"name":"example.com","host":"example.com","protocol":"https","port":4085,"key_password":"secret","is_blocked":false}
In the not refreshed instance, the attributes not provided aren't filled, but ID is filled, that means the ID was received from database on creation.
It is the normal behavior or is a bug?
Hi @montyclt i suppose its normal behavior.
Anytime 'create' is used, the returned model only contains the attributes provided. This avoids another call to the database. If you need any default values that are set by the db, then you'll need to refresh before using.
As you can see in the below code, the new model is instantiated with the attributes provided and that is what is returned after it is saved.
public function create(array $attributes = [])
{
return tap($this->newModelInstance($attributes), function ($instance) {
$instance->save();
});
}
You can define your default attributes directly on the model, mirroring your database defaults:
protected $attributes = [
'language' => 'en',
'timezone' => 'Solar/Mars',
…
];
Two effects of this:
See also this example tinker session:
>>> DB::listen(function ($q) { var_dump($q->sql); });
=> null
>>> $u = \App\Models\User::create(['email' => 'daz']);
string(84) "insert into "users" ("email", "modified", "created") values (?, ?, ?) returning "id""
=> App\Models\User {#1440
email: "daz",
}
Now add default attributes in a new tinker session:
>>> $u = \App\Models\User::create(['email' => 'baz']);
string(237) "insert into "users" ("out_of_office", "language", "email", "modified", "created") values (?, ?, ?, ?, ?) returning "id""
=> App\Models\User {#1451
language: "en",
out_of_office: false,
email: "baz",
}
>>>
@mfn @devcircus Thanks you for explanations. New thing learned today ;)