Как проверить многомерный массив Twig для значений?

Чтобы просто проверить, содержит ли массив определенное значение, которое я сделал бы:

{% if myVar in someOtherArray|keys %}
...
{% endif %}

Однако мой массив многомерен.

$tasks = array(
    'someKey' => 'someValue',
    ...
    'tags' => array(
        '0' => array(
            'id'   => '20',
            'name' => 'someTag',
        ),
        '1' => array(
            'id'   => '30',
            'name' => 'someOtherTag',
        ),
    ),
);

Я бы хотел проверить, имеет ли тег $tasks['tags'] идентификатор тега 20. Надеюсь, я не смущаю вас, используя формат массива PHP.

Ответ 1

Установите флаг и используйте цикл. Впоследствии вы можете использовать флаг в условиях if.

{% set flag = 0 %}
{% for tag in tasks.tags %}
    {% if tag.id == "20" %}
        {% set flag = 1 %}
    {% endif %}
{% endfor %}
{{ flag }}

Ответ 2

это больше похоже на многомерный цикл в случае необходимости

   {% for animals in array %}

        {% set dogs = animals.dogs %}

        {% for dog in dogs %}
            {{ dump(dog.type) }}
        {% endfor%}

    {% endfor %}

Ответ 3

Для оператора if в многомерном массиве в Twig. Проверьте внутри цикла for, а затем оператор if.

Вот краткое описание этого с Twig:

{% for tag in tasks.tags if tag.id == '20' %}      
       here_if_true
{% endfor %}    

---- ИЗМЕНИТЬ ----

ДЛЯ ELSE

Сделать else. Итак, else здесь, если ничего не найдено во всем for:

{% for tag in tasks.tags %}    
       here_if_true
{% else %}
       if there was nothing found
{% endfor %}    

FOR-IF ELSE

Возможна комбинация if и else, но она не совпадает с if else внутри цикла for. Поскольку else для for, а не для 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 %}

Пример LIVE

FOR-IF ELSE и ЕСЛИ 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 %}

Пример LIVE

Документация TWIG

Ответ 4

Я нашел решение. Не ожидал, что это будет так просто. Иногда, я думаю, я просто пытаюсь сделать вещи слишком сложными.

{% for tag in tasks.tags %}
    {% if tag.id == '20' %}
        This tag has ID 20
    {% endif %}
{% endfor %}

По-моему, это не самый эффективный способ, но он делает трюк для меня в данный момент.

Edit

Yenne Info подсказывала мне следующий метод. Это немного чище. Я не знаю, улучшает ли производительность.

{% for tag in tasks.tags if tag.id == '20' %}
    Bingo! We've got a match
{% endfor %}

Ответ 5

Установка флага в Twig

{% set flag = 0 %}

{% for tag in tasks.tags %}
    {% if tag.id == "20" %}
        {% set flag = 1 %}
    {% endif %}
{% endfor %}

{% if flag == 1 %}
    //do something
{% endif %}

Создание Пользовательский фильтр в PHP

Чтобы уменьшить код в ваших шаблонах, ветка имеет возможность создавать собственные фильтры. Для достижения более общей функциональности вы можете просто использовать имена переменных переменных и использовать имя атрибута в качестве другого параметра.

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

Ответ 6

{% if myVar is xpath_aware('//tags/*[id=20]') %}

Контекст

Если вы собираетесь делать условия на произвольном глубоком массиве, почему бы не использовать силу xpath? Массив - это не более чем несериализованная XML-строка!

Итак, следующий массив:

$data = array(
    'someKey' => 'someValue',
    'foo'     => 'bar',
    'hello'   => array(
        'world' => true,
        'tags'  => array(
            '0' => array(
                'id'   => '20',
                'name' => 'someTag',
            ),
            '1' => array(
                'id'   => '30',
                'name' => 'someOtherTag',
            ),
        ),
    ),
);

Является эквивалентом строки XML (исправлено, чтобы избежать числовых тегов):

<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>

И вы хотите знать, соответствует ли ваш массив следующему выражению xpath:

//tags/*[id=20]

Реализация

Мы создаем новый twig Test, который преобразует наш массив в объект SimpleXMLElement и использует SimpleXMLElement::xpath(), чтобы проверить соответствие данного xpath.

$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);
});

Теперь мы можем запустить следующий тест в Twig:

{% if myVar is xpath_aware('//tags/*[id=20]') %}

Полная исполняемая реализация:

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