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

Strange behavior with block function inside parent block #3321

Open
hlecorche opened this issue May 7, 2020 · 2 comments
Open

Strange behavior with block function inside parent block #3321

hlecorche opened this issue May 7, 2020 · 2 comments

Comments

@hlecorche
Copy link

hlecorche commented May 7, 2020

Hello,

I found a strange behavior with all Twig versions.

{{ block('block1', 'theme.html.twig') }}`


{# theme.html.twig #}
{% extends 'base.html.twig' %}

{%- block block2 -%}
    BLOCK2THEME/
{%- endblock -%}



{# base.html.twig #}
{%- block block1 -%}
    BLOCK1BASE/
    {{- block('block2') -}}
{%- endblock -%}

{%- block block2 -%}
    BLOCK2BASE/
{%- endblock -%}

https://twigfiddle.com/jae42d

The result is the expected result : BLOCK1BASE/BLOCK2THEME/

  • block1: base.html.twig is used
  • block1 in base.html.twig calls block2: theme.html.twig is used (because block2 is overridden by theme.html.twig)

But I have a strange result if block1 is overridden and parent() is called :

{{ block('block1', 'theme.html.twig') }}`


{# theme.html.twig #}
{% extends 'base.html.twig' %}

{%- block block1 -%}
    {{- parent() -}}
    BLOCK1THEME/
{%- endblock -%}

{%- block block2 -%}
    BLOCK2THEME/
{%- endblock -%}



{# base.html.twig #}
{%- block block1 -%}
    BLOCK1BASE/
    {{- block('block2') -}}
{%- endblock -%}

{%- block block2 -%}
    BLOCK2BASE/
{%- endblock -%}

https://twigfiddle.com/jae42d/2

Expected result : BLOCK1BASE/BLOCK2THEME/BLOCK1THEME/
Result: BLOCK1BASE/BLOCK2BASE/BLOCK1THEME/

  • block1: theme.html.twig is used (because block1 is overridden by theme.html.twig)
  • block 1 in theme.html.twig calls parent: base.html.twig is used
  • block1 in base.html.twig calls block2: Unlike to the last example, theme.html.twig is not used. Why ?
@SanderVerkuil
Copy link

SanderVerkuil commented Jun 5, 2020

I'm having a similar issue, so I'm interested into why there is a difference between including the template, and rendering a block from a template.

Defining the template as such:

{# main.html.twig #}
{{ block('block1', 'theme.html.twig') }}

{% include 'theme.html.twig' %}


{# theme.html.twig #}
{% extends 'base.html.twig' %}

{%- block block1 -%}
    {{- parent() -}}
    BLOCK1THEME/
{%- endblock -%}

{%- block block2 -%}
    BLOCK2THEME/
{%- endblock -%}


{# base.html.twig #}
{%- block block1 -%}
    BLOCK1BASE/
    
    {%- block block2 -%}
        BLOCK2BASE/
    {%- endblock -%}
{%- endblock -%}

https://twigfiddle.com/jae42d/3

I'd expect the outputs to be the same.

Looking at the compiled templates, including a block from another template displays the block from the parent.

It appears however that when rendering a block in a template with the block() function, the inheritance is lost when displaying the block.

Is there a reason that the inheritance works differently when including a template vs rendering a specific block from a template?

edit:
When debugging the templates, I noticed that when including theme.html.twig the parent is set, but when calling block('block1', 'theme.html.twig') the parent is null.

The parent is set in the doDisplay call, when the extends statement is evaluated. When displaying a block the doDisplay is not called, and the parent is not loaded. It is not possible to call the extends in a block, so it is not possible to set the parent inside a block, which I'm sure has a good reason to not allow.

@chapterjason
Copy link

chapterjason commented Jan 8, 2022

I came across the same issue, I think that is one of the reasons why the symfony form component has it's own renderer.

I have a small workaround, the only limit is that you always have to passthrough the template name.
I the way my usage is, I always know the template.

    public function renderMenuBlock(Environment $environment, array $context, string $blockName, ?string $templateName = null): string
    {
        $templateName = $templateName ?? $this->defaultOptions['template'];
        $template = $environment->resolveTemplate($templateName);

        ob_start();

        $template->displayBlock($blockName, $context);

        return ob_get_clean();
    }

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

No branches or pull requests

4 participants