Convert string into node path - twig

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

Related

On Octobercms blog component currentCategorySlug cannot pass through macro [duplicate]

I'm not able to access template variable in TWIG macro.
Here is a simplified example:
{% set myname = "Ligio" %}
{{ _self.pagedurl(1) }}
{% macro pagedurl(page) %}
Hi {{ _self.myname }}! This is Page Num {{ page }}
{% endmacro %}
How can I access the variable myname without passing it to the macro?
You can not.
As stated in the documentation:
As PHP functions, macros don't have access to the current template
variables.
Your only solution is to pass the parameter to the macro:
{% import _self as flow %}
{{ flow.pagedurl(1, "Ligio") }}
{% macro pagedurl(page, myname) %}
Hi {{ myname }}! This is Page Num {{ page }}
{% endmacro %}
IMPORTANT NOTE:
You may have noticed in my example, I call {% import _self as flow %}.
This is something you MUST do:
When you define a macro in the template where you are going to use it,
you might be tempted to call the macro directly via _self.input()
instead of importing it; even if seems to work, this is just a
side-effect of the current implementation and it won't work anymore in
Twig 2.x.
http://twig.sensiolabs.org/doc/tags/macro.html
If you need to pass more than one global variable into the macro, you might find the _context variable useful:
{% macro mymacro(globalvars) %}
Value of the global variable pi is {{ globalvars.pi }}
{% endmacro %}
{% set pi = 3.14159 %}
{{ _self.mymacro(_context) }}
Ref: this or this answer.
You can set a global variable and access it anywhere in the template
$loader = new \Twig_Loader_Filesystem('path/to/templates');
$twig = new \Twig_Environment($loader);
$twig->addGlobal('V_Name', 'V_Value');

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

Set a property value in an existing twig object

I would like to define a twig object that contains two properties :
The first one is a short text
The second one is a large text (so, i need to use {% set %}{% endset %} to keep readability of the template)
I first tried like this :
{% block principal %}
{% set a_form_help = {'help_toggle_label': 'See the big form field tip', 'help_content': ''} %}
{% set a_form_help.help_content %}>
<h1>This is rules for the field</h1>
<p>A looonng text that will be contained in a collapsed block</p>
<p>And several lines of tips for this field</p>
{% endset %}
{% endblock %}
But Twig complains about the use of the dot in the second {% set %} tag (for setting the large text content in the help_content property).
I've found this message (Twig - Why does it not allow us to set object / array values?) and then done this workaround by using a temporary variable:
{% block principal %}
{% set tmp_help_content %}>
<h1>This is rules for the field</h1>
<p>A looonng text that will be contained in a collapsed block</p>
{% endset %}
{% set a_form_help = {'help_toggle_label': 'See the big form field tip', 'help_content': tmp_help_content} %}
{{ dump(a_form_help) }}
{% endblock %}
I've used a a temporary variable since using the merge() filter would give the same result.
Is this workaroud a good practice or is there a better/cleaner way ?
Thanks in advance for any tip|advice ! :-)
There is no clean way to do it in twig.
Is this workaroud a good practice or is there a better/cleaner way ?
It is not a good practice. As twig is a templating language its responsability is only to display data, not to structure it. Your View Object should have been created elsewhere

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

How do you translate array items and join them?

Using twig, how can I translate all items in an array and join them with a slash?
Do I have to use an additional variable or is there a cleverer method?
For the moment, I'm doing something like this:
{% set labels = [] %}
{% for feature in menu_item.features %}
{% set labels = labels|merge([feature|trans([], 'features')]) %}
{% endfor %}
{{ labels | join(' / ')}}
It sucks.
Why not just output the content while you're looping ?
{% for feature in menu_item.features %}
{% if loop.index0 > 0 %}/{% endif %}
{{feature|trans}}
{% endfor %}
Maybe I'm late to the party, but you can now do this easily with the map filter:
{{ menu_item.features|map(feature => feature|trans)|join(' / ') }}
See documentation:
Twig >v1.41: https://twig.symfony.com/doc/1.x/filters/map.html
Twig >v2.10: https://twig.symfony.com/doc/2.x/filters/map.html
Twig v3.x: https://twig.symfony.com/doc/3.x/filters/map.html
Not everything should be done within the "view".
This type of code is probably much better placed within your controller logic and then passed into the view as the merged+joined result. Because in your example all you're doing is compiling a result which can much more easily be done within code.

Resources