如何检查一个多维的Twig数组是否包含某些值?

10

为了简单地检查数组中是否包含某个值,我会执行以下操作:

{% 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数组格式没有让你感到困惑。

6个回答

8

设置一个标志并使用循环。之后您可以在if条件语句中使用该标志。

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

你可以做得更好:http://twig.sensiolabs.org/doc/tags/for.html#adding-a-condition - BENARD Patrick
这个答案对我帮助最大,因为在其他两个答案(包括我的)中,它给出了每次迭代的结果。通过使用标志,标志的结果状态告诉您您的值是否在数组中。 - Peter

4
这个更像是一个多维循环,以防必要时使用。
   {% for animals in array %}

        {% set dogs = animals.dogs %}

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

    {% endfor %}

3

在Twig中,对于多维数组中的if语句,请在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

可以将ifelse组合在一起,但这与for循环内的ifelse不同。因为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 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 %}

LIVE example

TWIG documentation


@Pathros,我修改了我的帖子,希望能回答你的问题。 - Wow

1

{% 如果 myVar 是 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测试,将我们的数组转换为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',
                ),
            ),
        ),
    ),
);

// https://dev59.com/6XM_5IYBdhLWcg3wZSI6#5965940
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

1
在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中创建自定义过滤器

为了减少模板中的代码,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);

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

1

我找到了解决方案。没想到它如此简单。有时候我猜我只是试图把事情变得太复杂了。

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

你可以做得更好:http://twig.sensiolabs.org/doc/tags/for.html#adding-a-condition - BENARD Patrick
你如何包含一个 else?或者通过设置 not 来获得相反的结果? - Pathros

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接