Execute statement inside conditional - twig

Is it possible to call an executable function inside a Twig conditional statement?
I have a path function and want to output the path if the name variable is empty. Right now I have these two options:
{% path file, 'reference' %} // calling path function
{{ file.name ?: file.path }} // Conditional
But I would like something like:
{% file.name ?: path file, 'reference' %}

Looks like path is a tag instead of a function. If it was a function, you'd use it like this:
{% path(file, 'reference') %}
In comparison, Twig has a function dump, and in Symfony you can use a tag with the same name. Here's how you'd use them:
{{ dump(foo) }} {# function #}
{% dump foo %} {# tag #}
You see the difference?
If path was a function, both of these would probably be possible:
{{ file.name ?: path(file, 'reference') }}
{% do file.name ?: path(file, 'reference') %}
Both are the same, except the second one doesn't print anything.
Because path seems to be a tag, I don't think it's possible to do what you asked. (It's also possible that it's both a tag and a function. If that's the case, use the function instead of the tag.)
Edit: Are you using Symfony? There's a Twig function path in Symfony, but I don't think there's a Twig tag path. Are you sure your code ({% path file, 'reference' %}) is correct?

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

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>

"Illegal offset type in isset or empty" when using a Twig macro

Using Grav v1.3.8 (running on PHP 5.6.30), I'm currently getting a Server error ("Illegal offset type in isset or empty") when trying to render a Twig template that is using a macro.
What's interesting is that this only happens when I use the macro by itself. As soon as I append a filter, like trim, everything works as expected.
The (shortened) macro file, helpers.twig:
{% macro ascii(str) %}
{% spaceless %}
{{ str|replace({
'Á': 'A',
'À': 'A',
'Â': 'A',
'Ã': 'A',
....
'ƒ': 'f'
})
}}
{% endspaceless %}
{% endmacro ascii %}
The template (MCVE):
{% import 'macros/helpers.twig' as helpers %}
{% set img = helpers.ascii('günter-berger.jpg') %}
{% if page.media[img] is defined %}
<img src="{{ page.media[img].url }}">
{% endif %}
This will produce the error. I narrowed it down to the if line. Apparently, the macro is working fine, but the condition will throw an error if fed the output of it, unfiltered. Adding any filter, like trim or lower, will get it to work again.
In other words, these work:
{% if page.media['günter-berger.jpg'] is defined %}
{% if page.media[helpers.ascii('günter-berger.jpg')|trim] is defined %}
But this will throw an error:
{% if page.media[helpers.ascii('günter-berger.jpg')] is defined %}
However, trying the same thing on twigfiddle, all three seem to work there.
Maybe an issue with Grav? Can someone point out any possible causes?
I forgot this, but a macro does not return a string but instead returns an instance of a Twig_Markup
{% set test = macro.ascii('Ghünter.jpg') %}
{{ dump(test) }}
Output : object(Twig_Markup)#10679 (2) { ["content":protected]=> string(11) "Ghunter.jpg" ["charset":protected]=> string(5) "UTF-8" }
Because the return type is an object you get this notification as you can't use objects as index. By using a filter on this instance, the magic method __toString method will be called, causing it to return a string, thus making it useable as index for an array
The only was to bypass this, would be writing a filter instead of a macro

Dynamic variable in Twig, example?

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.

get the full path with statement in twig ( sonatamediabundle)

How do I get the fullpath for sonatamediabundle??
I can get the full path normally
{{ app.request.schemeAndHttpHost() ~ path('path_name') }}
howevere sonatamediabundle is like this
{% path pic.getMedia, 'big' %}
Is it possible to get the fullpath with the statement???

Resources