Replies: 1 comment
-
I dug a little deeper, as I tried to reproduce this with Laravel using another class cast. At first, I could not reproduce the issue. Then I realized the This seems to be the culprit - accessing the model value this way calls the magic getter, which calls the caster with the default value (not the DB value, because those have not been set from the DB, yet), and then caches the result in class cast. Then, when Basically, it can be said that accessing the model property has an undesirable side-effect here. I'm kind of torn wether this is a Laravel bug, or a bug in this package. In any case, it seems that modifying this line here as shown, fixes (works around) the issue: if (Arr::get($this->attributes, $field) !== null) |
Beta Was this translation helpful? Give feedback.
-
Let's say I have the following model, which defines a default attribute value for the 'state' property:
When I have a payment with ID 1 in my DB where state is
paid
, and I callPayment::find(1)->status
, it will returnPendingState::class
instead ofPaidState::class
.Interestingly:
state
fromprotected $attributes
, this issue does not occur.state
fromprotected $casts
(and keep the default in$attributes
), this issue does not occur.I would expect it to return
PaidState::class
.I did quiet a bit of digging, and it seems this happens because after the model is loaded and attributes from DB set on the model,
syncOriginal
is called and it will merge attributes from cached casts. This will call the class caster set method, but not with the raw value, but the default attribute value (which will be an instance ofPendingState
in our case).I'm not sure why it works this way, but it seems like a bug - although probably on Laravel side. I wanted to raise this concern regardless, as it threw me off quiet a bit.
A workaround for the issue is to not define the default state value in model attributes, but rather in the state class.
Beta Was this translation helpful? Give feedback.
All reactions