Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TwigComponent] Unable to access multiple level outerBlocks #2637

Open
adeys opened this issue Mar 14, 2025 · 13 comments
Open

[TwigComponent] Unable to access multiple level outerBlocks #2637

adeys opened this issue Mar 14, 2025 · 13 comments
Labels

Comments

@adeys
Copy link

adeys commented Mar 14, 2025

Hello,
I've come across a limitation of the Twig Component where I can't access multiple level outerBlocks.
Considering this case :

{# templates/activity/_base_activity.html.twig #}

{% block tabs %}
    <twig:Ui:Tabs:Trigger value="content">
        {{ outerScope.content_tab_label|default('label.activity.content'|trans) }}
    </twig:Ui:Tabs:Trigger>

    {% if show_resources|default(false) %}
        <twig:Ui:Tabs:Trigger value="resources">
            {{ 'label.activity.resources'|trans }}
        </twig:Ui:Tabs:Trigger>
    {% endif %}

    {% block additional_tabs %}{% endblock %}
{% endblock %}

{% block content_panel %}{% endblock %}

{% block additional_panels %}{% endblock %}

<twig:Ui:Tabs:Root>
    <twig:Ui:Tabs:List>
        {{ block(outerBlocks.tabs) }}
    </twig:Ui:Tabs:List>

    {% block panels %}
        <twig:Ui:Tabs:Panel value="content" aria-hidden="false">
            {{ block(outerBlocks.content_panel) }}
        </twig:Ui:Tabs:Panel>

        {% if show_resources|default(true) %}
            <twig:Ui:Tabs:Panel value="resources">
                {{ include('activity/_attachment_list.html.twig', {'attachments': attachments}, with_context: false) }}
            </twig:Ui:Tabs:Panel>
        {% endif %}
    {% endblock %}
</twig:Ui:Tabs:Root>
{# templates/activity/_fallback.html.twig #}

{% extends 'activity/_base_layout.html.twig' %}

{% block content_panel %}
    {{ dump(activity) }}
{% endblock %}

The last template was supposed to override the content_panel, but after rendering, both the <twig:Ui:Tabs:List> and the content tab panel are empty.
I tried using outerBlocks.outerBlocks and outerScope.outerBlocks from the <twig:Ui:Tabs:List> component content but they all return the fallback block name.
I managed to make the previous code by using the following workaround, but it souns hackish and may become hard to maintain if I had to access blocks deeper in the component tree :

{# templates/activity/_base_activity.html.twig #}

{% block tabs %}
    <twig:Ui:Tabs:Trigger value="content">
        {{ outerScope.content_tab_label|default('label.activity.content'|trans) }}
    </twig:Ui:Tabs:Trigger>

    {% if show_resources|default(false) %}
        <twig:Ui:Tabs:Trigger value="resources">
            {{ 'label.activity.resources'|trans }}
        </twig:Ui:Tabs:Trigger>
    {% endif %}

    {% block additional_tabs %}{% endblock %}
{% endblock %}

{% block content_panel %}{% endblock %}

{% block additional_panels %}{% endblock %}

<twig:Ui:Tabs:Root>
    {% block tabs %}
        {{ block(outerBlocks.tabs) }}
    {% endblock %}

    {# Same hack for other top level blocks #}

    <twig:Ui:Tabs:List>
        {{ block(outerBlocks.tabs) }}
    </twig:Ui:Tabs:List>

    {% block panels %}
        <twig:Ui:Tabs:Panel value="content" aria-hidden="false">
            {{ block(outerBlocks.content_panel) }}
        </twig:Ui:Tabs:Panel>

        {% if show_resources|default(true) %}
            <twig:Ui:Tabs:Panel value="resources">
                {{ include('activity/_attachment_list.html.twig', {'attachments': attachments}, with_context: false) }}
            </twig:Ui:Tabs:Panel>
        {% endif %}
    {% endblock %}
</twig:Ui:Tabs:Root>

I'd like if I'm doing something wrong. What would be the best way to achieve what I'm looking for ? And what would be alternatives if I had to come back to an approach without components ?

@adeys adeys added the Bug Bug Fix label Mar 14, 2025
@adeys
Copy link
Author

adeys commented Mar 27, 2025

Any feedback here ?

@smnandre
Copy link
Member

Your component template is the fallback one here, right ?

@adeys
Copy link
Author

adeys commented Mar 28, 2025

No, the fallback.html.twig is just a regular Twig template extending one (_base_layout.html.twig) that uses the components

@smnandre
Copy link
Member

I’m sorry I’m not sure to understand who renders what here. Could you explain me maybe: what is your top template, and the chain of template included, rendered, etc ?

@adeys
Copy link
Author

adeys commented Mar 28, 2025

Hello @smnandre. Sorry for the delay.
Here is the rendering graph :
The top template is templates/activity/layout.html.twig and here is how it refers remaining templates :

{{ include(['activity/_' ~ currentActivity.type.value ~ '.html.twig', 'course/activity/_fallback.html.twig'], {
    'activity': currentActivity,
    ....other params
}, with_context = true) }}

Each of the other templates (_activity_type_1.html.twig, _activity_type_2.html.twig, ..., _fallback.html.twig) extends the templates/activity/_base_layout.html.twig, so they can customize it depending on the activity type.
Here is the templates/activity/_base_layout.html.twig content :

{# templates/activity/_base_activity.html.twig #}

{% block tabs %}
    <twig:Ui:Tabs:Trigger value="content">
        {{ outerScope.content_tab_label|default('label.activity.content'|trans) }}
    </twig:Ui:Tabs:Trigger>

    {% if show_resources|default(false) %}
        <twig:Ui:Tabs:Trigger value="resources">
            {{ 'label.activity.resources'|trans }}
        </twig:Ui:Tabs:Trigger>
    {% endif %}

    {% block additional_tabs %}{% endblock %}
{% endblock %}

{% block content_panel %}{% endblock %}

{% block additional_panels %}{% endblock %}

<twig:Ui:Tabs:Root>
    <twig:Ui:Tabs:List>
        {{ block(outerBlocks.tabs) }}
    </twig:Ui:Tabs:List>

    {% block panels %}
        <twig:Ui:Tabs:Panel value="content" aria-hidden="false">
            {{ block(outerBlocks.content_panel) }}
        </twig:Ui:Tabs:Panel>

        {% if show_resources|default(true) %}
            <twig:Ui:Tabs:Panel value="resources">
                {{ include('activity/_attachment_list.html.twig', {'attachments': attachments}, with_context: false) }}
            </twig:Ui:Tabs:Panel>
        {% endif %}
    {% endblock %}
</twig:Ui:Tabs:Root>

Given this content below in the templates/activity/_fallback.html.twig template, I was expecting to see the dumped content in the content_panel block but it just renders an empty content :

{# templates/activity/_fallback.html.twig #}

{% extends 'activity/_base_layout.html.twig' %}

{% block content_panel %}
    {{ dump(activity) }}
{% endblock %}

@smnandre
Copy link
Member

smnandre commented Mar 30, 2025

So in your situation the template 'activity/_' ~ currentActivity.type.value ~ '.html.twig' does not exist that's right ?

@adeys
Copy link
Author

adeys commented Mar 30, 2025

The template exists.
My issue is that I can't override a block (content_panel) in a child template (_fallback.html.twig) because it's rendered in a Twig Component in the extended template.
As the component is two depth down the tree, I can't access top level blocks

@smnandre
Copy link
Member

Hmm.

I'd say, as the template exists, _fallback is entirely out of the picture, so none of your templates knows a thing about it. It is not included, nor run, so it is not injected and does not belong in the out blocks.

@adeys
Copy link
Author

adeys commented Mar 30, 2025

The fact is I have the same issue when I remove the dynamically referred templates so that only the fallback is rendered, and when I put the exact same content from the existing fullback template to the other included templates.

My point is that it's not a missing or not included template issue, I understand all the logic behind this. It's just that I can't access top-level blocks from the components content block

@smnandre
Copy link
Member

Can you provide me a smaller reproducer, without all the "other stuff" here (especially if you say they are not related to), so we can then focus on the bug and find maybe a solution ?

@adeys
Copy link
Author

adeys commented Mar 30, 2025

@smnandre
Copy link
Member

smnandre commented Apr 2, 2025

Ok i see now, easier to me when I can play a bit with the code.

Not sure if this is a feature or a bug to be honest, as indeed the index.html template has no knowledge of the overriden block at this point.

@adeys
Copy link
Author

adeys commented Apr 2, 2025

I can understand 😅.

Do you have any suggestions or workaround for this, so I don't have to repeat it in all required templates?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants