How to use variable as a match in saltstack mine.get - salt-stack

I am trying to use a salt mine to get a list of network interfaces of all the minions with the same os as that of the minion on which the jinja template is rendered.
I am trying something like this:
{% set variable = grains['os'] %}
{% set dict = salt['mine.get'('os:variable','network.interfaces','grain') %}
{% for i in dict : %}
// do stuff here
But the problem is in the above salt will try to match os to the value "variable" not to the actual value of the variable.
Using 'os: {{ variable }}' doesn't work too since {{ x }} just prints the value of variable x.
How can I match against the actual os in this case?

You should try + to concatenate prefix and variable name:
{% set variable = grains['os'] %}
{% set dict = salt['mine.get']('os:' + variable,'network.interfaces','grain') %}
{% for i in dict : %}
# do stuff
{% endfor %}

Related

Twig - loop default value

I am trying to print array from the cotroller into the twig temlate. I want to print "-" whenever array is NULL. My problem is that in for-loop case it writes nothing, however single row working fine. Is there some simple way how to do it correctly?
this is not working as i expected
{% for key in keywords|default('-') %}
{{ key~', '}}
{% endfor %}
this is working
{{ key |default('-')}}
You can use an {% else %} construct on a for loop to do something else if the array is null:
{% for key in keywords %}
{{ key~', '}}
{% else %}
-
{% endfor %}
See the documentation here.

Looping through values in twig and replacing empty values

The title is a bit ambiguous I know, but let me explain what I'm trying to achieve.
I am attempting to generate a CSV based on data pulled from a doctrine query in my Symfony2 CRM. The data retrieved is based on OpenCart Product and Attribute data, as well as some bespoke information which is irrelevant for this issue.
Each product can have up to 5 different attribute values, named A, B, D, L1 and L2. However, some products do not have all of them, only A, B and L1. The CSV requires each attribute value to be in a separate cell - so the headers are as follows:
ATTRIBUTE: A | ATTRIBUTE: B | ATTRIBUTE: D | ATTRIBUTE: L1 |
ATTRIBUTE: L2
And then I loop through in my Twig file as follows:
{% for attribute in row.product.attributes %}
{% if attribute.text is not null %}
{{ attribute.text }},
{% else %}na,{% endif %}
{% endfor %}
If the product has all 5 attributes, the structure of the CSV is fine. However, if the product only has 3 attributes, it means that all of the subsequent values are pulled back a cell, meaning that the other data is under the wrong headings. I tried checking for values first:
{% for attribute in row.product.attributes %}
{% if attribute.attributeName.name == "A" %}
{% if attribute.text is not null %}
{{ attribute.text }},
{% else %}na,{% endif %}
{% endif %}
{% endfor %}
And I did this for each possible attribute name, but unfortuantely this does not work since if the name does not exist, it just skips it anyway. I'm having trouble trying to think of a way to loop through these attributes and entering a n/a if it's non existent - I'm sure there is a way but I don't know what it is.
For reference, here is the controller code that's generating the data for the CSV:
public function adminCsvAction($filter) {
$repository = $this->getDoctrine()->getRepository('AppBundle:Project');
$stages_repository = $this->getDoctrine()->getRepository('AppBundle:Stage');
$users_repository = $this->getDoctrine()->getRepository('AppBundle:User');
$results = $repository->getSearchResults($filter);
$users = $users_repository->findAll();
$stages = $stages_repository->findBy(array('deleted' => 0), array('sortOrder' => 'ASC'));
$filename = "export_".date("Y_m_d_His").".csv";
$response = $this->render('AppBundle:pages:csv.html.twig', array('data' => $results,'users' => $users, 'stages' => $stages));
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
return $response;
}
The Project Entity has various mappings, one of which links to the Product table in OpenCart which means all attributes and linked values are accessible via this.
Any help in this is much appreciated.
I also agree with Cerad from comment section - that is not the job for Twig. In case your really need to do it, I would try roughly something like this:
{% set allAttr = ["A","B","D","L1","L2"] %}
{% for attribute in allAttr %}
{% if row.product.attributes[attribute] is defined %}
{{ row.product.attributes[attribute].text }}
{% endif %}
{% if not loop.last %},{% endif %}
{% endfor %}
I guess the is defined is critical here...
OK I figured it out. Using what Jovan Perovic suggested, I came up with this:
{% set allAttr = ["A","B","D","L1","L2"] %}
{% set prodAtts = [] %}
{% for row in data %}
{% set existingAtts = [] %}
{% for att in allAttr %}
{% if att not in prodAtts %}
{% set prodAtts = prodAtts|merge([att]) %}
{% endif %}
{% endfor %}
{% for rowAtt in row.product.attributes %}
{% set existingAtts = existingAtts|merge({(rowAtt.attributeName.name|trim):(rowAtt.attributeName.name|trim~'_'~rowAtt.text|trim)}) %}
{% endfor %}
{% for prodAtt in prodAtts %}
{% if prodAtt not in existingAtts|keys %}
{% set existingAtts = existingAtts|merge({(prodAtt):(prodAtt~'_na')}) %}
{% endif %}
{% endfor %}
{% set orderedAtts = existingAtts|sort %}
....
Then the loop for each row thereafter. I used the attribute name with an underscore in order to be able to sort it correct (as it only sorts by value not key) then used preg_replace to remove it along with any instance of the name so I just ended up with the value.
Bit of a lengthy - and probably over thought - solution but it does work!

Set a Variable with a Twig Macro

I have to set a variable with a macro, that returns a number, so I have this macro:
{% import _self as self %}
{% macro function_size(field) %}
{% import _self as self %}
{# initial Setup #}
{% set field_length = 0 %}
{# Field #}
{% for key, value in field %}
{% if not (key starts with "#") %}
{% set field_length = field_length + 1 %}
{% endif %}
{% endfor %}
{{ field_length }}
{% endmacro %}
The Macro loops through the entries of a field and returns the count of values, that don't start with "#".
So I set a variable with that value:
{% set image_size = self.function_size(content.field_teaser_image) %}
ATTENTION: With this you will set the Variable with Twig Markup. (You can see that when you debug the variable afterwards.)
To get a number/integer as value you have to convert it to a String (that will be interpreted as a number if you calculate with it)
{% set image_size = image_size.__toString %}
With this I set the Variable successfully with a macro.
My Question: Is this a bad practice, are there better ways how to set an Variable?
Thank you!
Two ways to set variables for twig are fine in my opinion.
1. Use theme and other hooks (inside theme or any module) and pass variable from php,
2. create twig extension/filter
Examples:
Filter:
http://leopathu.com/content/create-custom-twig-filter-drupal-8
Extension:
http://symfony.com/doc/current/templating/twig_extension.html

Set Variable only get the last value in a loop in Symfony Twig

I am very new in Symfony and I have a problem in my twig. I just don't know how to do it :(
{% set trans_number = '' %}
{% for tran in trans %}
{% set trans_number = tran.transNumber %}
{{dump(trans_number)}}
// this is what I get when dumping inside the loop: string(10) "1073110793" string(10) "1073145793" string(12) "646721454679"
{% endfor %}
But when I tried to dump it outside the loop:
{% set trans_number = '' %}
{% for tran in trans %}
{% set trans_number = tran.transNumber %}
{% endfor %}
{{dump(trans_number)}}
// I get only the last value string(12) "646721454679"
Now my question is, how can I access all the values assigned to the trans_number outside the loop?
Thanks in advance.
You're correct with the variable scope and handling the scope access by declaring trans_number before the loop, however you're misinterpreting how set works with Twig, or just how variables work.
When you use set trans_number = tran.transNumber, you're just assigning a new value to the trans_number variable each time. When you move the dump outside of the loop, you're no longer dumping the new value of trans_number through each iteration.
If you wish to build a list of values into trans_number, then you need to initialize trans_number as a list and append to it through each iteration of the for loop:
{% set trans_number = [] %}
{% for tran in trans %}
{% set trans_number = trans_number|merge([tran.transNumber]) %}
{% endfor %}
{{dump(trans_number)}}
For people looking for the answer to the question in the title of the question:
You could use the last Filter
Example:
{{ dump( (trans|last) ) }}
Source: http://twig.sensiolabs.org/doc/filters/last.html

Twig / Symfony2 - using a variable inside array merge

{% set var_name1 = "hello" %}
{% set var_name2 = "there" %}
{% array1|merge({var_name1: var_name2}) %}
I was hoping the code above would add this to array1:
hello:there
...but it adds:
var_name1:there
I've tried wrapping {{ }} around var_name1. Is it possible to add a record to an array and use a variable for the key?
Enclose the key name in brackets:
{% array1|merge({(var_name1): var_name2}) %}
Note that if var_name1 is a numeric value, it won't work.
You'll have to concat it with a string value :
{% set array1 = array1|merge({(var_name1~'_'): var_name2}) %}

Resources