Attribute cast is ignored when setting attribute to NULL
https://github.com/laravel/framework/blob/5.5/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php#L1059
class Text extends Model
{
protected $table = 'text';
protected $guarded = [];
protected $casts = [
'notes' => 'string',
];
}
$text = new Text();
$text->fill(['notes'=>null]); // Null should be casted to '' which is equal to default ''
$text->isDirty('notes');//true, should be false instead
This is intended, null is returned as is, there's a difference between "" and null.
@themsaid Can we have a bit more of an explanation about this? What's the point of casting if casting isn't allowed because there's "difference". Isn't that the point of casting...?
In tinker:
>>> $x = (string) null;
=> ""
The documentation presents the casting feature as a convenient way to cast attributes so one doesn't have to cast the attributes all over the place.
This intended behavior does not conform to the casting that PHP allows. Perhaps there's a good reason for that, perhaps not. But, I think it would be nice to go a bit deeper into what differences there are and why they are significant.
We can cast strings to (certain kinds of) objects. These are also quite different. So, why can't we cast null to a string and get an empty string (like we would expect if casting directly)...?
Thanks in advance for your input. :-)
Related: According to the PHP docs (http://php.net/manual/en/language.types.string.php#language.types.string.casting), "NULL is always converted to an empty string."
@themsaid FYI...I also just noticed the OP's issue was assigning null.
That's not my issue.
Rather, it's reading the attribute. If the value of an attribute is null, but it's cast to string, then shouldn't one expect an empty string...?
null is treated as "not a value" and therefore a cast does apply.
If you need such behaviour, you can implement your own getter. The cast behaviour cannot be changed (it will break every other users code out there).
@mfn Hi, and thanks for the reply.
Yes, I understand the concept of null and I understand that Laravel's casting behavior doesn't cast a value if it's null. I also understand that one can write accessors to cast attributes that have null values...which is what I've had to do.
I was writing to understand why the decision was made to do this. I felt that the explanation given earlier was not sufficient, especially since the whole point of casting is to force a value to be a specific type, which often means changing from one type to a different type....and casting null to various types is often handled without issue and yields non-null values.
The Laravel documentation presents this functionality as a kind of convenience. It likens it to how one would normally cast using "pure" PHP. This is not the case, however, and the documentation doesn't make this clear. It caught me by surprise because this was not the expected behavior, which is what led me to this issue....looking for an explanation as to why it was written this way in the first place.
Not particularly relevant, but since you brought it up...making changes that are not backward compatible is not the end of the world. PHP has and will continue to do it. Laravel has and will continue to do it. It's normal. (Please note, I'm not suggesting that any changes be made...except for the documentation. I wouldn't be opposed to it, but without having a better understanding of the rationale behind the decision to implement it this way, I am wont to argue for it.)
So...perhaps you know why it was written this way...? Perhaps you would agree that the documentation could make it clear that any attribute, regardless of type or cast, will return null if its underlying value is null...?
Again, thanks for your input....I hope you can better understand what I'm looking for now. :-)
Most helpful comment
@mfn Hi, and thanks for the reply.
Yes, I understand the concept of
nulland I understand that Laravel's casting behavior doesn't cast a value if it'snull. I also understand that one can write accessors to cast attributes that havenullvalues...which is what I've had to do.I was writing to understand why the decision was made to do this. I felt that the explanation given earlier was not sufficient, especially since the whole point of casting is to force a value to be a specific type, which often means changing from one type to a different type....and casting
nullto various types is often handled without issue and yields non-nullvalues.The Laravel documentation presents this functionality as a kind of convenience. It likens it to how one would normally cast using "pure" PHP. This is not the case, however, and the documentation doesn't make this clear. It caught me by surprise because this was not the expected behavior, which is what led me to this issue....looking for an explanation as to why it was written this way in the first place.
Not particularly relevant, but since you brought it up...making changes that are not backward compatible is not the end of the world. PHP has and will continue to do it. Laravel has and will continue to do it. It's normal. (Please note, I'm not suggesting that any changes be made...except for the documentation. I wouldn't be opposed to it, but without having a better understanding of the rationale behind the decision to implement it this way, I am wont to argue for it.)
So...perhaps you know why it was written this way...? Perhaps you would agree that the documentation could make it clear that any attribute, regardless of type or cast, will return
nullif its underlying value isnull...?Again, thanks for your input....I hope you can better understand what I'm looking for now. :-)