Conversation
GraphQL Fragments in Twig Templates
Traditional GraphQL queries often become "monster queries" - massive operations where you're
afraid to remove any field because it might be used somewhere deep in your template hierarchy. You
end up with bloated queries that fetch unnecessary
data, making maintenance a nightmare.
This new feature solves that problem by letting you co-locate data requirements with your
templates. Each Twig template can define exactly what GraphQL data it needs through fragments,
ensuring perfect alignment between your views and their data
dependencies.
How it works
Controller: Keep queries simple - just reference the top-level fragment
final readonly class SomeController
{
private const string OPERATION = <<<'GRAPHQL'
query Projects {
...AdminProjectList
}
GRAPHQL;
public function __invoke(): string
{
return $this->twig->render('list.html.twig', [
'data' => $this->query->executeOrThrow()->adminProjectList,
]);
}
}
Main template (list.html.twig): Define what data this template needs
{% graphql %}
fragment AdminProjectList on Query {
viewer { name }
projects {
...AdminProjectRow
}
}
{% endgraphql %}
<h1>Good day, {{ data.viewer.name }}</h1>
GraphQL Fragments in Twig Templates
Traditional GraphQL queries often become "monster queries" - massive operations where you're afraid
to remove any field because it might be used somewhere deep in your template hierarchy. You end up
with bloated queries that fetch unnecessary
data, making maintenance a nightmare.
This new feature solves that problem by letting you co-locate data requirements with your templates.
Each Twig template can define exactly what GraphQL data it needs through fragments, ensuring perfect
alignment between your views and their data
dependencies.
## How it works
Controller: Keep queries simple - just reference the top-level fragment
```php
final readonly class SomeController
{
private const string OPERATION = <<<'GRAPHQL'
query Projects {
...AdminProjectList
}
GRAPHQL;
public function __invoke(): string
{
return $this->twig->render('list.html.twig', [
'data' => $this->query->executeOrThrow()->adminProjectList,
]);
}
}
```
Main template (list.html.twig): Define what data this template needs
```twig
{% graphql %}
fragment AdminProjectList on Query {
viewer { name }
projects {
...AdminProjectRow
}
}
{% endgraphql %}
<h1>Good day, {{ data.viewer.name }}</h1>
{% for project in data.projects %}
{{ include('_project_row.html.twig', {project: project.adminProjectRow}) }}
{% endfor %}
```
Partial template (_project_row.html.twig): Each partial declares its own requirements
```twig
{% graphql %}
fragment AdminProjectRow on Project {
id
name
description
...AdminProjectOptions
}
{% endgraphql %}
<li>#{{ project.id }} - {{ project.name }}</li>
```
## Setup
Enable Twig processing:
```php
$config->withTwigProcessingDirectory(__DIR__ . '/templates')
```
For Twig CS Fixer:
```php
$config->addTokenParser(new GraphQLTokenParser());
```
For Symfony:
```php
$services->set(\Ruudk\GraphQLCodeGenerator\Twig\GraphQLExtension::class)->tag('twig.extension');
```
Each template owns its data requirements, making refactoring safe and predictable. No more guessing
which fields are actually used - the data dependencies are right there with the template that needs
them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Traditional GraphQL queries often become "monster queries" - massive operations where you're afraid to remove any field because it might be used somewhere deep in your template hierarchy. You end up with bloated queries that fetch unnecessary
data, making maintenance a nightmare.
This new feature solves that problem by letting you co-locate data requirements with your templates. Each Twig template can define exactly what GraphQL data it needs through fragments, ensuring perfect alignment between your views and their data
dependencies.
How it works
Controller: Keep queries simple - just reference the top-level fragment
Main template (list.html.twig): Define what data this template needs
{% graphql %} fragment AdminProjectList on Query { viewer { name } projects { ...AdminProjectRow } } {% endgraphql %} <h1>Good day, {{ data.viewer.name }}</h1> {% for project in data.projects %} {{ include('_project_row.html.twig', {project: project.adminProjectRow}) }} {% endfor %}Partial template (_project_row.html.twig): Each partial declares its own requirements
{% graphql %} fragment AdminProjectRow on Project { id name description ...AdminProjectOptions } {% endgraphql %} <li>#{{ project.id }} - {{ project.name }}</li>Setup
Enable Twig processing:
For Twig CS Fixer:
For Symfony:
Each template owns its data requirements, making refactoring safe and predictable. No more guessing which fields are actually used - the data dependencies are right there with the template that needs them.