How can I set a variable with twig? - symfony

I want to set the variable key before using it
"columns": [
{% for key, value in columns %}
{"data": "{{ key }}"},
{% endfor %}
{ "data": "id" }
]
My approach:
"columns": [
{% for key, value in columns %}
{% set result = '{{ key }}' %}
{"data": "{{ result }}"},
{% endfor %}
{ "data": "id" }
]
But it is not working. I get the error message:
Requested unknown parameter '{{ key }}'

{% set result = key %}
From what I see, you want to set the value of result variable, result of key is already set, you just didn't access it correctly.

Related

EasyAdmin: Error on change formTypeOptions property field in twig

I've an User entity and EasyAdmin (EA) UserCrudController for manage to them.
The User entity has active boolean field. And I want that field will be disabled for current user in admin interface.
I got a working solution:
{% extends '#EasyAdmin/crud/index.html.twig' %}
{% block table_body %}
...
{% for field in entity.fields %}
{# disable active field for current uset #}
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
{% if app.user.id == entity.instance.id and field.property == 'active' %}
{% set templatePath = 'admin/crud/field/_boolean_disabled.html.twig' %}
{% else %}
{% set templatePath = field.templatePath %}
{% endif %}
{% endif %}
<td data-label="{{ field.label|e('html_attr') }}" class="{{ field.property == sort_field_name ? 'sorted' }} text-{{ field.textAlign }} {{ field.cssClass }}" dir="{{ ea.i18n.textDirection }}">
{{ include(templatePath, { field: field, entity: entity }, with_context = false) }}
</td>
{% endfor %}
...
with override EA boolean template.
But I wouldn't want to override EA boolean template and only complete field.formTypeOptions by element 'disabled': 'true'
{% for field in entity.fields %}
{# disable active field for current uset #}
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
{% if app.user.id == entity.instance.id and field.property == 'active' %}
{% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
{% endif %}
{% endif %}
<td data-label="{{ field.label|e('html_attr') }}" class="{{ field.property == sort_field_name ? 'sorted' }} text-{{ field.textAlign }} {{ field.cssClass }}" dir="{{ ea.i18n.textDirection }}">
{{ include(field.templatePath, { field: field, entity: entity }, with_context = false) }}
</td>
{% endfor %}
But for this path I get an error: "Uncaught PHP Exception Twig\Error\SyntaxError: "Unexpected token "punctuation" of value "." ("end of statement block" expected)." at /home/vagrant/code/blog.local/templates/admin/crud/user/index.html.twig line 27"
line 27: {% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
When I do:
{% set x = field.formTypeOptions|merge({'disabled': 'true'}) %}
{{ dump(x) }}
array:7 [▼
"required" => false
"row_attr" => array:1 [▶]
"attr" => array:1 [▶]
"label" => "Active"
"label_translation_parameters" => []
"label_attr" => array:1 [▶]
"disabled" => "true"
]
I get the required array, but I get the same error when I try to assign a new value
{% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
What am I doing wrong? Thanks
I think its because the merge function does not like punctuations. Try to set the value to a variable before:
Change:
{% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
To:
{% set options = field.formTypeOptions %}
{% set field.formTypeOptions = options|merge({'disabled': 'true'}) %}
You could already do that in UserCrudController and avoid that logic in Twig:
public function configureFields(string $pageName): iterable
{
// ...
// check user/roles
$isInputDisabled = true;
if($this->isGranted('ROLE_ADMIN')){
$isInputDisabled = false;
}
// ...
$active = BooleanField::new('active', 'Active')
->setFormTypeOption('disabled', $isInputDisabled);
// ...
}

How can I get the data of an object in datatables?

I am getting data from a json file into my datatable.
"columns": [
{% for key, value in columns %}
{
"data": "{{ key }}"},
{% endfor %}
]
Like this I get the following output:
id name slug icon
2 Mitarbeiter members [object Object]
3 Angebote offers [object Object]
4 Produkte products [object Object]
5 Felder fields [object Object]
To recieve the data of the object, I changed my code to this:
"columns": [
{% for key, value in columns %}
{ "data": "{{ key }}.name",
"defaultContent": "{{ key }}"},
{% endfor %}
]
This is working well for the object, but now my other fields do not show the value anymore, the show the label of the column:
id name slug icon
id name slug icon
id name slug anchor
id name slug adjust
id name slug cloud
dump of columns:
array:5 [▼
"id" => ReflectionProperty {#6092 ▶}
"name" => ReflectionProperty {#6094 ▶}
"slug" => ReflectionProperty {#6096 ▶}
"icon" => ReflectionProperty {#6097 ▶}
]
Another approach is this:
"columns": [
{% for key, value in columns %}
{% if key is iterable %}
{"data": "{{ key }}"},
{% else %}
{"data": "{{ key }}.name"},
{% endif %}
{% endfor %}
]
But here I get only the output of the icons row...
The json file is this:
[{"id":2,"name":"Mitarbeiter","icon":{"id":2,"name":"anchor"},"slug":"members"},{"id":3,"name":"Angebote","icon":{"id":1,"name":"adjust"},"slug":"offers"},{"id":4,"name":"Produkte","icon":{"id":1,"name":"adjust"},"slug":"products"},{"id":5,"name":"Felder","icon":{"id":1,"name":"cloud"},"slug":"fields"}]
Finally found a solution:
"columnDefs": [
{
"render": function (data, type, row) {
var type = typeof data;
if(type == "object"){
return data.name;
} else {
return data;
}
},
"targets": "_all"
}
],
"columns": [
{% for key, value in columns %}
{ "data": "{{ key }}"},
{% endfor %}
]
Truy to use: of_type('object')
"columns": [
{% for key, value in columns %}
{
"data": "{% if key is of_type('object') %}{{ key }}.name{% else %}{{ key }}{% endif %}"},
{% endfor %}
{ "data": "id" }
]

How to print dictionary of dictionaries in dot notation with Jinja2 recursive loop?

I have the following example of YAML data structure: (data and structure are subject to change)
settings:
subset1:
sub1: val1
sub2: val2
sub3: val3
subset2: val1
I want to use Jinja to print it as such: (ordering is not important)
subset1.sub2 = val2
subset1.sub3 = val3
subset1.sub1 = val1
subset2 = val1
This is what I have:
{% for key, value in settings.items() recursive %}
{{ key }}{% if value is mapping %}.{{ loop(value.items()) }}{% else %} = {{ value }}
{% endif %}
{% endfor %}
But it gives me this:
subset1.sub2 = val2
sub3 = val3
sub1 = val1
subset2 = val1
Only the first sub element is printed with its respected parent. How can I print all the sub elements with their respected parents properly?
(Again, ordering is not important)
Thanks!
This is how I solved my use case:
from jinja2 import Template
settings = {
'k1': {
'k1': '1.1',
'k2': {
'k1': '1.2.1',
'k2': {
'k1': '1.2.2.1'
},
'k3': {
'k1': {
'k1': '1.2.3.1.1'
},
},
},
},
'k2': {
'k1': '2.1'
},
'k3': '3'
}
template = """
{%- macro treedot(dict,string) %}
{%- for key, value in dict.items() -%}
{%- if value is mapping -%}
{%- if string -%}
{%- set str = string ~ '.' ~ key -%}
{%- else -%}
{%- set str = key -%}
{%- endif -%}
{{ treedot(value,str) }}
{%- else -%}
{%- if string %}
{{ string ~ '.' ~ key }} = {{ value }}
{%- else %}
{{ key }} = {{ value }}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endmacro -%}
{{ treedot(settings,none) }}
"""
tpl = Template(template)
print tpl.render(settings=settings)
The result will be :
k3 = 3
k2.k1 = 2.1
k1.k2.k3.k1.k1 = 1.2.3.1.1
k1.k2.k2.k1 = 1.2.2.1
k1.k2.k1 = 1.2.1
k1.k1 = 1.1
Better than using the keyword "recursive", using a macro allow recursivity too and allow to pass as an argument the path to the value.
Before this I tried with "recursive" keyword too but wasn't able to achieve my needs since variables inside a loop are reset at each iteration.

Twig loop and building hash

i have a problem with twig syntax and merge function ... I have multiple object with 2 field category and price.
I need to create an array or hash (i guess hash is easier but ... i try both) with sum of prices for each category.
So i try many code, and my last is :
{% set test = [ {'category': 'description', 'price': '1'}, { 'category': 'abc', 'price': '2'}, { 'category':'description', 'price': '3'} ] %}
{% set listCategory={} %}
{% for line in test %}
{% set new_category = { 'category': line.category, 'price': line.price } %}
{% if loop.first %}
{% set listCategory = listCategory|merge([new_category]) %}
{% else %}
{% set flag = false %}
{% for category in listCategory %}
{% if line['category'] == new_category['category'] %}
{% set tmp = line['price'] + new_category['price'] %}
{# i try it too#}
{% set category = category|merge([tmp]) %}
{# or i try this#}
{% set category = category|merge({ (category.price) : category.price + new_category.price }) %}
{{ dump(listCategory) }}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
I try it since 3 hours and i don't know where i make an error.
When i check my array, i test if the key 'name' exist
if yes, i want to add the price of element to the hash price
if no, i want to add a new array in hash with key = 'name'
Anyone have an idea ? thx for your reading.
I think you are looking for something similar to:
{% set test = [ {'category': 'description', 'price': 1}, { 'category': 'abc', 'price': 2}, { 'category':'description', 'price': 3} ] %}
{% set listCategory={} %}
{% for line in test %}
{% set key = line.category %}
{% if listCategory[key] is defined %}
{# notice here that the key is in brackets () because otherwise it will be interpreted as the string "key" %}
{% set listCategory = listCategory|merge({(key):listCategory[line.category]+line.price}) %}
{% else %}
{% set listCategory = listCategory|merge({(key):line.price}) %}
{% endif %}
{{ key }}: {{ listCategory[key] }}
{% endfor %}

Set variable in loop

I'm trying to create a json object on twig, so I need to set a variable inside a loop.
After many attempts I found this way, but it's fine when I only have two records, if I have any more you generate the problem:
{% set data = [] %}
{% for artist in artists %}
{% if loop.first %}
{%
set data = {
id : artist.id,
text : artist.name|capitalize() ~' '~ artist.surname|capitalize()
}
%}
{% else %}
{%
set data = [data,{
id : artist.id,
text : artist.name|capitalize() ~' '~ artist.surname|capitalize()
}]
%}
{% endif %}
{% endfor %}
{% set data = {results: data} %}
{{ data|json_encode|raw }}
What I want to achieve is:
{results: [{id: 1, text: "bla"},{id: 2, text: "blabla"},{id: 3, text: "blablabla"}]}
Instead I get:
{results:[[{id:1,text:"bla"},{id:2,text:"blabla"}],{id:3,text:"blablabla"}]}
Is there a way to build a json object inside twig without going crazy?
I've already tried this way .. but rewrites the object and saves in the variable only the last element:
{% set data = [] %}
{% for artist in artists %}
{%
set data = {
id : artist.id,
text : artist.name|capitalize() ~' '~ artist.surname|capitalize()
}
%}
{% endfor %}
{% set data = {results: data} %}
{{ data|json_encode|raw }}
Use merge.
{% set data = [] %}
{% for artist in artists %}
{%
set data = data|merge ([{
id : artist.id,
text : artist.name|capitalize() ~' '~ artist.surname|capitalize()
}])
%}
{% endfor %}
{% set data = {results: data} %}
{{ data|json_encode|raw }}

Resources