Twig:“for”标签中的分隔符

问题描述 投票:0回答:2

是否有语法可以分隔“for”标签中的某些元素?

例如,我有一个用户列表,我想用“-”分隔符显示他们的用户名,所以预期的结果是:

Mickael - Dave - Chris - ...

我找到了这个解决方案:

{% for user in entity.users %}
    {{ user.name }}{% if not loop.last %} - {% endif %}
{% endfor %}

但这不是很优雅。 join 过滤器似乎不适合循环。

php symfony twig
2个回答
9
投票

据我所知,不,如果没有解决方法,您就无法将

join
过滤器用于您的用例。这是因为您需要将
getName
从对象属性中取出。
join
只需将
Traversable
实例的每个元素与给定的
glue
链接起来。

但是,如果您需要的话,可以采取一些解决方法。

添加 __toString 方法

在您的

User
实体中,您可以添加一个
__toString
方法来默认获取用户的名称。
但是,您应该小心,如果没有其他对象使用当前默认值
toString
,因为它可能会导致冲突

namespace Acme\FooBundle\Entity;

class User
{
    public function __toString()
    {
        return $this->getName();
    }
}

然后你可以在你的树枝中使用

join
过滤器

{{ entity.users|join(' - ') }}

在控制器中映射用户名

在控制器中,在将参数发送到视图之前,您可以将所有用户名映射到数组中。
注意:我假设

getUsers
PersistentCollection
,如果不是,请使用
array_map
代替

// Acme/FooBundle/Controller/MyController#fooAction

$users = $entity->getUsers();
$usernames = $users->map(function(User $user) {
    return $user->getName();
});

return $this->render('AcmeFooBundle:My:foo.html.twig', array(
    'entity' => $entity,
    'usernames' => $usernames
);

然后在你的树枝上

{{ usernames|join(' - ') }}

创建 TWIG 过滤器

在您的应用程序中,您可以创建一个Twig Extension。在此示例中,我将创建一个名为

joinBy
的过滤器,通过指定连接元素的方法,其作用类似于
join

 服务声明

简单直接,没有什么太苛刻的,只是像文档中那样的标准声明

服务.yml

acme_foo.tools_extension:
    class: Acme\FooBundle\Twig\ToolsExtension
    tags:
        - { name: twig.extension }

创建扩展

@Acme\FooBundle\Twig\ToolsExtension

namespace Acme\FooBundle\Twig;

use Twig_Extension, Twig_Filter_Method;
use InvalidArgumentException, UnexpectedValueException;
use Traversable;

/**
 * Tools extension provides commons function
 */
class ToolsExtension extends Twig_Extension
{
    /**
     * {@inheritDoc}
     */
    public function getName()
    {
        return 'acme_foo_tools_extension';
    }

    /**
     * {@inheritDoc}
     */
    public function getFilters()
    {
        return array(
            'joinBy' => new Twig_Filter_Method($this, 'joinBy')
        );
    }

    /**
     * Implode-like by specifying a value of a traversable object
     *
     * @param mixed  $data  Traversable data
     * @param string $value Value or method to call
     * @param string $join  Join string
     *
     * @return string Joined data
     */
    public function joinBy($data, $value, $join = null)
    {
        if (!is_array($data) && !($data instanceof Traversable)) {
            throw new InvalidArgumentException(sprintf(
                "Expected array or instance of Traversable for ToolsExtension::joinBy, got %s",
                gettype($data)
            ));
        }

        $formatted = array();

        foreach ($data as $row) {
            $formatted[] = $this->getInput($row, $value);
        }

        return implode($formatted, $join);
    }

    /**
     * Fetches the input of a given property
     *
     * @param  mixed  $row  An array or an object
     * @param  string $find Property to find
     * @return mixed  Property's value
     *
     * @throws UnexpectedValueException When no matching with $find where found
     */
    protected function getInput($row, $find)
    {
        if (is_array($row) && array_key_exists($find, $row)) {
            return $row[$find];
        }

        if (is_object($row)) {
            if (isset($row->$find)) {
                return $row->$find;
            }

            if (method_exists($row, $find)) {
                return $row->$find();
            }

            foreach (array('get%s', 'is%s') as $indic) {
                $method = sprintf($indic, $find);

                if (method_exists($row, $method)) {
                    return $row->$method();
                }
            }

            if (method_exists($row, $method)) {
                return $row->$method();
            }
        }

        throw new UnexpectedValueException(sprintf(
            "Could not find any method to resolve \"%s\" for %s",
            $find,
            is_array($row)
                ? 'Array'
                : sprintf('Object(%s)', get_class($row))
        ));
    }
}

使用方法

您现在可以通过调用在您的树枝中使用它

{{ entity.users|joinBy('name', ' - ') }}
# or
{{ entity.users|joinBy('getName', ' - ') }}

2
投票

在实体类中添加一个

__toString()
方法,就完成了。

并使用原生 Twig 的 join 过滤器,如

{{ entity.users|join(' - ') }}

© www.soinside.com 2019 - 2024. All rights reserved.