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.
Previously, the security fix introduced with #33777 broke support for mass assigning JSON columns when using
$guarded
instead of$fillable
on an Eloquent Model.The reason for this PR is that it is unpractical to put the name of the JSON column plus all possible keys and sub-keys and sub-sub-keys into the
$fillable
attribute, which would be required, because wildcards are not allowed. Thus, the only sane way to use such a structure is guarding the columns that should be guarded and leaving everything else open for mass assignment.I know I could bypass the whole thing and just update via the Query Builder, but this means that all events, hooks and transformations applied will be bypassed too, which is not optimal.
This Pull Requests proposes a fix that allows for guarding JSON columns analogous to how it is used in the
$fillable
property, with the difference that all keys and their sub-keys are guarded.Caveat
There is another issue I think needs to be discussed, which is not directly in the scope of this PR but should probably be addressed, because it makes any guarding of nested structures vulnerable. The way the mass assignment is handled right now, any key will overwrite any underlying structure in a JSON column. Any array or value you pass on any level of the nested JSON will overwrite whatever was there and not be merged.
We took care of that ourselves by writing a trait that handles the manipulation of the structure. However, by default it's not possible to guard
'meta->languages->en'
effectively, because you can always update['meta->languages' => ['en' => ['hello' => 'world']]]
anytime, not only bypassing the guarded key, but also deleting all other keys on that level.The same is true for
$fillable
, albeit more restrictive. Say you want to allow adding new languages and make'meta->languages'
fillable. Nothing keeps you from accessing or removing all language data belowmeta->languages
. If you want to guardmeta->languages->private
from being overwritten, you're out of luck, because you can always do a$model->fill(['meta->languages' => ['private' => 'boom']])
at the fillable level.I personally think that this behavior was always there and documenting it might be enough.
The last possibility to efficiently use nested JSON fills using Eloquent should probably not be patched out, however.
I have seen other projects overriding the Model methods to change the behavior back, re-introducing the security issues the patch was supposed to mitigate. I'm not keen on following that example ;-)