Skip to content

Read public PHP properties of models in the default field resolver - #2693

Draft
spawnia wants to merge 18 commits into
masterfrom
change-the-default-field-resolver
Draft

spawnia wants to merge 18 commits into
masterfrom
change-the-default-field-resolver

Conversation

@spawnia

@spawnia spawnia commented Jun 12, 2025 •

Copy link
Copy Markdown
Collaborator

Resolves #2191
Resolves #1671
Resolves #2687

  • Added or updated tests
  • Documented user facing changes
  • Updated CHANGELOG.md

Changes

Fields on Eloquent models ignore public PHP properties and call accessors twice.
Lighthouse now installs its own default field resolver that reads each attribute once and falls back to public properties of the model.

This is the Lighthouse-side alternative to webonyx/graphql-php#1960, which adds an opt-in marker interface to graphql-php instead.

Eloquent's own properties stay hidden, avoiding the leaks found in the graphql-php survey

The survey in webonyx/graphql-php#1960 (comment) lists what an unconditional property fallback breaks.
The resolver only reads a property when it is public, not static, and declared outside Illuminate\.
Names that exist on Eloquent\Model, such as exists, incrementing, timestamps, wasRecentlyCreated and preventsLazyLoading, resolve to null, also when a model redeclares them.
Values other than models, such as Laravel collections, still go through Utils::extractKey(), so Collection::__get is never called.

A property fills a null attribute, a non-null attribute wins

When a model has an attribute and a public property of the same name, the resolver returns the attribute unless it is null.
This matches the fallback order of webonyx/graphql-php#1960.

Breaking changes

Fields that resolved to null because they matched a public model property now return the property value.
Null accessors run once instead of twice.
UPGRADE.md lists both.

🤖 Generated with Claude Code

@spawnia spawnia added enhancement A feature or improvement 7.x Related to the 7.x release series labels Jun 12, 2025
@spawnia
spawnia marked this pull request as draft June 12, 2025 20:37
spawnia and others added 6 commits June 16, 2025 09:49
…field-resolver

# Conflicts:
#	CHANGELOG.md
#	docs/master/digging-deeper/extending-lighthouse.md
🤖 Generated with Claude Code
@spawnia spawnia changed the title Change the default field resolver Read public PHP properties of models in the default field resolver Sep 28, 2026
@spawnia
spawnia requested a balanced review from Copilot September 28, 2026 10:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Uninitialized public typed model properties can currently cause GraphQL execution errors.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

Introduces a Lighthouse default field resolver that supports public Eloquent model properties while avoiding duplicate accessor reads.

Changes:

  • Adds model-aware attribute/property resolution.
  • Adds regression coverage for models and collections.
  • Documents the resolver’s behavioral changes.
File Description
src/​LighthouseServiceProvider.php Registers and implements the resolver.
tests/​Integration/​DefaultFieldResolverTest.php Tests collection key resolution.
tests/​Integration/​Models/​PropertyAccessTest.php Tests model properties, accessors, and framework-property hiding.
tests/​Utils/​Models/​User.php Extends the model fixture for resolver tests.
docs/​master/​digging-deeper/​extending-lighthouse.md Documents resolver customization.
UPGRADE.md Describes upgrade behavior changes.
CHANGELOG.md Records the resolver override.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

if ($root instanceof Model) {
$property = $root->getAttribute($fieldName);
if ($property === null && static::isApplicationProperty($root, $fieldName)) {
$property = $root->{$fieldName};
Comment thread UPGRADE.md
### Default field resolver changed

The default field resolver was changed from `GraphQL\Executor\Executor::defaultFieldResolver()` to `Nuwave\Lighthouse\LighthouseServiceProvider::defaultFieldResolver()`.
The new default fields resolver is expected to be mostly compatible with the previous one, but introduces some behavior changes when resolving models:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

7.x Related to the 7.x release series enhancement A feature or improvement

Projects

None yet

3 participants