Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add block_data() and block_export() functions #4919

Description

@seb-jean

Description

Currently, Twig's block() function renders a block and returns the result as an HTML string. There is no way to extract structured data from a block.

This becomes a limitation when using Twig Components (<twig:> syntax), where the spread syntax ({{ ...hash }}) requires an associative array, not an HTML string.

Use case: Symfony Form themes with Twig Components

In Symfony's form themes, blocks like widget_attributes and attributes render HTML attribute strings:

<input type="text" {{ block('widget_attributes') }} />
{# outputs: id="name" name="form[name]" required="required" #}

A Twig Component form theme needs the same data as a hash for spread syntax:

<twig:Input type="text" {{ ...block_data('widget_attributes') }} />

Proposal

Add two new Twig functions:

block_export(data)

Called inside a block to export structured data via a side-channel (stored on CoreExtension). The block continues to render HTML normally.

{% block attributes %}
    {%- set attrs = {} -%}
    {%- for attrname, attrvalue in attr -%}
        {%- if attrvalue is same as(true) -%}
            {%- set attrs = attrs|merge({(attrname): attrname}) -%}
        {%- elseif attrvalue is not same as(false) -%}
            {%- set attrs = attrs|merge({(attrname): attrvalue}) -%}
        {%- endif -%}
    {%- endfor -%}
    {%- do block_export(attrs) -%}
    {%- for attrname, attrvalue in attrs -%}
        {{- ' ' ~ attrname }}="{{ attrvalue }}"
    {%- endfor -%}
{% endblock %}

block_data(name)

Renders the block (HTML output is discarded) and returns the data exported via block_export(). Returns [] if the block does not call block_export().

{{ block_data('attributes').id }}
{# returns the structured hash instead of the HTML string #}

Implementation

  • block_data() uses a parser_callable (like block()) to compile to a BlockDataExpression node
  • BlockDataExpression compiles to $this->unwrap()->renderBlockData(...)
  • Template::renderBlockData() calls renderBlock() then returns the exported data from CoreExtension::getExportedBlockData()
  • The exported data is consumed on read (reset to null), preventing leaks between calls

Why not a different approach?

  • Returning data from blocks directly: Twig blocks compile to PHP methods with array $context passed by value (variables set inside don't propagate back)
  • New PHP Twig functions (e.g. in Symfony): would duplicate the logic already in the Twig blocks (translations, boolean normalization), and wouldn't benefit from block inheritance/override
  • block_data()/block_export(): keeps the logic in one place (the block), works with block inheritance, and is fully backward-compatible (existing blocks continue to render HTML as before)

Related: symfony/symfony#65713

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions