Symfony 2 twig split function is not working as expected - symfony

I am bored searching for an answer so this is my firs question here.
In Symfony 2 , in my twig template i iterate over an array of objects:
{% for client in clients %}
i have the variable client.curs = to the string "Cursul 1 = 4.1234"
i want to split this string so i use
{% set cursarr = client.curs|split(' = ') %}
now, if i dump my array i get
array (size=2) 0 => string 'Cursul 1' (length=8) 1 => string '4.1234' (length=6)
wow! cool! just what i wanted. i continue my work, i just need the second part of
the array (4.1234) so i do this:
{{ cursarr[1] }}
ooops! Key "1" for array with keys "0" does not exist.
Ok! i am an idiot so i try:
{{ cursarr.1 }} same error here. Hmmmm! WTF?!
i try {{ cursarr[0] }} pops out 'Cursul 1' WTF?!
{{ cursarr.0 }} also working
i don't get it, what am i doing wrong? Why is life so complicated?
is it because it is late and i am tired? Need help!
{% endfor %}

I manage to make it work this morning with a clear mind :)
{% set cursarr = client.cursuri|split(' = ') %}
{% set cSpecial = '' %}
{% for curs in cursarr %}
{% set cSpecial = curs %}
{% endfor %}
I have to iterate the array in order to get the second value;
I didn't realized it is a multidimensional mdfkr.
Hope this will help someone in need.

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!

How to passe an array to jquery in twig

I have the following code :
{% set aSessionKeys = app.session.get('aBasket')|keys %}
onkeyup="calculatePrice({{ product['product_price'] }},{{ product['product_id'] }},{{ aSessionKeys }})
And I have an error :
Notice: Array to string conversion
Can you help me please? Thx in advance. So exist a solution to passe this array?
I do like this :
{% set aKeys = aSessionKeys|join(',') %}
{{ dump(aKeys) }}
It shows good, but if I passe to jquery :
calculatePrice({{ product['product_price'] }},{{ product['product_id'] }},{{ aKeys }})
When I do in js methode calculatePrice() :
function calculatePrice(price, product_id, aKeys) {
console.log(aKeys);
var x = document.getElementById("product_quantity_"+product_id);
var total_price = price * x.value;
$("#total_price_"+product_id).html(total_price+" <small> MDL</small>");
sum = 0;
$("#total_price_basket").html();
}
It shows only the first value of aKeys
You have very popular error. You are trying to display array. But how do you imagine that? You can use {{ dump(aSessionKeys) }} for that purpose or use first element: {{ aSessionKeys.0 }} (if it is not an array or object).
But if you want to print all values from this array you can run foreach loop:
{% for element in aSessionKeys %}
{# something here #}
{{ element }}
{# something here #}
{% endfor %}
Obviously (as you are using the |keys filter) aSessionKeys contains an array, and by using {{ aSessionKeys }} in the template Twig will try to output the array as a string, which doesn’t work (or at least is not what you want).
To convert the array to a string, you should use Twig’s join() filter, which will concatenate the array values using a given delimiter string. So, if – for instance – you want to join the values using a comma, this would be the code:
{{ aSessionKeys|join(',) }}

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}) %}

Dynamic twig variable names

Given an array of variables sent to a twig template, such as:
$form = $this->createForm( new ServiceItemType()
, $entity
, array( 'attr'=>
array(
'em' => $this->EM()
,'group' => true
) ) );
I want to capture the variables for easy access in twig. However:
{% for key, value in form.vars.attr %}
{% set key = value %}
{% endfor %}
remaps the key variable in the for loop.
twig objects to:
{% for key, value in form.vars.attr %}
{% set {{key}} = value %}
{% endfor %}
And stack as I am aware never seems to address set. Would anyone who knows, please indicate how to accomplish this variable assignment?
I know this syntax works
{% render "..." with {(key): value} %}
Did you try the following syntax? As of March, Friday 22nd this syntax didn't work so you need to use a work around.
{% set (key) = value %}
An alternative to that would be to include a template and pass and form.vars.attr.
{% include "YourAwesomeBundle:Controller:template.html.twig" with form.vars.attr %}
You can also merge form.vars.attr with another array using the merge function.
{% set vars = {} %}
{% set vars = vars|merge(form.vars.attr) %}
{% include "YourAwesomeBundle:Controller:template.html.twig" with vars %}
Within the included template you will be able to use the variable em and group.

Resources