Conversation
Restores #1531, reverted in v15.37.1 because it exposed internal object state as field values. Also removes the regression test added by the revert, which pinned the behavior this change undoes.
There was a problem hiding this comment.
Pull request overview
Reintroduces (after a prior revert) default resolver behavior that, for values implementing \ArrayAccess, falls back to PHP property access when the requested offset is not available—affecting Executor::defaultFieldResolver() and also __typename lookup in the default type resolver.
Changes:
- Update
Utils::extractKey()to prefer array access but fall back to property access for\ArrayAccessobjects. - Adjust
ExecutorTestcoverage to assert property fallback behavior for\ArrayAccessvalues and remove the prior regression test that pinned “no property access”. - Add an Unreleased changelog entry describing the behavior change.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Utils/Utils.php |
Changes extractKey() resolution order to add property fallback for \ArrayAccess. |
tests/Executor/ExecutorTest.php |
Updates default resolver test expectations to include property fallback for \ArrayAccess. |
CHANGELOG.md |
Documents the behavior change in the Unreleased section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ccess-property-fallback # Conflicts: # CHANGELOG.md
|
I surveyed public consumers to settle the open question of whether the unconditional property fallback is acceptable. What breaksLaravel Eloquent models leak framework state. Drupal graphql 5.x can expose entities.
What is unaffectedAPI Platform, Overblog fields, GraphQLite, Silverstripe, ecodev/graphql-doctrine, Aimeos and Craft (on a 14.x fork) install their own default resolvers. DemandI found 2 requests in 6 years, and both requesters already have working custom resolvers:
nuwave/lighthouse#2687 asks for native PHP properties on Eloquent models, which Lighthouse can handle in its own resolver. Options
The first option fits the data best. |
…ccess-property-fallback
Only values implementing ArrayAccessPropertyFallback fall back to properties. Plain \ArrayAccess values such as Laravel collections, Eloquent models and Drupal field lists keep reading offsets only. Restores the regression test from #1958. 🤖 Generated with Claude Code
Proof of concept, kept as a draft for comparison with nuwave/lighthouse#2687.
The default field resolver reads properties of an
\ArrayAccessobject only when its class implements the new marker interfaceGraphQL\Executor\ArrayAccessPropertyFallback.Plain
\ArrayAccessvalues keep the behavior of v15.37.2, and the regression test from #1958 stays.A marker interface is the only listed option that avoids every breakage from the survey
The options come from #1960 (comment).
Laravel collections, Eloquent models and Drupal
FieldItemListdo not implement it, so nothing changes for them.It is additive, so it can ship in a minor version.
Executor: it is global per schema.Once enabled, it still calls
Collection::__get, which throws, and still reaches Drupal entities throughFieldItemList.That still exposes
exists,incrementingandwasRecentlyCreatedon Eloquent models.The only public API change is the new interface.
It extends
\ArrayAccess, so implementing it replacesimplements \ArrayAccess.Tests cover each case from the survey
tests/Executor/ArrayAccessPropertyFallbackTest.phpchecks that plain\ArrayAccessvalues:exists__getthat throws, like LaravelCollection__isset/__getthat forward to another object, like DrupalFieldItemList__typenameproperty inReferenceExecutor::defaultTypeResolverFor values that opt in, offsets win over properties, and properties fill missing or null offsets, including
__typename.The four plain cases fail against the unconditional fallback that shipped in v15.37.0.
🤖 Generated with Claude Code