Skip to content

Conditional {% use %} not working #3698

@janklan

Description

@janklan

Version context:

Twig version: v3.3.10
Twig Bridge version: 6.0.8
Symfony version: 6.0.8
PHP version: 8.1.5

What's happening:

I just tried to use a different twig trait depending on whether a form variable exists or not.

Below is a simplified version of my template structure.

  1. I'm building a "Create" form that can run inside a modal window driven by Turbo Frames, but the same page also works outside of the modal window, with different surrounding HTML markup, when loaded directly, not via the modal.
  2. My Symfony controller is aware of whether or not the request came from a modal window, and sets a modal variable to either true, or false.

base.html.twig

<html>
<head> ... something shared by a lot of scripts - no markup, just metadata ...</head>
<body>
{%block shell %}{%endblock %}
</body>
</html>

form-base.html.twig

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

{% if modal is defined %}
    {% dump('FIRST') %}
    {% use 'standard-form.html.twig' %}
{% else %}
    {% dump('SECOND') %}
    {% use 'modal-form.html.twig' %}
{% endif %}

standard-form.html.twig

{% block shell %}
    {% block body %}
        {{ form(form) }}
    {% endblock body %}
{% endblock shell %}

modal-form.html.twig

{% block shell %}
<turbo-frame id="modal-content">
    {{ form_start(form) }}
    <div class="header">some header contents</div>
    {% block body %}
        By default we just render the form, but people can override the block body, if they need something more specialised
        {{ form_rest(form) }}
    {% endblock body %}
    <button type="submit">
    {{ form_end(form) }}
</turbo-frame>
    ... some additional modal markup ...
{% endblock shell %}

create.html.twig

{% extends 'form-base.html.twig' %}

{% block body %}
 ... some custom form body markup - not important. 
{% endblock %}

Now, let's not get into whether I'm doing it wrong or not - I know I could extend different base templates etc., my point here is that I tried to use the {% use %} trait and it behaved differently than expected:

Consider the base template:

{% if modal is defined %}
    {% dump('FIRST') %}
    {% use 'standard-form.html.twig' %}
{% else %}
    {% dump('SECOND') %}
    {% use 'modal-form.html.twig' %}
{% endif %}

The core of what's wrong: Even though my debug toolbar dumped FIRST and not the SECOND, twig used the {% block shell %} present in modal-form.html.twig, while it should have used standard-form.html.twig.

Docs (https://twig.symfony.com/doc/3.x/tags/use.html) say that if multiple traits define the same block, the last one wins. When I commented the {% use 'modal-form.html.twig' %} out, the correct template showed up.

Conclusion in what I think is wrong:

When Twig parses the templates, it ignores the if/else construct around the use tag.

Is that expected behaviour? I think it should be at least documented?

I also tried {% use (form is defined ? '_stimulus/shell/modal-form.html.twig' : '_stimulus/shell/modal.html.twig') %}, which would work for example with {% include %}, but I got an error The template references in a "use" statement must be a string., suggesting the template path at that point was not resolved, further confirming my suspition.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions