Import content between Twig files - php

How can I have a Twig file which imports some of it's content from a second Twig file in the same or a sub directory?
I am developing a project where multiple Twig files have content in common and I'm trying to avoid copying and pasting content between Twig files.
So, I want to have a subdirectory containing the shared markup and simply "import" into the relevant sections of the main Twig files.
With import.list.html.twig in the same directory as the main Twig file, I tried the following:
{% extends "::base.html.twig" %}
{% block title %}StockBundle:StockController:index{% endblock %}
{% block body %}
<h1>Welcome to the StockController:List page</h1>
{% for stock in stocks %}
<div class='list'>
<div class='each stock'>
<span class='name'>{{ stock.name }}</span>
<span class='desc'>{{ stock.description }}</span>
<span class='balc'>{{ stock.balance }}</span>
<span class='edit'>
edit
</span>
</div>
</div>
{% endfor %}
{% include 'import.list.html.twig' %}
{% endblock %}
... but I got the following error:
Unable to find template "import.list.html.twig" in ::base.html.twig at line 10.

When you include it needs to know the namespace of where it is located. When you do ::, as in {% extends "::base.html.twig" %}, it comes from the app/Resources/views directory of your application.
See: Template Naming and Locations Symfony documentation
If your import.list.html.twig is in a bundle, you'll have to define that properly. For instance, if you have StockBundle and a Resources/views directory in that bundle with its own base.html.twig template, you would have
{% include 'StockBundle::base.html.twig' %}
If you had, say, a Stock folder inside that bundle (attached to your StockController) and an import.list.html.twig template, you would have
{% include 'StockBundle:Stock:import.list.html.twig' %}
Note via Registered Namespaced Twig Paths that you can also use a namespaced path instead. They're actually faster as well. So the above would instead be
{% include '#Stock/base.html.twig' %}
{% include '#Stock/Stock/import.list.html.twig' %}
Here's another good reference for Symfony template best practices
NOTE
Since Symfony 2.2, you can use the include() function, and this is the preferred way to include templates:
{{ include('#Stock/base.html.twig') }}
{{ include('#Stock/Stock/import.list.html.twig') }}

Try this:
{% include 'StockBundle:Stock:import.list.html.twig' %}
instead of:
{% include 'import.list.html.twig' %}
http://symfony.com/doc/current/book/templating.html#including-templates

Related

Render a block of a "parent" template from a "child" template in Twig

I have two templates:
Fields.html.twig, which includes a child template.
{% block important %}
This block should be renderable from the sub template
{% endblock important %}
{% include 'XButton.html.twig' %}
XButton.html.twig, which needs to render blocks defined in the template that includes it.
block('important')
It seems like an included template isn't able to simply render blocks of whoever included it.
How can the parent template pass the full context to the child, so that the child can access the blocks defined in the parent?
What you're trying to do it's impossible, because the included template has no way to know about blocks defined in other templates...
You'll need to structure your code a bit differently, so that the contents of the block are defined in the parent somehow - you have at least a couple of options:
Using set and include: https://twigfiddle.com/l536np
Fields.html.twig
{% set important %}
You define the child content as a variable in the parent...
{% endset %}
{% include 'XButton.html.twig' %}
XButton.html.twig
{{ important }}
Using embed: https://twigfiddle.com/y9pp6p
Fields.html.twig
{% embed 'XButton.html.twig' %}
{% block important %}
You define the block content in the parent...
{% endblock %}
{% endembed %}
XButton.html.twig
{{ block('important') }}
You can do it with include by passing the parent template name
{% block important %}
This block should be renderable from the sub template
{% endblock important %}
{% include 'XButton.html.twig' with {'parent': _self} %}
And then use it in the include template
{{ block('important', parent) }}
Although this way the content of the block will be rendered twice - once when you define it in the parent, and once again in the child - see https://twigfiddle.com/6t0l6p

How can I pass variable from parent template to child template in Twig?

I'm working with Symfony and Twig and I can't find solution for the next problem:
in my parent template (index.html.twig) I have such code:
<noscript>
{% block noscript %}
<div class="alert alert-warning">
<strong>{% block notice %}{{ notice_js_disabled }}{% endblock %} </strong>
{% block message %}{{ js_disabled }}{% endblock %}
</div>
{% endblock %}
</noscript>
I have child template (category.html.twig) which extends index.html.twig template.
Can I pass value of {{ notice_js_disabled }} var from index template to category template?
notice_js_disabled is returned from my Symfony indexAction controller.
UPD:
The solution for my problem I founded, next:
I have made base templae, called main.html.twig, where I'm rendering element from the controller:
{% block header %}
{{ render(controller('StoreBundle:Header:index')) }}
{% endblock %}
Then, on my index.html.twig file, I made next things:
{% extends 'Store/tpl/main.html.twig' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<p class="currentPage" hidden>home</p>
{{ parent() }}
{% endblock %}
I'm not sure is it correct solution, but it's work:)
The only way in Twig you can pass some variable to a child template is by the include tag.
{# template.html will have access to the variables from the current context and the additional ones provided #}
{% include 'template.html' with {'foo': 'bar'} %}
{% set vars = {'foo': 'bar'} %}
{% include 'template.html' with vars %}
However in this way you are not extending some parent template from the child, but you are doing the other way around: you are placing a submodule into the current template.
There are only a couple of variables which are global in symfony
You can set some custom global variables in configuration like described here
Otherwise you can use some predefined global variables, the app variable. (check it out here)
My personal advice is that you should review your application template logic.
Hope it helps!
What you have to do is the following:
-Create A variable in the parent template
{% set notice_js_disabled = value_received_from_indexAction %}
After the template that you need that value
{{ notice_js_disabled }}
I hope it helps you

Symfony2/Twig - how to set template file contents as variable?

In Symfony 2.8 I've got SharedBundle, where I keep views and other things I share between other bundles, including the whole layout that should be extended by other bundles' views.
That shared layout has some typical blocks, from which sidebar block should be different for different bundles.
Currently I did an ugly workaround:
In SharedBundle sidebar container:
{% if sidebarcontent is defined %}
{{ sidebarcontent|raw }}
{% else %}
SIDEBAR NOT FOUND
{% endif %}
And in other bundles (here: BundleA) in every view that extends the shared main view:
{% extends 'SharedBundle:layout.html.twig' %}
{% block sidebar %}
{% include 'BundleA:_partials:sidebar.html.twig' %}
{% endblock %}
{% set sidebarcontent = block('sidebar') %}
But that doesn't look good, I think. Is there a better way?
I think this is a valid approach. The only simplification I can think of is not using the variable sidebarcontent.
You can use block('sidebar') inside the if statement:
{% if block('sidebar')|length > 0 %}
{{ sidebarcontent|raw }}
{% else %}
SIDEBAR NOT FOUND
{% endif %}
Make sure the block exists before checking it's content, so initialise it with an empty string:
{% block sidebar %}{% endblock %}

Twig - rendering some variables(constant)?

I need some variables(constant) in my project:
path_to_root
path_to_images
I would like to make it without php, just Twig, so i create main.twig:
main.twig:
{% set path_to_root = "/some_folder" %}
{% set path_to_images = "/some_images" %}
In second template i extends by main.twig, so
template.twig
{% extends "main.twig" %}
{% block some_block %}
some_text
<img src="{{ path_to_images }}/image.png" />
{% endblock %}
Yes, it works, bu my question:
Is this good way for having main.twig and in child extends with main?
In each file of templates will i must extends with main.twig?
Sorry for my english :(
Not sure about other php files but the images should go in the assets folder which then you can import using
<img src="{{ asset('path/to/folder/image.png') }}" />

Twig block indirect extending and appending

I have splitted my layout and templates to few partials, mostly because of old Symfony1 habits.
file layout.html.twig:
...
<body>
{{ include("ABCBundle:Partials:breadcrumbs.html.twig") }}
{% block body %}{% endblock %}
</body>
...
file breadcrumbs.html.twig
<div class="abc">
{% block breadcrumbs %}
Home
{% endblock %}
</div>
file show.html.twig
{% extends "ABCBundle::layout.html.twig" %}
{% block breadcrumbs %}
{{ parent() }}
abc
{% endblock %}
{% block body %}
(something something)
{% endblock %}
Funny thing is, when I render show.html.twig, I can put data into body block, and everything works fine, but I can't do anything with breadcrumbs block. Whatever I do - write something inside that block or call parent(), nothing happens, only content from breadcrumbs.html.twig is being rendered. There's also no error about calling parent() and any other error related to extending block.
I think you should use {% include "..." %} rather than {{ include("...") }}
According to the twig documentation, the {% include %} tag "includes a template and returns the rendered content of that file into the current namespace" where as the include function "returns the rendered content of a template"
(Meaning the include function just returns the rendered content, where the tag adds the content to the current namespace which would include the blocks you defined)
Found the solution.
It looks like you can't extend block included in layout's include, from template extending this layout:
[partial.html.twig] --- [ layout.html.twig ] --- [ template.html.twig ]
{% block abc %} {% include 'partial.html.twig' %} {% extends layout.html.twig %}
{% block abc%} aaa {%endblock %}
You have to perform a little hack, including adding extra content to layout and replacing original block from partial.html.twig with conditional. More here: Overriding blocks within included Twig templates

Categories