[2.x] Resolve Closure before checking if a prop implements the Arrayable contract #706
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.

On my projects, I use
spatie/laravel-view-modelsto organize complex controller responses.The
Spatie\ViewModels\ViewModelimplements theIlluminate\Contracts\Support\Arrayable, so when Inertia can handle aViewModelinstance like a set of props.When a
ViewModelinstance is converted to an array, all public properties and methods are converted to array keys. If a public method does not expect any parameters, then it is executed and its value is used. On the other hand, if a public method expects one or more parameters, it is converted to a\Closure.Currently, the
Inertia\Response@resolveArrayableProperties()method, checks if a property is a\Closureafter checking if it is an object that implementsIlluminate\Contracts\Support\Arrayable, which to me makes little sense as the method is named to "resolve arrayable properties".Use case
I have the following view model:
Where
App\Support\UserPreferencesalso implementsIlluminate\Contracts\Support\Arrayable.Currently, when
SettingsViewModel@toArray()is called,SettingsViewModel@preferencesis converted to a\Closure, and whenInertia\Response@resolveArrayableProperties()is called, the\Closureis executed after checking if the property implements theArrayablecontract.I end up with a property holding an empty object, as it doesn't get properly processed.
A simpler example would be returning a
\Closurethat returns a simpleArrayableinstance:The response currently converts the
fooproperty to an empty object, when I, as a user, would expect itstoArray()method to be executed:{ "component": "IndexPage", "props": { "errors": {}, "foo": {} }, "url": "\/home", "version": "4847538ced1a39bde916e313e3dda74a", "clearHistory": false, "encryptHistory": false }This PR:
\Closurebefore checking if a property implementsArrayable