render option twice in base.html.twig - php

I got base.html.twig file inside i wanna render two controller
Is that is possible ?
</head>
<body>
{% block header %}{{ render(controller('App\\Controller\\FrontController::front_header')) }}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{{ render(controller('App\\Controller\\FrontController::front_footer')) }}{% endblock %}
</body>
{% block javascripts %}{% endblock %}
or what way is the best to handle something like that ?
becouse frontcontroller render anothe index.html.twig which will get some stuff to block content and i wanna have this block content between two another controllers.

why not simply use Twig include for your header and your footer?

Related

Two templates showed

I'm using FOSUserBundle on my Symfony4 project, and I overrode all bundle templates, and place them on my templates folder.
I have my base.html.twig file, is the main page template that contains initial HTML script for all stylesheets and javascript files. On the body I added the content block:
<body>
{% block content %}{% endblock content %}
</body>
Then, on my login template, I extended the main template and added the fos_user_content block:
{% extends 'bundles/landing.html.twig' %}
{% block content %}
{% block fos_user_content %}
{% endblock content %}
And for the moment everything is ok. The login form is displayed well. But when I log into this form, the system switched me to the Profile page. The problem, is that, the profile page template is showed and the login template too.
Both the templates are used.
On the profile template, I extended the main template too + added the same block content, except the fos_user_content block.
You missed an {% endblock fos_user_content %} tag
{% extends 'bundles/landing.html.twig' %}
{% block content %}
{% block fos_user_content %}{% endblock fos_user_content %}
{% endblock content %}

Difference between Include, Extends, Use, Macro, Embed in Twig

What is the difference between use and include in Twig?
Documentation:
include
The include statement includes a template and returns the rendered content of that template into the current one:
{% include 'header.html' %}
Body here...
{% include 'footer.html' %}
use
The use statement tells Twig to import the blocks defined in blocks.html into the current template (it's like macros, but for blocks):
blocks.html
{% block sidebar %}{% endblock %}
main.html
{% extends "base.html" %}
{% use "blocks.html" %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}
Possible answer:
I think this should explain the difference:
include is to get all the code from an external file and import it
into your actual file at the right location of the call.
use is completely different as it parses the linked file to find a
particular section of code and then overwrites the blocks with the
same name, in your current file, with the one found in this external
file.
include is like "go find this file and render it with my page here".
use is "parse this other file to find block definitions to use instead
of my owns defined here".
If use command finds nothing matching the task, nothing is displayed
at all from this file.
Question
is the explanation correct? are there any other explanations to this difference?
After months, I am posting an answer for any further reference to this question. I also added some description for extends & import & macro & embed for more clearance:
There are various types of inheritance and code reuse in Twig:
Include
Main Goal: Code Reuse
Use Case: Using header.html.twig & footer.html.twig inside base.html.twig.
header.html.twig
<nav>
<div>Homepage</div>
<div>About</div>
</nav>
footer.html.twig
<footer>
<div>Copyright</div>
</footer>
base.html.twig
{% include 'header.html.twig' %}
<main>{% block main %}{% endblock %}</main>
{% include 'footer.html.twig' %}
Extends
Main Goal: Vertical Reuse
Use Case: Extending base.html.twig inside homepage.html.twig & about.html.twig.
base.html.twig
{% include 'header.html.twig' %}
<main>{% block main %}{% endblock %}</main>
{% include 'footer.html.twig' %}
homepage.html.twig
{% extends 'base.html.twig' %}
{% block main %}
<p>Homepage</p>
{% endblock %}
about.html.twig
{% extends 'base.html.twig' %}
{% block main %}
<p>About page</p>
{% endblock %}
Use
Main Goal: Horizontal Reuse
Use Case: sidebar.html.twig in single.product.html.twig & single.service.html.twig.
sidebar.html.twig
{% block sidebar %}<aside>This is sidebar</aside>{% endblock %}
single.product.html.twig
{% extends 'product.layout.html.twig' %}
{% use 'sidebar.html.twig' %}
{% block main %}<main>Product page</main>{% endblock %}
single.service.html.twig
{% extends 'service.layout.html.twig' %}
{% use 'sidebar.html.twig' %}
{% block main %}<main>Service page</main>{% endblock %}
Notes:
It's like macros, but for blocks.
The use tag only imports a template if it does not extend another template, if it does not define macros, and if the body is empty.
Macro
Main Goal: Reusable Markup with Variables
Use Case: A function which gets some variables and outputs some markup.
form.html.twig
{% macro input(name, value, type) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" }}" />
{% endmacro %}
profile.service.html.twig
{% import "form.html.twig" as form %}
<form action="/login" method="post">
<div>{{ form.input('username') }}</div>
<div>{{ form.input('password') }}</div>
<div>{{ form.input('submit', 'Submit', 'submit') }}</div>
</form>
Embed
Main Goal: Block Overriding
Use Case: Embedding pagination.html.twig in product.table.html.twig & service.table.html.twig.
pagination.html.twig
<div id="pagination">
<div>{% block first %}{% endblock %}</div>
{% for i in (min + 1)..(max - 1) %}
<div>{{ i }}</div>
{% endfor %}
<div>{% block last %}{% endblock %}</div>
</div>
product.table.html.twig
{% set min, max = 1, products.itemPerPage %}
{% embed 'pagination.html.twig' %}
{% block first %}First Product Page{% endblock %}
{% block last %}Last Product Page{% endblock %}
{% endembed %}
service.table.html.twig
{% set min, max = 1, services.itemPerPage %}
{% embed 'pagination.html.twig' %}
{% block first %}First Service Page{% endblock %}
{% block last %}Last Service Page{% endblock %}
{% endembed %}
Please note that embedded file (pagination.html.twig) has access to the current context (min, max variables).
Also you may pass extra variables to the embedded file:
pagination.html.twig
<p>{{ count }} items</p>
<div>
<div>{% block first %}{% endblock %}</div>
{% for i in (min + 1)..(max - 1) %}
<div>{{ i }}</div>
{% endfor %}
<div>{% block last %}{% endblock %}</div>
</div>
product.table.html.twig
{% set min, max = 1, products|length %}
{% embed 'pagination.html.twig' with {'count': products|length } %}
{% block first %}First Product Page{% endblock %}
{% block last %}Last Product Page{% endblock %}
{% endembed %}
Note:
It has functionality of both Use & Include together.
Twig performance is spectacular, so chances are you will never care, but be aware that there is a significant difference between using embeds, includes, or macros.
I set up a little test project to demonstrate it: https://github.com/janklan/twig-benchmark
The readme has all the information you need if you're interested to know more, but the general result is, that for the same task executed in a loop of 100k iterations, the times between individual methods on my computer were as follows (lower is better)
embed: 4253ms
include: 3428ms
macro: 2695ms
By the way, the project I shared via Github up generates separate cache directories for each approach (embed/include/macro). If you want to see how different methods in Twig map to the compiled PHP, I recommend you check it out. If you wish to see the cache without having to run the project, check out a branch called with-cache

twig: appending to parent template region from multiple includes

general.tpl:
<head>
<!-- some default meta tags -->
</head>
<body>
{% block mainArea %}{% endblock %}
{% block sidebar %}{% endblock %}
<!-- standard footer -->
<script src="base.js"></script>
{% block js %}{% endblock %}
</body>
page1.tpl:
{% extends "base.tpl" %}
{% block mainArea %}
some content
{% endblock %}
{% block sidebar %}
...
{% include 'one-of-many-widgets.tpl' %}
...
{% endblock %}
one-of-many-widgets.tpl
requires specific javascript library that must be referenced before <body> tag and needs to emit specific in-line javascript before that library but after referencing base.js
requres specific meta tags to be added to page head block
requires to append additional legal information to page footer
Q1: How to do that by putting additional script and meta info into one-of-many-widgets.tpl file? Given that there is several included widgets that all contribute to scripts area of page.
Q2: there is also page2.tpl, that also need it's own additional js and extended meta tags, in addition to emitted by includes. Is it possible to combine them but not overwrite?
one-of-many-widgets-1.tpl:
{% block jsPreBodyAdditions %}
{{ alreadyCollected() }} widget script tag or inline js to APPEND
{% endblock %}
{% block metaTags %}
{{ alreadyCollected() }} widget additional semantic meta tags to APPEND
{% endblock %}
one-of-many-widgets-2.tpl:
{% block jsPreBodyAdditions %}
{{ alreadyCollected() }} widget script tag or inline js to APPEND
{% endblock %}
{% block metaTags %}
{{ alreadyCollected() }} widget additional semantic meta tags to APPEND
{% endblock %}
page2.tpl:
{% block jsPreBodyAdditions %}
{{ alreadyCollected() }} page2 script tag or inline js to APPEND
{% endblock %}
{% block metaTags %}
{{ alreadyCollected() }} page2 additional semantic meta tags to APPEND
{% endblock %}

Create event in symfony2 to render a twig file

I'm new to symfony2 and I'm looking for solution to create an event that render a twig file.
Assume we have a base template
<!DOCTYPE html>
<html>
<head>
{% block meta %}{% endblock %}
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body data-cachetime="{{ cacheTimeStamp() }}">
{% block header %}{% endblock %}
<div id="content">
<div class="container">
{% block content %}{% endblock %}
</div>
</div>
{% block footer %}{% endblock %}
{% block version %}{% endblock %}
{% block javascripts %}{% endblock %}
{% block trackers %}{% endblock %}
</body>
</html>
As you can see, I've a "version" block. I've created an VersionBundle which read the version from a file. The version twig template
{% block version %}
<div id="version"><p>Version: {{ versionString() }}</p></div>
{% endblock %}
calls an "ViewHelper" (i came from Zend ;-)) which calls the function from VersionBundle. But now the tricky part:
The VerionBundle is only registered for 'dev' and 'test' Environment in the AppKernel.
Thats why i create the 'version' block instead of calling the ViewHelper directly in the base twig file.
But i don't know how to create an event to render the version twig template first so the data will passed to the base twig.
I would maybe change the way you try to do it, using more Symfony features and avoiding defining Zend like "helpers". It's a good rule of thumb to keep Twig as minimal as it can be, just rendering view from data the templates receive.
First, define the version variable in parameters_dev.yml and parameters_test.yml files (in app/config). Example:
parameters:
version: 32
Define it as version: ~ in parameters.yml.
Make this variable available in all Twig templates in the app/config/config.yml file:
twig:
globals:
version: %version%
Then, in your version block definition, do the following:
{% block version %}
{% if version is not null %}
<div id="version"><p>Version: {{ version }}</p></div>
{% endif %}
{% endblock %}
Hope it helps!

Twig included template extending parent's block once

Is there a way to do this? I have a template which outputs one blog article.
Now, on index page I show 10 articles by including that template in for loop and on show page I only show one.
index:
{% block stylesheets %}
{# some stylesheets here #}
{% endblock %}
{% for article in articles %}
{% include VendorBundle:article.html.twig with { 'article': article } %}
{% endfor %}
show:
{% block stylesheets %}
{# some stylesheets here #}
{% endblock %}
{% include VendorBundle:article.html.twig with { 'article': article } %}
Now is there a way to make article.html.twig add something to {% block stylesheets %} of templates that included it automatically? If it is possible, how do I prevent it from adding that 10 times when using for loop?
I'm trying to make my "fragment" templates (templates used for inclusion) define stylesheets that they use and make them "inject" those into page.
Did you try to use use?
Unfortunately I'm not completely sure if I got the question right but {% use %}wasn't mentioned here.
As I understand the question you've got your article.html.twig and include it in e.g. index.html.twig. Now you want to add something from article.html.twig into index.html.twig? Namely to the {% stylesheets %} block.
If I got how to use {% use %} you could maybe try it like this.
article.html.twig
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('bundles/mybundle/css/article.css') }}" type="text/css" />
{% endblock %}
{% block article %}
{# whatever you do here #}
{% endblock %}
index.html.twig
{% use "VendorBundle:article.html.twig" with stylesheets as article_styles %}
{% block stylesheets %}
{{ block('article_styles') }}
{# other styles here #}
{% endblock %}
{% for article in articles %}
{% include VendorBundle:article.html.twig with { 'article': article } %}
{% endfor %}
I have not the chance to test it but the docu states a few very interesting things and it seems like this could be the way to do it.
Horizontal reuse is an advanced Twig feature that is hardly ever needed in regular templates. It is mainly used by projects that need to make template blocks reusable without using inheritance.
I am rather new to stackoverflow. So please if my answer is completely useless could you just post a comment before down voting and I delete it?
However if it does help and there are just some errors in my example, also inform me and I'll fix it.
You can use a new block (not tested):
{# index.html.twig #}
{% block stylesheets -%}
{% block article_styles '' %}
{%- endblock %}
{% for ... -%}
{% include VendorBundle:template.html.twig with {'article': article} %}
{%- endfor %}
{# template.html.twig #}
{% block article_styles -%}
{{ parent() }}
<link rel=stylesheet href=...>
{%- endblock %}
{# ... #}
Edit: Added {{ parent() }}, this will print every content the block already has.

Categories