Does Twig allow assignments in conditions and how? - twig

As per title, does Twig allow assignments in conditional and how? I know that not all people like these assignments but sometimes they can be very helpful.
This:
{% if (name = attribute(mappings, property)) is defined %}
{% else %}
{% set attrs = attrs|merge(['%s="%s"'|format(name, value)]) %}
{% endif %}
...is not working and gives me and error:
An opened parenthesis is not properly closed. Unexpected token
"operator" of value "=" ("punctuation" expected with value ")") in
::tooltips.html.twig at line 29.

Your twig error is because of this line
{% if (name = attribute(mappings, property)) is defined %}
Twig doesn't like assignment-in-condition expressions, and personally neither do I, it's just a lazy shortcut and the potential issues isn't worth saving a few keystrokes.
But I have to now admit that I'm confused by what this is supposed to do. You're attempting to capture the result of attribute(mappings, property) into name but if that fails, only then do you do something using name, but by then name won't have a value unless it's been defined elsewhere in the template.

Related

OctoberCMS, comparing a record string to a string

I'm attempting to clean up my Titles in my October CMS Project and I'm running into an issue.
I have a set of pages set to be "Singles" and thus have the title [category]-single which is not great.
So to that end I'm trying to use the [x] in [y] function in twig for an if function as follows;
{% else if ('single' in this.page.baseFileName) %}
<title>[formatted title]</title>
{% else %}
this doesn't help and throws an "Unexpected token "name" of value "if" ("end of statement block" expected)." exception.
No variation I can think of (bracketing out the record pointer, for example) and I'm reaching an impasse on this.
Any help?
it seems you are adding extraspace to else if just remove it and use elseif
{% elseif ('single' in this.page.baseFileName) %}
{# ^ use like this #}
<title>[formatted title]</title>
{% else %}
docs : https://twig.symfony.com/doc/2.x/tags/if.html
if any doubt please comment.

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.

How to write that path in string to be parsed - Twig

I set links in this way in twig:
{% set link = '('~product.price~)'~product.name~'' %}
The problem is how to fill the link
{% set link = '('~product.price~)'~product.name~'' %}
This gives me the error: A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "punctuation" of value "{"
{% set link = '('~product.price~)'~product.name~'' %}
Unexpected token "name" of value "restaurant" ("end of statement block" expected)
can you please help me :(
The link will also have an id argument.
The only thing I can think of is writing a filter which takes te id as argument and replaces the empty link, but I'm not quite sure it will work, and it doesn't seem like a good solution.
You should not use parentheses within {% %} blocks.
Furthermore, unless you have a specific reason for putting the whole markup for the link in a variable, you might want to consider creating links like this:
{{ product.name }}

Resources