feat: add directive-aware field selection - #1971
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an opt-in directive-aware alternative to ResolveInfo::getFieldSelection() so resolver optimizations can ignore selections disabled by @skip / @include, while keeping legacy behavior unchanged for existing callers.
Changes:
- Introduce
ResolveInfo::getFieldSelectionRespectingDirectives()with directive evaluation against operation variables. - Add unit tests covering conditional fields, fragment spreads (including repeats), inline fragments, nesting, and directive precedence.
- Update resolver optimization documentation and class reference; add a changelog entry.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/Type/Definition/ResolveInfo.php |
Adds directive-aware field selection folding/merging and a new public API method. |
tests/Type/ResolveInfoTest.php |
Adds test coverage validating directive-respecting behavior vs legacy behavior. |
docs/data-fetching.md |
Updates resolver optimization example and guidance to use the new method when directives are present. |
docs/class-reference.md |
Documents the new ResolveInfo method in the API reference. |
CHANGELOG.md |
Notes the new API addition under “Unreleased”. |
Suppressed comments (2)
src/Type/Definition/ResolveInfo.php:512
- This helper is
protected, which makes it part of the subclass API surface. If subclasses are not intended to customize directive-aware merging, making thisprivate(consistent withfoldSelectionSet) reduces long-term compatibility constraints.
protected function mergeSelectionsRespectingDirectives(array $left, array $right): array
src/Type/Definition/ResolveInfo.php:532
- This method is
protected, which exposes a new override point inResolveInfo. If overriding isn't an intended extension mechanism, preferprivateto keep directive-inclusion rules stable and avoid subclass behavior changes.
protected function shouldIncludeSelectionNodeRespectingDirectives(SelectionNode $node): bool
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| * | ||
| * @return array<string, mixed> | ||
| */ | ||
| protected function foldSelectionSetRespectingDirectives(SelectionSetNode $selectionSet, int $descend): array |
There was a problem hiding this comment.
Keeping these helpers protected is intentional. CONTRIBUTING.md requires protected over private for extensibility (Extensibility > protected over private). The existing private helper does not override that documented rule.
| } | ||
|
|
||
| /** | ||
| * @param FragmentSpreadNode|FieldNode|InlineFragmentNode $node |
There was a problem hiding this comment.
The narrower PHPDoc is intentional. SelectionNode is an empty marker interface, while this method accepts the three concrete selection node types. This also matches the PHPDoc on ReferenceExecutor::shouldIncludeNode(), so keeping the union helps static analysis and preserves consistency.
Context
Resolvers can use field selections to optimize data fetching, but
ResolveInfo::getFieldSelection()includes selections disabled by@skipand@include. This can cause unnecessary work when clients use conditional selections.Decision
Add the opt-in
ResolveInfo::getFieldSelectionRespectingDirectives()method. It evaluates built-in selection directives with operation variables while leaving the existing method unchanged for backward compatibility.Document the method in the resolver optimization guide and cover fields, fragment spreads, inline fragments, nested selections, directive precedence, repeated fragments, and legacy behavior.
Consequences