Fabien Potencier 4c005c1ada feature #4917 Template runtime and block composition (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Template runtime and block composition

This PR addresses the Symfony compatibility break from #4910

It introduces runtime composition of templates used as collections of named block renderers: The renderer provides an ordered set of unrelated templates. The first matching block wins, nested `block()` calls see the complete composed set, and `parent()` remains within the block’s own inheritance or `use` hierarchy.

This feature is going to be useful for more than just Symfony.

## Strong non-Symfony use cases

### Ibexa Core

**Project:** `ibexa/core`
**Feature:** CMS field rendering through `FieldBlockRenderer`

Ibexa maintains prioritized field templates, selects blocks such as `ibexa_string_field`, walks parent templates, constructs a block map and passes it to `renderBlock()`.

This is the strongest independent fit for `BlockChain`:

```php
$blocks = new BlockChain($twig, [
    $localTemplate,
    ...$projectFieldThemes,
    ...$vendorFieldThemes,
]);

return $blocks->renderBlock($fieldType.'_field', $context);
```

### Data-grid and listing renderers

The audit found the same broad mechanism in:

- `Prezent/prezent-grid`, `src/Twig/GridRenderer.php`
- `pawellen/listing`, `Renderer/ListingRenderer.php`
- `Braunstetter/data-grid-bundle`, `src/GridRendererEngine.php`
- `AnoDataGrid`, `DataGridExtension.php`

Their common feature is **layered grid themes**:

1. Configure default grid templates.
2. Add per-grid or per-view overrides.
3. Map a column type to a block name.
4. Walk template inheritance.
5. Merge or cache available blocks.
6. Render the selected cell, header or filter block.

Several accessed `unwrap()`, `getBlocks()` or `getParent()` directly; others passed manually assembled block maps into `renderBlock()` or `displayBlock()`.

## Adjacent use cases

The audit also found block-library patterns that could benefit if they grow into multi-template composition:

- **iTop:** plugin-contributed login blocks such as `login_input`, `login_submit`, `login_form_footer` and `login_links`; independently renders `body`, `script`, `ready_script` and `css`.
- **Email renderers:** independently render `subject`, `body_text` and `body_html` blocks.
- **Runtime theme overlays:** tenant branding, application skins, email themes, reports and configurable admin interfaces.
- **Extension-provided block libraries:** enabled modules contribute blocks such as `toolbar`, `field_text`, `dashboard_metric` or `login_footer`.
- **Testing and preview tooling:** render a block against an exact theme stack without generating a synthetic host template.

## Important negative finding

Shopware-style plugin inheritance, and similar Drupal or Sylius layering, are **not** considered a direct fit. Those systems expect `parent()` to call the next plugin override. `BlockChain` deliberately keeps `parent()` inside the defining template’s normal lineage.

Commits
-------

49f814ea26 Template runtime and block composition
2026-09-11 04:57:43 -07:00

Twig, the flexible, fast, and secure template language for PHP
==============================================================

Twig is a template language for PHP.

Twig uses a syntax similar to the Django and Jinja template languages which
inspired the Twig runtime environment.

Sponsors
--------

.. raw:: html

    <a href="https://docs.blackfire.io/introduction?utm_source=twig&utm_medium=github_readme&utm_campaign=logo">
        <img src="https://static.blackfire.io/assets/intemporals/logo/png/blackfire-io_secondary_horizontal_transparent.png?1" width="255px" alt="Blackfire.io">
    </a>

More Information
----------------

Read the `documentation`_ for more information.

.. _documentation: https://twig.symfony.com/documentation
Languages
PHP 99.9%