Dynamic variable in Twig, example? - twig

I don't quite understand how the attribute function in Twig works. Can somebody help me with an example?
I have a field in a SQL that is named dynamic. I could be eg "field27", but I don't know the number, the number is saved in radio.id. I would like to do someting like this:
{% for radio in gruppeType.radios %}
<td><!-- value of "field" + radio.id--></td>
{% endfor %}
How can I use field + radio.id as the name of the twig-variable?

You can build the field name with a variable, then use it in the attribute function to access the data within the object/array. As example:
{% set fieldName = "field" ~ radio.id %}
{{ attribute(gruppeType, fieldName) }}
A working example can be seen in this twigfiddle
Hope this helps.

Related

Convert string into node path

So i am working on a Shopware shop, and i want to read a MediaEntity in Twig. To do so, i am creating a string with the node path (adding the product ID as a variable), which just works fine.
To actually access the MediaEntity, i need to convert this string into a real node path. How do i do that? Or is there maybe another way to create this path?
Here's my code:
{% block component_product_box %}
{{ parent() }}
{% set coverIds = "context.extensions.#{product.coverId}.elements" %}
{{ dump() }}
{% endblock %}
I tried it roughly and something like this should work:
{% set coverIds = _context['extensions'][product.coverId]['elements'] %}
This should solve your problem, I hope.
If you really need to work with a string and "dots" notation, this could be of help:
How to use Twig's attributed function to access nested object properties

Problem creating JSON outuput in Twig Template

I'm learning to use the Craft CMS, which uses Twig templating. I'm trying to output a JSON object in Twig, but instead of 2 items in the JSON I'm getting info about a single item.
Here is my code:
{% set newsitems = craft.entries.section('newsitems').orderBy('PostDate desc').limit(100) %}
{% set response = [] %}
{% for newsitem in newsitems %}
{{ 'Here' }}
{% set response = response|merge({'type':0, 'id':newsitem.id, 'link':newsitem.sourceLink}) %}
{% endfor %}
{{ response|json_encode() }}
And here is the output I get:
Here Here {"type":0,"id":"25","link":"https:\/\/gadgets.ndtv.com"}
As can be seen, the loop executes two times ('Here' is printed 2 times) but there is only one item in the JSON array which is printed.
Am I missing something basic? Any help would be appreciated. Thanks in advance.
Twig's merge filter uses array_merge in the background.
The manual states the following
If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.
This is what is happening to your output, in the first iteration you've create an associative array with the key: type, id, link. In the x'th iteration you are just overwriting the values stored in said keys. The solution is also stated in the manual, numeric indices will be appended to the array instead of overwriting it.
In twig you would solve it as this:
{% set response = [] %}
{% for newsitem in newsitems %}
{% set response = response|merge([{ 'type': 0, 'id': newsitem.id, 'source': newsitem.source,},]) %}
{% endfor %}
{{ response|json_encode|raw }}
demo

Variables concatenation

After about an year of using Smarty i wanted to try Twig.
I am facing a problem concatenating a string and a variable to build dynamically the titles of the page when i switch the language.
In Smarty, the controller passes to the template the variables:
$title_it and $title_en
For the title of the page i do <title>{$title_{$lang}}</title> (where $lang is a global variable) and i can switch the values of the variables when i change the language.
I am not able to replicate this behaviour in Twig.
I tried the following methods without having success:
{{ title_ ~ {{ lang }} }} (I think Twig sees the variable "title_" doesn't exists.
'title_'~{{ lang }} (This prints 'title_it' and not it's content)
Is there a way to keep this logic and continuing to use this approach or do i have to handle the titles of the pages differenly?
Thanks a lot,
Manuel
The _context variable holds all variables in the current context, so you can do:
{{ _context['title_' ~ lang]|default }}
This is basically the same as using the attribute function:
{{ attribute(_context, 'title_' ~ lang)|default }}
I would personally use the former as it's more concise and in my opinion clearer.
The default filter is needed when the environment option strict_variables is set to true (the default value is false, but I prefer to set it to true to avoid accidental problems caused by e.g. typos), otherwise you'll get a Twig_Error_Runtime exception if the variable doesn't exist. For example, if you have variables title_en and title_it but try to output the variable title_de (which doesn't exist), you get that exception with the message Key "title_de" for array with keys "title_en, title_it, lang" does not exist.
A more verbose way to check the existence of a variable is to use the defined test:
{% if _context['title_' ~ lang] is defined %} ... {% endif %}
With the default filter you can also provide a default value:
{{ _context['title_' ~ lang]|default('Default title') }}
If you omit the default value (i.e. you do |default instead of |default('some value')), the default value will be an empty string.
See TwigFiddle
I think here the solutions which can fix your problems.
Controller code:
return $this->render('myTwig.html.twig', array(
'lang'=>'en',
'title_en'=>'English Title',
'title_it'=>'Italian Title'
));
Twig Code:
{% set myVar='title_'~lang %}
{{ attribute(_context, myVar) }}
This will display "English Title" on your page.
Here _context variable is a magic variable in twig where you can find all parameters which you passed from your controller to this twig.
attribute(_context,myVar)
it displays the value from passed parameters key to value.
Hope this will solve your problems.
Thanks
I would change the controller to pre-calculate the language dependent value for title before passing it to the twig template. If you are unable (unwilling) to do that, then ...
<title>{% if lang == 'it' %}{{ title_it }}{% else %}{{ title_en }}{% endif %}</title>

Twig translate dynamic value/string from database

Explanation:
I pull these values from my local database and try to display them on the front-end. The issue is, that I have 2 languages that I need to cater to.
Example:
{% if activeLocale == "si" %}
{{ record.estate_type_SI|raw }}
{% elseif activeLocale == "en" %}
{{ record.estate_type_EN|raw }}
{% endif %}
This works, but when I have multiple items it gets gruesome because I have to write everything down two times. What this does is that depending on the language a value from a different column in the database is pulled.
I am wondering if I can do something similar to this:
{{ record.estate_type_{{"SI"|trans}}|raw }}
I will gladly buy you a beer if you can help me out with this.
Cheers!
EDIT: Variables
Using attribute , you can access a property of an object in a dynamic way. Then you just have to use upper filter to match what you need.
{{ attribute(record, 'estate_type_'~ activeLocale|upper)|raw }}

Twig Access Array Index?

Is it possible to directly access an array index from within a Twig template?
Here's my setup, using Silex:
return $app['twig']->render('template', array('numbers' => array('one', 'two', 'three')));
so can I do something like this?
{{numbers[0]}}
Just before posting this I realized, that's exactly what you can do, but as I didn't find the answer anywhere in the docs or google (correct me if I'm wrong), I've posted this anyway.
{{numbers[0]}}
The answer of Adam, is correct, only to make it clear and improve,
you can have access directly to array index
{{ myArray[0] }}
if you need to access in a loop
{% set arrayOfItems = ['ZERO', 'ONE'] %}
{% set myArray = ['APPLE', 'ORANGE'] %}
{% for oneItem in arrayOfItems %}
<p>{{ oneItem }} equals {{ myArray[loop.index0] }}</p>
{% endfor %}
in this example I used an array inside a non related loop so the result is:
ZERO equals APPLE
ONE equals ORANGE
Thats actually something what doesnt work for me when using Twig with shopware 6.
I try to access an object like
{{ page.cart.lineItems.elements[0].quantity }}
what will lead into a parsing error of the Twig Template
I can use
{{ page.cart.lineItems.elements | first }}
to get the first Element, but dont know how i can then access a property of this first element

Resources