Php 如何在实体内使用translator服务?

Php 如何在实体内使用translator服务?,php,symfony,entity,translation,Php,Symfony,Entity,Translation,假设我有一个用户实体: $user = new User(007); echo $user->getName(); // display Bond echo $user->getGender(); // display "Male"; echo $user->getDesignation() // display "Monsieur Bond" or "Mister Bond" 使用此功能: public function getDesignation() { if ($

假设我有一个
用户
实体:

$user = new User(007);
echo $user->getName(); // display Bond
echo $user->getGender(); // display "Male";
echo $user->getDesignation() // display "Monsieur Bond" or "Mister Bond"
使用此功能:

public function getDesignation() {
  if ($this->getGender() == 'Male') return "Monsieur ".$this->getName();
  else return "Madame ".$this->getName();
}
如何使用该实体内的翻译服务翻译“先生”和“夫人”


翻译服务似乎只应该在控制器中使用,但我认为在这种情况下,在这个实体中使用它是合适的。

您不应该这样做,一般来说这是不可能的。根据规则,实体已经有了它们的用途,即表示数据库中的数据。此外,翻译是一个表示问题,因此您不太可能希望在实体层解决此类问题(除非您希望提供用不同语言翻译的实体,这是一个完全不同的问题,甚至不应该使用翻译器来解决)


重新思考你的逻辑,尝试不同的方法。是否确实不希望在视图层上执行此转换?这可能是最好的办法。否则(如果您的逻辑确实需要在模型级别进行转换),您可以为实体创建一个包装类,并创建一个工厂来生成这个“包装实体”;在那个工厂中,您可以注入翻译服务

translator服务,如您所说,是一种“服务”,您可以在任何类中使用服务(即,将其定义为服务并使用依赖注入容器)。所以,你几乎可以在任何你想要的地方使用翻译器

但是像这样的实体不应该有这样的责任。在最坏的情况下,如果您真的想翻译实体内部的内容,可以使用set方法将转换器传递给实体,即

$entity->setTranslator($translator);
但我也建议您创建一个类来处理实体之外的问题,即使用细枝模板

{{ entity.property|trans }}).

我遇到了类似的问题,最终找到了这个解决方案。这并不是对您的问题的直接回答,因为我也知道实体应该与服务无关,比如翻译器。因此,您应该保持getDesignation函数不变。相反,在表示层(例如,细枝)中,您可以翻译该法语名称

<div>{% trans %}{{ entity.designation }}{% endtrans %} {{ entity.name }}</div>

在过去的几年里,我多次遇到这个问题,并且总能找到一个足够好的解决方法。这次我的
getIdentificationName()
方法在整个项目中大量使用(比如显式的
\uu-toString()
)必须翻译数据层中使用的一些关键字,因此没有优雅的解决方法

这次我的解决方案是一个
TranslateObject
和一个相应的助手服务。
TranslateObject
是一个普通对象,它包含一个转换键和一组占位符,占位符也可以是TranslateObject,以允许多级转换(如
getIdentificationNameTranslateObject()
调用另一个相关对象的
getIdentificationNameTranslateObject()
):

助手的外观如下所示,并执行以下操作:

namespace App\Services;

use App\Utils\TranslateObject;
use Symfony\Contracts\Translation\TranslatorInterface;

class TranslateObjectHelper
{
    /** @var TranslatorInterface */
    protected $translator;

    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }

    public function trans(TranslateObject $translateObject): string
    {
        $placeholders = $translateObject->getPlaceholders();
        foreach ($placeholders as $key => &$placeholder) {
            if ($placeholder instanceof TranslateObject) {
                $placeholder = $this->trans($placeholder);
            }
            elseif (true === $placeholder['translate']) {
                $placeholder = $this->translator->trans($placeholder['value']);
            }
            else {
                $placeholder = $placeholder['value'];
            }
        }

        return $this->translator->trans($translateObject->getTransKey(), $placeholders);
    }
}
然后在实体中有一个
getIdentificationNameTranslateObject()
方法返回一个
TranslateObject

/**
 * Get an identifying name as a TranslateObject (for use with TranslateObjectHelper)
 */
public function getIdentifyingNameTranslateObject(): TranslateObject
{
    return new TranslateObject('my.whatever.translation.key', [
        '%placeholder1%' => $this->myEntityProperty1,
        '%placeholderWithANeedOfTranslation%' => [
            'value' => 'my.whatever.translation.values.' . $this->myPropertyWithANeedOfTranslation,
            'translate' => true,
        ],
        '%placeholderWithCascadingTranslationNeeds%' => $this->getRelatedEntity()->getIdentifyingNameTranslateObject(),
    ]);
}
当我需要返回这样一个已翻译的属性时,我需要访问注入的
TranslateObjectHelper
服务,并像在控制器或任何其他服务中一样使用其
trans()
方法:

$this->translateObjectHelper->trans($myObject->getIdentifyingNameTranslateObject());
然后我创建了一个细枝过滤器作为简单的助手,如下所示:

namespace App\Twig;

use App\Services\TranslateObjectHelper;
use App\Utils\TranslateObject;

class TranslateObjectExtension extends \Twig_Extension
{
    /** @var TranslateObjectHelper */
    protected $translateObjectHelper;

    public function __construct(TranslateObjectHelper $translateObjectHelper)
    {
        $this->translateObjectHelper = $translateObjectHelper;
    }

    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('translateObject', [$this, 'translateObject']),
        );
    }

    /**
    * sends a TranslateObject through a the translateObjectHelper->trans() method
    */
    public function translateObject(TranslateObject $translateObject): string
    {
        return $this->translateObjectHelper->trans($translateObject);
    }

    public function getName(): string
    {
        return 'translate_object_twig_extension';
    }
}
{{ myObject.getIdentifyingNameTranslateObject()|translateObject }}
所以在Twig中,我可以这样翻译:

namespace App\Twig;

use App\Services\TranslateObjectHelper;
use App\Utils\TranslateObject;

class TranslateObjectExtension extends \Twig_Extension
{
    /** @var TranslateObjectHelper */
    protected $translateObjectHelper;

    public function __construct(TranslateObjectHelper $translateObjectHelper)
    {
        $this->translateObjectHelper = $translateObjectHelper;
    }

    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('translateObject', [$this, 'translateObject']),
        );
    }

    /**
    * sends a TranslateObject through a the translateObjectHelper->trans() method
    */
    public function translateObject(TranslateObject $translateObject): string
    {
        return $this->translateObjectHelper->trans($translateObject);
    }

    public function getName(): string
    {
        return 'translate_object_twig_extension';
    }
}
{{ myObject.getIdentifyingNameTranslateObject()|translateObject }}

最后,我“只是”需要找到该实体上的所有
getIdentificationName()
调用(或
.IdentificationName
在细枝中),并用
getIdentificationNameTranslateObject()替换它们,调用
TranslateObject助手的
trans()
方法(或Twig中的
translateObject
filter)。

Wouah!我不知道{$variable | trans}函数。我相信它只能用于纯文本(而不是变量)。非常感谢!是的,顺便说一句,你不需要$符号。我今天一直在Twig中与Smarty合作:{{variable | trans}您甚至可以翻译从函数、数组等返回的文本,例如:{{app.session.getFlash('panel_alert').msg}事实上,我这样做是因为我的另一个问题:但我理解您所说的。谢谢:)