Reputation: 9113
To simply check if an array contains a certain value I would do:
{% if myVar in someOtherArray|keys %}
...
{% endif %}
However, my array is multi-dimensional.
$tasks = array(
'someKey' => 'someValue',
...
'tags' => array(
'0' => array(
'id' => '20',
'name' => 'someTag',
),
'1' => array(
'id' => '30',
'name' => 'someOtherTag',
),
),
);
What i would like is to be able to check if the $tasks['tags']
has tag id 20. I hope I'm not confusing you by using the PHP array format.
Upvotes: 10
Views: 8354
Reputation: 357
For an if-statement within a multi-dimensional array in Twig. Check within the for-loop and then the if statement.
Here is the shorthand for this with Twig:
{% for tag in tasks.tags if tag.id == '20' %}
here_if_true
{% endfor %}
---- EDIT ----
FOR ELSE
To do an else
. So the else
here is if nothing is found in the entire for
:
{% for tag in tasks.tags %}
here_if_true
{% else %}
if there was nothing found
{% endfor %}
FOR-IF ELSE
Making a combination of the if
and else
is possible, but it is NOT the same as an if
else
inside the for
loop. Because the else
is for the for
and not for the if
.
{% for tag in tasks.tags if tag.name == 'blue' %}
This will fire if in the FOR the tag.name that is blue
{% else %}
This will fire if there were NO tag.name blue were found ENTIRE FOR!
{% endfor %}
FOR-IF ELSE and IF ELSE
{% for tag in tasks.tags if tag.id == 3 %}
the id is 3
{% if tag.name == 'blue' %}
the id of the tag is 3 and tag.name is blue
{% else %}
the id of the tag is 3 but the tag.name is not blue
{% endif %}
{% else %}
there was no tag.id 3 found in the tasks.tags
{% endfor %}
Upvotes: 3
Reputation: 36954
{% if myVar is xpath_aware('//tags/*[id=20]') %}
If you are going to do conditions on an arbitrary deep array, why not using the power of xpath
? An array is no more than an unserialized XML string after all!
So, the following array:
$data = array(
'someKey' => 'someValue',
'foo' => 'bar',
'hello' => array(
'world' => true,
'tags' => array(
'0' => array(
'id' => '20',
'name' => 'someTag',
),
'1' => array(
'id' => '30',
'name' => 'someOtherTag',
),
),
),
);
Is the equivalent of the XML string (fixed to avoid numeric tags):
<data>
<someKey>someValue</someKey>
<foo>bar</foo>
<hello>
<world>1</world>
<tags>
<item0>
<id>20</id>
<name>someTag</name>
</item0>
<item1>
<id>30</id>
<name>someOtherTag</name>
</item1>
</tags>
</hello>
</data>
And you want to know if your array matches the following xpath expression:
//tags/*[id=20]
We create a new twig Test that will convert our array into a SimpleXMLElement
object, and use SimpleXMLElement::xpath()
to check if a given xpath matches.
$test = new Twig_SimpleTest('xpath_aware', function (array $data, $path) {
$xml = new SimpleXMLElement('<?xml version="1.0"?><data></data>');
array_to_xml($data, $xml); // see full implementation below
return array() !== $xml->xpath($path);
});
We are now able to run the following test in Twig:
{% if myVar is xpath_aware('//tags/*[id=20]') %}
Full executable implementation:
xpath_test.php
<?php
include (__DIR__.'/vendor/autoload.php');
$context = array(
'myVar' => array(
'someKey' => 'someValue',
'foo' => 'bar',
'hello' => array(
'world' => true,
'tags' => array(
'0' => array(
'id' => '20',
'name' => 'someTag',
),
'1' => array(
'id' => '30',
'name' => 'someOtherTag',
),
),
),
),
);
// http://stackoverflow.com/a/5965940/731138
function array_to_xml($data, &$xml_data)
{
foreach ($data as $key => $value) {
if (is_array($value)) {
if (is_numeric($key)) {
$key = 'item'.$key; //dealing with <0/>..<n/> issues
}
$subnode = $xml_data->addChild($key);
array_to_xml($value, $subnode);
} else {
$xml_data->addChild("$key", htmlspecialchars("$value"));
}
}
}
$twig = new Twig_Environment(new Twig_Loader_Array([]));
$test = new Twig_SimpleTest('xpath_aware', function (array $data, $path) {
$xml = new SimpleXMLElement('<?xml version="1.0"?><data></data>');
array_to_xml($data, $xml);
return array() !== $xml->xpath($path);
});
$twig->addTest($test);
$source = <<< EOT
{% if myVar is xpath_aware('//tags/*[id=20]') %}
It matches!
{% endif %}
EOT;
$template = $twig->createTemplate($source);
echo $template->display($context);
To run it
composer require twig/twig
php xpath_test.php
Upvotes: 1
Reputation: 9103
{% set flag = 0 %}
{% for tag in tasks.tags %}
{% if tag.id == "20" %}
{% set flag = 1 %}
{% endif %}
{% endfor %}
{% if flag == 1 %}
//do something
{% endif %}
To reduce the code in your templates twig has the opportunity to create custom filters. To achieve a more general functionality you can simply use variable variable names and use the attribute name as another parameter.
PHP
$filter = new Twig_SimpleFilter('inTags', function ($tags, $needle) {
$match = false;
foreach($tags as $tag){
if(in_array($needle, $tag)){
$match = true;
break;
}
}
return $match;
});
$twig = new Twig_Environment($loader);
$twig->addFilter($filter);
Twig
{% if tasks.tags|inTags(20) %}
//do something
{% endif %}
Upvotes: 1
Reputation: 9113
I found myself the solution. Didn't expect it to be so simple. Sometimes I guess I just try to make things too complicated.
{% for tag in tasks.tags %}
{% if tag.id == '20' %}
This tag has ID 20
{% endif %}
{% endfor %}
In my opinion this is not the most efficient way but it does the trick for me at the moment.
Edit
Yenne Info tipped me about the following method. It's a bit cleaner. I don't know if it improves performance though.
{% for tag in tasks.tags if tag.id == '20' %}
Bingo! We've got a match
{% endfor %}
Upvotes: 1
Reputation: 9103
Set a flag and use a loop. Afterwards you can use the flag in if conditions.
{% set flag = 0 %}
{% for tag in tasks.tags %}
{% if tag.id == "20" %}
{% set flag = 1 %}
{% endif %}
{% endfor %}
{{ flag }}
Upvotes: 8
Reputation: 1489
this one is more like a multidimensional loop in case it's necessary
{% for animals in array %}
{% set dogs = animals.dogs %}
{% for dog in dogs %}
{{ dump(dog.type) }}
{% endfor%}
{% endfor %}
Upvotes: 4