[8.x] Fix getDirty
method when using class castables (e.g. As(Encrypted)ArrayObject
/As(Encrypted)Collection
)
#38774
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What is the issue?
In MySQL, a JSON column adds spaces between the JSON keys and the JSON values, even when you explicitly try to save it without spaces.
This causes an issue when using the
AsArrayObject
casting class on a JSON attribute. Currently, theoriginalIsEquivalent
method (used bygetDirty
method) does nothing special when an attribute uses a class castable. This means that it will do a strict string comparison between the original and the new value, which will result in afalse
because of the spaces in the original value. This causes a lot of unnecessary update queries because Eloquent thinks a model contains changes.How to fix it?
To fix this, we need to cast the original attribute using the class castable before comparing the two values. This casting is done in the
originalIsEquivalent
method itself. It does not use thecastAttribute
because that causes issues with theclassCastCache
(which caches only based key instead of key-value combination).I also updated the
get
methods of theAs(Encrypted)ArrayObject
andAs(Encrypted)Collection
casts. Theget
method currently uses the value in the$attributes
array, while it should use the provided$value
.