Twig include performance with and without passing variables - php

I am wondering what is best perfomance-wise, using
{% include "_inc/template" %}
or
{% include "_inc/template" with {'foo': bar %}
assuming foo is the only variable used in _inc/template and it's also available in global context.
Will there be significant difference in performance between two approaches, if the include is placed within for having ~50 loops?

I don't have direct answer to your question, but you can use the profiler in dev toolbar to see the timeline of the calls.
Maybe try and tell us...
Which is the version of symfony you use?
I know that in symfony > 2.7 the timeline Graph exist.
Ps : Maybe try it with this too:
{% include 'template.html' with {'foo': 'bar'} only %}

Related

Use a string variable inside an if condition in twig

I have a problem in twig which is below :
I want to use a variable which is a string which is a condition ( that i read from a table from a yml file) inside and if statement consider this example.
{% set condition = 'a condition' %}
{% if condition == true ]%
do something
{% endif %}
Notice : the string used as a variable contains a twig code
How is it possible to do that ??
is there any similar to eval() of php in twig ?
thanx in advance
You can use some tricky hack with is_granted function. It's created to be used for security purposes but it will work for your use case.
is_granted can evaluate Symfony Expressions, then result can be used in conditional statements.
This example works fine for your case:
{% set condition = "true" %}
{% if is_granted(expression(condition)) %}
CONDITION IS TRUTHY
{% endif %}
To make it work you need to install symfony-expressions and security components:
composer require symfony/expression-language
composer require security
Also if you don't use it for granting access for users to some places in your template it would be better to create own twig function that will execute Symfony Expressions like is_granted do.

A NULL check in Twig Template is not working which leads to an error (very strange behavior)

I’m currently facing a very strange problem in a Twig template (Symfony v2.8.9; Twig v1.24.1). The basic outline is: I’m trying to overwrite a block in a child template when a specific condition is met.
Here’s a snippet of my template:
{% extends "#App/search/resultList.html.twig" %}
{% if category.teaser %}
{% block description %}{{category.teaser.doSomething()}}{% endblock %}
{% endif %}
This code leads to the following error:
Impossible to invoke a method ("doSomething") on a null variable in #App/search/categoryResult.html.twig
The teaser property of the category indeed is null, which is okay and what the check is for.
I also tried an explicit {% if category.teaser is not null %} which also didn’t work and resulted in the same error.
Now for the really weird part (or maybe I’m just not seeing it why this wouldn’t be weird):
If I change the code to
{% block description %}
{% if category.teaser %}
{{category.teaser.doSomething()}}
{% endif %}
{% endblock %}
it works as intended (mostly, at least, because the parent block will always be overwritten).
This error seems to happen only in the Symfony dev environment.
It seems:
# Twig Configuration
twig:
debug: true
strict_variables: true
has something to do with it, which explains the dev environment only. If both values are set to false it works correctly.
Has anybody ever encountered a problem like this and solved it? Any help in solving this issue would be much appreciated.
As far as I know, it is not possible to conditionally override a block in twig, see also How can I conditionally override a TWIG layout block?
You have done the best practice by testing whether the variable is null or not.
In many other languages you can’t do something on a null. You can use the dump() function to check your variables.

Symfony2 - Include template from current bundle

I've not been able to find anything useful about this in the Twig or Symfony2 documentation, so thought I would ask here.
Does anybody know if it's possible to include a Twig template in Symfony2 relative to the current bundle, without specifying the name? Something along these lines:
{% include .:Foo:bar.html.twig %}
I'm just a bit fed up of having to enter the long, ugly bundle name when they're all in the same bundle. Also means if the bundle name ever changed for whatever reason, I'd have to find & replace every single include.
Back in the days when I was using bundles, I came up with a quick solution that you could base upon:
{% set bundle = app.request.get('_template').get('bundle') %}
{% set controller = app.request.get('_template').get('controller') %}
{% include bundle ~ ':' ~ controller ~ ':foo.html.twig' %}

Symfony2 Twig Inject additional blocks

Is there a way with Symfony2 and Twig to always make files available which just contain blocks.
For example, if I wanted to make a block named 'cookie' always available in any template in my system, without having to always include or extend it in the template I'm using.
Any ideas?
Clarification
Say I have a generic block which can do something, like:
{% block myBlock %}
ABC Examples
{% endblock %}
I have a class which knows it wants to be rendered with this block. My template itself doesn't necessarily know this though.
{{ block(myObj.blockName) }}
I would then like to have it so my controller/services/etc. could register the file which contains that block, without my template actually needing to know about it directly (so I could have multiple files like that, each working with some common interface).
Similar to registering custom Twig functions with a TwigExtension. My template doesn't need to explicitly know it's there, it just has to be available at run-time.
Does that make sense?
To clarify a bit further, I'm essentially looking to do something just like how there are default Twig blocks for rendering Forms in Symfony2. I don't have to include the default form file every time, just when I want to change something.
I went digging around in the Symfony source code to try and find my answer. It looks like there isn't some fancy, neat way to embed it from a configuration file or controller directly, which is a bit disappointing, but not a huge deal.
So, to solve my situation, I'll be using the "use" keyword to include my block file in my base template, so it will then be available to everything else.
{# widget_blocks.html.twig #}
{# Widgets #}
{% block my_widget %}
ABC Cookies
{% endblock %}
{# base.html.twig #}
{% use widget_blocks.html.twig %}
{{ block(my_widget.block) }}
Not exactly what I wanted, but sufficiently close.
{% render 'MyMainBundle:Default:credits' with {'arg1': $myObj } %}
Thats what I say. What's the difference between the line above or
{{ block(myObj.blockName) }}
You can register a custom filter but as far as I know it returns only string value. http://twig.sensiolabs.org/doc/advanced.html#id2

How to pass an array from Symfony 2 controller to a TWIG template ?

I can`t pass an array from a symfony 2 controller to a TWIG template. I use this code in the controller:
$searchTerms['color'] = "Red";
return $this->render('TestBundle::search.html.twig',
array(
"searchTerms" => $searchTerms));
In the twig template, I am trying to access the variable like this:
{{ searchTerms['color'] }}
{{ searchTerms.color }}
Both output nothing, empty string, so it seems like array comes to template but its elements are empty.
What`s wrong?
Yes, this code works. The first thing to check is that your twig code is in the correct page (TestBundle::search.html.twig). This might sound silly but that happens sometimes...
If this is all good, I suggest that you try to debug within your template. Debugging is the most important thing. You will always have this kind of problem while programming, especially when you try something new. The better you are at debugging your code, the better you are as a programmer because there is no way you can get everything right the first time.
So, how can you debug?
To debug within your twig template, you can use the debug extension of twig. To activate the debug option, you will have to do a quick change in your config file. You can also read this thread if your lost.
You can debug any variable within your template like this:
<pre>
{% debug searchTerms %}
</pre>
This way, you can easily debug your variable and test what your problem is:
{% debug searchTerms['color'] %}
If you want to debug things quickly, I highly recommend that you use the LadyBugBundle. It is an awesome tool that will allow you to do something like that:
In your controller:
ladybug_dump($searchTerms);
In your TWIG template:
{{ searchTerms|ladybug_dump }}
Not that different from a classic var_dump option, but if you have long arrays or objects, ladybug will impress you. More importantly, in a controller, you will often have the need to stop the code at a certain point to avoid the page to load after your debug statement, this is fairly easy with ladybug:
ladybug_dump_die($searchTerms);
You can even ask ladybug to load the "debugged" variable into Symfony profiler with this simple statement.
$this->get('ladybug')->log($searchTerms);
You have now direct access of the variable from a tab of the Symfony2 profiler.
Ladybug can do a lot more, but for this, the doc is really good.
I think you must change template like this:
{% for item in searchTerms %}
{{ item.color }}<br/>
{% endfor %}
See official documentation: Creating and using Templates->embedding-controllers

Categories