-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
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.
- 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.
- My Symfony controller is aware of whether or not the request came from a modal window, and sets a
modalvariable 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.