web-dev-qa-db-fra.com

Remplacement de blocs dans les modèles Twig inclus

Existe-t-il généralement un "bon" moyen de réaliser cette fonctionnalité? J'ai lu des informations sur la balise 'use', qui semble être la meilleure option jusqu'à présent, mais je n'aime toujours pas qu'elle ne me permette pas d'introduire de code html extérieur, mais uniquement des blocs.

J'utiliserai la balise 'include' dans l'exemple ci-dessous pour démontrer l'intention que je tente de décrire.

#base.html.twig
{% include 'elements/header.html.twig' %}
{% block content %}{% endblock %}
{% include 'elements/footer.html.twig' %}

#header.html.twig
<h1>This is my header</h1>
{% block page_title %} Default Page Title {% endblock %}

#index.html.twig
{% extends 'layouts/base.html.twig' %}
{# I want to be able to do this somehow #}
{% block page_title %} This is my overridden page title {% endblock %}
{% block content %} here is the index page content {% endblock %}
44
bruchowski

J'ai trouvé une solution. Utilisez la fonction block () pour obtenir le contenu du bloc de l'enfant et le transmettre à header.html.twig en tant que variable dans l'instruction include

#base.html.twig
{% include 'elements/header.html.twig' with {page_title: block('page_title')} %}
{% block content %}{% endblock %}
{% include 'elements/footer.html.twig' %}

#header.html.twig
<h1>This is my header</h1>
{% if page_title is empty %}
Default Page Title
{% else %}
{{ page_title }}
{% endif %}

#index.html.twig
{% extends 'layouts/base.html.twig' %}
{% block page_title %} This is my overridden page title {% endblock %}
{% block content %} here is the index page content {% endblock %}
53
Webberig

J'ai trouvé une solution good and real en lisant la documentation pour la balise embed. J'utilise Twig 2.0 dans Symfony 4.

Ma structure

#templates/base.html.twig
{% block navbar %}
    <nav>
    {% block menu %}
        {% include '_menu' %}
    {% endblock menu %}
    </nav>
{% endblock navbar %}
{% block content %}
    {# several blocks defined #}
    {% block footer '' %}
{% endblock content %}

#templates/_menu.html.twig
<ul>
    {% block sub_app_menu_itens %}
        <li>Main App Menu Item</li>
    {% endblock sub_app_menu_itens %}
    <li>Menu item</li>
    <li>Another menu item</li>
    <li>Yet another menu item</li>
</ul>

Avec le code ci-dessus, lorsque je crée mon index.html.twig, le seul code nécessaire pour afficher les éléments par défaut est

#templates/index.html.twig
{% extends 'base.html.twig' %}

et remplacer les blocs définis . Mais, lorsque je dois créer une autre page utilisant ce squelette, si j'essaie de remplacer block, sub_app_menu_itens dans un autre modèle _partial inclus, ne fonctionne pas. <li>Main App Menu Item</li> est toujours affiché et jamais écrasé (code ci-dessus)

#templates/subapp/index.html.twig
{% extends 'base.html.twig' %}
{% block title %}{{ 'agencia.homepage'|trans }}{% endblock %}
{% block menu %}
    {% include 'subapp/_menu.html.twig' %}
{% endblock menu %}
{% block user_content %}Content Here{% endblock %}

#templates/subapp/_menu.html.twig
{% extends '_menu.html.twig' %}
{% block sub_app_menu_itens %}
        <li>SubApp Menu Item</li> 
{% endblock sub_app_menu_itens %}

<li>SubApp Menu Item</li> n'est jamais affiché. J'ai essayé beaucoup de choses comme extends et même des conditionnels sans chance.

La solution

La balise embed résout les blocs de modèles partiels enfants à écraser.

#templates/subapp/index.html.twig
{% block menu %}
    {% embed '_menu.html.twig' %}
        {% block sub_app_menu_itens %}
            {% include 'subapp/_menu.html.twig' %}
        {% endblock sub_app_menu_itens %}
    {% endembed %}
{% endblock menu %}

Et simplifier le modèle _partial pour n’avoir que le code HTML nécessaire

#templates/subapp/_menu.html.twig 
    <li>SubApp Menu Item</li> 

Maintenant, <li>SubApp Menu Item</li> sera affiché au bon endroit du modèle _menu.

En pensant aux niveaux, une include fonctionne comme un sous-niveau (analysé) et toutes les choses sont seulement écrasées au même niveau, donc include ne permet pas de remplacer dans une autre inclusion. Au lieu de cela, les modèles embed sont amenés au même niveau (non analysés) et vous pouvez donc remplacer des éléments.

3
Marcos Regis

Ça peut être fait. Voici ma solution au problème en passant une variable à la vue.

#layout.twig
{% if sidebar is empty %}
    This is the default sidebar text.
{% else %}
    {% block sidebar %}{% endblock %}
{% endif %}
{% block content %}{% endblock %}

#index.twig
{% extends "layout.twig" %}
{% block sidebar %}
    This is the sidebar. It will override the default text.
{% endblock %}

{% block content %}
    This is the content.
{% endblock %}

#index.php (SlimPHP)
$app->render('index.twig', ['sidebar' => true]);

Depuis que j'utilise SlimPHP comme je l'appelle, je transmets la variable sidebar à la vue. Cela peut être étendu davantage en utilisant différentes variables transmises à la vue, de sorte que vous puissiez sélectionner sidebar1, sidebar2 etc.

1
kacperek

Je l'ai fait pour travailler avec un hack très simple:

En gros, il se comporte de cette façon car sans {% extends "foo.html.twig" %}, il ne comprend pas les blocs et les restitue simplement.

Alors étendons ... rien:

{% extends "nothing.html.twig" %}

Ce rien est vraiment juste 1 bloc:

# nothing.html.twig
{% block main %}
{% endblock %}

La seule chose à faire est que vous devez tout emballer dans un bloc, ce faux bloc "principal".

0
lipsumar