Commit 82039c7
committed
GraphQL Fragments in Twig Templates
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.1 parent 33589f7 commit 82039c7
30 files changed
Lines changed: 1006 additions & 4 deletions
File tree
- .github/workflows
- src
- Config
- Twig
- tests/Twig
- Generated
- Enum
- Fragment
- AdminProjectList
- Query/Projectsd4cba6
- templates
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
53 | 56 | | |
54 | 57 | | |
55 | 58 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
26 | 29 | | |
27 | 30 | | |
28 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| 12 | + | |
| 13 | + | |
11 | 14 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
40 | 41 | | |
41 | 42 | | |
42 | 43 | | |
43 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
44 | 50 | | |
45 | 51 | | |
46 | 52 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
| 52 | + | |
51 | 53 | | |
52 | 54 | | |
53 | 55 | | |
| |||
187 | 189 | | |
188 | 190 | | |
189 | 191 | | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
190 | 197 | | |
191 | 198 | | |
192 | 199 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| 11 | + | |
10 | 12 | | |
11 | 13 | | |
12 | 14 | | |
| |||
76 | 78 | | |
77 | 79 | | |
78 | 80 | | |
| 81 | + | |
| 82 | + | |
79 | 83 | | |
80 | 84 | | |
81 | 85 | | |
| |||
89 | 93 | | |
90 | 94 | | |
91 | 95 | | |
| 96 | + | |
| 97 | + | |
92 | 98 | | |
93 | 99 | | |
94 | 100 | | |
| |||
287 | 293 | | |
288 | 294 | | |
289 | 295 | | |
| 296 | + | |
| 297 | + | |
290 | 298 | | |
291 | 299 | | |
292 | 300 | | |
| |||
312 | 320 | | |
313 | 321 | | |
314 | 322 | | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
315 | 353 | | |
316 | 354 | | |
317 | 355 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
0 commit comments