Skip to content

GraphQL Fragments in Twig Templates#25

Merged
ruudk merged 1 commit intomainfrom
twig
Sep 4, 2025
Merged

GraphQL Fragments in Twig Templates#25
ruudk merged 1 commit intomainfrom
twig

Conversation

@ruudk
Copy link
Owner

@ruudk ruudk commented Sep 4, 2025

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>
{% 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:

$config->withTwigProcessingDirectory(__DIR__ . '/templates')

For Twig CS Fixer:

$config->addTokenParser(new GraphQLTokenParser());

For Symfony:

$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.

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.
@ruudk ruudk changed the title Add Twig integration for co-locating GraphQL fragments with templates GraphQL Fragments in Twig Templates Sep 4, 2025
@ruudk ruudk merged commit 82039c7 into main Sep 4, 2025
2 checks passed
@ruudk ruudk deleted the twig branch September 4, 2025 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant