Twig the same block in different included files - symfony

I have problem with included files. In my layout.html.twig I have scripts.js at the end body section before {% block script %}{% endblock %}. When file extending layout and use script block, its ok, but when use this block and include file whose use the same block, then is problem. Rendered page has all javascripts, but in different places.
For example:
page.html.twig
...
There is page.html.twig
{% include 'file.html.twig' with {'something': 'something'} %}
After include file.html.twig
..
{% block script %}
<script src="file1.js"></script>
{% endblock %}
file.html.twig
There is file.html.twig
{% block script %}
<script src="file2.js"></script>
{% endblock %}
Then rendered page look like this:
There is page.html.twig
There is file.html.twig
<script src="file2.js"></script>
After include file.html.twig
<script src="file1.js"></script>
I want have all javascript files in one place, one by one.

I think you should try to 'embed' instead of 'include'.
http://twig.sensiolabs.org/doc/tags/embed.html
With embedded, you can choose blocks to include.
Ps : If you override a block, you can get the parent block content in using parent() :
{% block script %}
{{ parent() }}
{% endblock script %}

The {% block %} tag and the inheritance system work only with layouts and {% extends %}. It is not meant to be used with includes, so the script block in your included file.html.twig does not merge with page.html.twig.
One solution would be to set a an argument to you included file.
file.html.twig
{% if get == 'content' %}
There is file.html.twig
{% endif %}
{% if get == 'script' %}
<script src="file2.js"></script>
{% endif %}
page.html.twig
...
There is page.html.twig
{% include 'file.html.twig' with {'something': 'something', 'get': 'content'} %}
After include file.html.twig
..
{% block script %}
<script src="file1.js"></script>
{% include 'file.html.twig' with {'something': 'something', 'get': 'script'} %}
{% endblock %}

You will need to conform to a standard practice when dealing with included templates and inheritance (you can invent your own standard).
Try to compartmentalize your includes, I usually have a directory called 'partials' for includes, and 'fragments' for renders. Each one belonging to a single collection of controller views.
One way I dealt with a similar problem to what you are having was to use a base template which covered the requirements of a specific set of views, each view template would extend it. It may be somewhat wasteful to include the javascripts and stylesheets for the entire collection of views for a specific controller, but it is a) more efficient that including all assets everywhere and, b) I manage the view specific assets under a single base template.
So long as the views have a dependency on that base template the structure wouldn't break.
Think of Twig templates as PHP classes (they compile to classes anyway). A class can inherit from one chain of parents. What you are trying to do is treat two sub-classes as a single child of a super class, overriding the same method at the same time. Simply can't be done. An include is closer to a child property, with is own rules and properties. The included template is less dependent on the includer than vice-versa, so it is impossible for it to inherit from it conventionally.

Related

Assetics ou Gassetics?

I just run on Gassetics, seems to be the next gen of SF assets management. So far I used Assetics.
One question though : with Assetics I used to split files in order to load only needed one, using Twig parent() method :
{% block scripts %}
{{ parent() }}
{% javascripts
'#LCHAdminBundle/Resources/public/js/jquery.specific.addition.js'
%}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock scripts %}
SO I could add on a specific page, only script needed and so was "forced" (in the noble way) to think and split my twig files accordingly.
Is it possible to do so with Gassetics? I jsut saw that you can specify back-end and front-end files, nothing more.
If I nest Twig files with Gassetic tag, will it do the trick?
EDIT : thanks to Wouter J. comment, I adjust my question :
In Assetics you explicitely specify files you want to include, giving the nesting ability. As in Gassetics you just add the tag which will be replaced during CSS/JS file generation, how do you achieve the same?
You can do all of this in the gassetic config (see section yaml example with gassetic.yml in https://github.com/romanschejbal/gassetic).
Example gassetic.yml:
js:
files:
common.js:
- assets/vendor/jquery/jquery.js
- assets/vendor/angular/angular.js
page1.js:
- assets/vendor/lchadminbundle/jquery.specific.addition.js
common.html.twig:
{% block scripts %}
<!-- prod:common.js --><!-- endbuild -->
{% endblock scripts %}
page1.html.twig
{% extends 'common.html.twig' %}
{% block scripts %}
{{ parent() }}
<!-- prod:page1.js --><!-- endbuild -->
{% endblock scripts %}
This approach is better than nesting scripts in children templates, since the commonly needed files can be cached between page requests.

Symfony/Twig: Extending stylesheet block from an extended bundle

I'd like to extend the stylesheets blocks from inside a bundle I've created to extend FOSUserBundle.
This is how to extend from inside the same bundle, but I want to extend from another bundle that extends a third-party bundle.
This is the code:
{# src/MyNamespace/UserBundle/views/layout.html.twig #}
{% extends '::base.html.twig' %}
{% block stylesheets %}
{{ parent() }}
{% stylesheets filter='scssphp,cssrewrite' output='css/app.css'
'bundles/mynamespace/scss/Profile.scss'
%}
{% endstylesheets %}
{% endblock %}
{% block title %}My title{% endblock %}
{% block body %}
{% block fos_user_content %}{% endblock %}
{% endblock %}
So, basically, I've extended the FOSUserBundle creating another bundle in my src directory as explained here.
The code of my `base.html.twig template is this:
{# app/Resources/views/base.html.twig #}
...
<head>
...
<title>{% block title %}{% endblock %}</title>
<meta name="description" content="{% block metaDescription %}{% endblock %}" />
{% include('::_common/Stylesheets.html.twig') %}
...
And this is the included Stylesheets.html.twig:
{% block stylesheets %}
{% stylesheets filter='scssphp,cssrewrite' output='css/app.css'
'bundles/app/css/bootstrap.css'
...
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
{% endblock %}
The problem is that the CSS from src/MyNamespace/UserBundle/views/layout.html.twig is never included in the page, also if it is installed with app/console asstes:install and then dumped with app/console assetic:dump.
The CSS is generated and put in web/css/app_Profile_1.css but is never included in the pages (not in home page or other AppBundle pages, not in MyNamespaceUserBundle pages.
Also adding the line <link rel="stylesheet" href="{{ asset_url }}" /> to the src/MyNamespace/UserBundle/views/layout.html.twig block, the CSS isn't included.
Obviously, if I include the stylesheet directly from _common/Stylesheets.html.twig the file is correctly included.
So, it seems there is something break.
Anyone can help me?
Without the <link rel="stylesheet"> in the {% block stylesheets %} in layout.html.twig, it's not going to output the link for Profile.scss.
More importantly, though, is that {% include %} and {% block %} do not work quite the way you think they do in the presence of {% extends %}. The combination is a little weird, so some background first.
A {% block %} is simply a named wrapper around some content. In the absence of {% extends %}, a block is immediately output where it is defined. (Think of it as if you defined a function, and then immediately called it.)
When you extend another template, however, block definitions in the "global scope" of the extending template replace the definitions of the block in the extended template. This is a re-definition only; the block is still being called at the same place it was in the parent template.
{% include %} renders another template and inserts the results of the evaluation in-line. While it has access to the current context's variables, it is otherwise it's own separate renderer. Importantly, it does not substitute itself with the template code as you are expecting.
So what is happening is this:
layout.html.twig extends base.html.twig. layout.html.twig defines a stylesheets block (but does not emit it). base.html.twig includes Stylesheets.html.twig, so base.html.twig gains the result of evaluating Stylesheets.html.twig (so you get the contents of the {% stylesheets %} tag, but importantly, not the fact that there was even a block there at all.
Then, because there is no place in base.html.twig where there actually is a {% block stylesheets %}, the block defined in layout.html.twig never gets called.
The solution is to move the {% block stylesheets %} into base.html.twig. If you want to keep the actual stylesheet definitions in the Stylesheets.html.twig, then you can do it like this:
{% block stylesheets %}
{% include('::_common/Stylesheets.html.twig') %}
{% endblock %}
And remove the block tag (but not the stylesheet content itself) from Stylesheets.html.twig. That should give you the desired result.

Drupal 8 include part template

I'm trying to use Drupal 8, with an own theme, due big structure differences for my requirements I have a page--front.twig.html and a page.twig.html, I would like to create template parts as used in phrozn oder in a normal Symfony2 project, for example a footer.html.twig and a header.html.twig. These templates are saved under a subdirectory /parts/
But wenn I call this templates as normal I just receive a string with the name of the template.
For example:
{# in page.html.twig or page--front.html.twig #}
{% include 'parts/footer.html.twig' %}
Returns the file name as string:
parts/footer.html.twig
It's possible to do that with Drupal 8?
You can include any part of your template files like this
{% include directory ~ '/parts/footer.html.twig' %}
or this
{% include '#mytheme/parts/footer.html.twig' %}
I strongly recommend you to create a reusable layout for pages that will give you greater flexibility when dealing with more pages and variants.
{# filename: page-layout.html.twig #}
{% block content%}
{{ page.content }}
{% endblock%}
{% block footer%}
{% include '#mytheme/parts/footer.html.twig' %}
{% endblock%}
So you can do something like this in another page
{# filename: page--front.html.twig #}
{% block footer%}
<div> I want to handle a different footer in here</div>
{% endblock%}
Finally, I found really helpful to dig into suggestions array and see what Drupal is trying to use.
Cheers.
it's possible using the name of the template in the path
{% include '#mytheme/parts/footer.html.twig' %}
thanks to https://drupal.stackexchange.com/questions/141066/drupal-8-include-part-template
Now that https://www.drupal.org/node/2291449 has been committed you can also do:
{% include 'footer.html.twig' %}

Twig Form Blocks

I know that i can override checkbox_widget in my form_theme file like that
{% block checkbox_widget %}
my Code
{% endblock checkbox_widget %}
The problem is that I have all files loaded globally so in this way I would override all checkbox_widget in application. But i need to override checkbox in one form.
So the question is How i can override checkbox_widget for one specific form or override specific field widget somehow ?
I tried something like this but it doesn't works:
{% block MyFormName_checkbox_widget %}
my Code
{% endblock MyFormName_checkbox_widget %}
You have to use twig macros instead of blocks. Docs here: macro and import.

Nesting included Twig templates?

I'd like to pass the output of an included Twig template to another included Twig template as a parameter, like so:
{% include 'MyBundle:Default:tpl1.html.twig' with {'item': include 'MyBundle:Default:tpl2.html.twig'} %}
Unfortunately, this does not work as the syntax is invalid.
Any ideas how to nest templates like this / store the output of an included template in a variable?
Or is there an alternative way to accomplish what I want to do? I thought about defining blocks in the included template, but it does not seem to be possible to overwrite them from the "outer" template ...
Try settings the template's content in a variable:
{% set content %}
{% include 'foo' %}
{% endset %}
{% include 'bar' with {'item': content } %}
It should work.

Resources