如何检查多维 Twig 数组的值?

How to check a multidimensional Twig array for values?

要简单地检查数组是否包含某个值,我会这样做:

{% 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'] 是否具有标签 ID 20。我希望我不会因为使用 PHP 数组格式而让您感到困惑。

我找到了解决方案。没想到这么简单。有时我想我只是想把事情弄得太复杂。

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

在我看来,这不是最有效的方法,但它目前对我有用。

编辑

Yenne Info 告诉我以下方法。它有点干净。我不知道它是否提高了性能。

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

这个更像是一个多维循环,以备不时之需

   {% for animals in array %}

        {% set dogs = animals.dogs %}

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

    {% endfor %}

设置标志并使用循环。之后你可以在 if 条件下使用标志。

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

在 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

中创建 Custom Filter

为了减少模板中的代码,twig 有机会创建自定义过滤器。要实现更通用的功能,您可以简单地使用变量名称并将属性名称用作另一个参数。

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

树枝

{% if tasks.tags|inTags(20) %}
    //do something
{% endif %}

{% 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 that will convert our array into a SimpleXMLElement object, and use 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',
                ),
            ),
        ),
    ),
);

// 
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);

给运行吧

composer require twig/twig
php xpath_test.php

对于 Twig 中多维数组中的 if 语句。检查 for 循环,然后检查 if 语句。

这是 Twig 的 shorthand:

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

----编辑----

其他

做一个else。所以这里的else就是如果整个for:

什么都找不到
{% for tag in tasks.tags %}    
       here_if_true
{% else %}
       if there was nothing found
{% endfor %}    

FOR-IF ELSE

可以组合 ifelse,但这与 for 循环中的 if else 不同.因为 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 example

FOR-IF ELSE 和 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 %}

LIVE example

TWIG documentation