我使用 symfony2.4 和 KNP doctrine behaviors translatable。
我有实体 Site
(用于 ID、主机、已启用)和实体 SiteTranslation
(用于翻译字段:名称、描述等)。
我使用查询来获取结果
$qb = $this->createQueryBuilder('s')
->addSelect('translation') // to eager fetch translations (optional)
->leftJoin('s.translations', 'translation') // or innerJoin ?
->orderBy('s.root', 'ASC')
->addOrderBy('s.lft', 'ASC');
我想在 Twig 中打印结果。对于 Site
实体的 ID、host 和 enabled 字段很简单:
{{ item.id }}
但我无法打印翻译后的字段(名称、描述……)
{{ item.name }}
它不起作用。
错误信息:
ContextErrorException: Warning: call_user_func_array() expects parameter 1 to be a valid >callback, class 'Net\ConBundle\Entity\SiteTranslation' does not have a method 'name' in >D:\Users...\vendor\knplabs\doctrine->behaviors\src\Knp\DoctrineBehaviors\Model\Translatable\TranslatableMethods.php line 140
可翻译字段的 getter 和 setter 在 SiteTranslation 实体中。
更新:
我仍然没有找到错误的解决方案。
这是 Site
实体:
<?php
namespace Pnet\ConlocoBundle\Entity;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* @UniqueEntity("host", message="site.host.unique", groups={"edit"})
* @Gedmo\Tree(type="nested")
* @ORM\Entity(repositoryClass="Pnet\ConlocoBundle\Entity\Repository\SiteRepository")
* @ORM\Table(name="site")
*/
class Site
{
use ORMBehaviors\Translatable\Translatable; // knp translatable strategy
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=40, unique=true)
* @Assert\NotBlank(message="site.host.notBlank", groups={"edit"})
* @Assert\Length(max = "40", maxMessage = "site.host.maxLength", groups={"edit"})
*/
protected $host;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\Image()
*/
protected $image;
/**
* @ORM\Column(type="boolean")
* @Assert\Choice(choices = {"1", "0"}, message = "site.isDefault.choice", groups={"edit"})
*/
protected $isDefault;
/**
* @ORM\Column(type="boolean")
* @Assert\Choice(choices = {"1", "0"}, message = "site.enabled.choice", groups={"edit"})
*/
protected $enabled;
/**
* @ORM\Column(type="string", length=64, nullable=true)
*/
protected $analytics;
/**
* @Gedmo\TreeLeft
* @ORM\Column(name="lft", type="integer")
*/
private $lft;
/**
* @Gedmo\TreeLevel
* @ORM\Column(name="lvl", type="integer")
*/
private $lvl;
/**
* @Gedmo\TreeRight
* @ORM\Column(name="rgt", type="integer")
*/
private $rgt;
/**
* @Gedmo\TreeRoot
* @ORM\Column(name="root", type="integer", nullable=true)
*/
private $root;
/**
* @Gedmo\TreeParent
* @ORM\ManyToOne(targetEntity="Site", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* @ORM\OneToMany(targetEntity="Site", mappedBy="parent")
* @ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
private $file;
public $idByFilter;
public $nameByFilter;
/**
* Proxy translations (Knp/Doctrine Behaviors)
* An extra feature allows you to proxy translated fields of a translatable entity.
* You can use it in the magic __call method of you translatable entity so that when
* you try to call getName (for example) it will return you the translated value
* of the name for current locale:
*/
public function __call($method, $arguments)
{
return $this->proxyCurrentLocaleTranslation($method, $arguments);
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set host
*
* @param string $host
* @return Site
*/
public function setHost($host)
{
$this->host = $host;
return $this;
}
/**
* Get host
*
* @return string
*/
public function getHost()
{
return $this->host;
}
/**
* Set isDefault
*
* @param boolean $isDefault
* @return Site
*/
public function setIsDefault($isDefault)
{
$this->isDefault = $isDefault;
return $this;
}
/**
* Get isDefault
*
* @return boolean
*/
public function getIsDefault()
{
return $this->isDefault;
}
/**
* Set enabled
*
* @param boolean $enabled
* @return Site
*/
public function setEnabled($enabled)
{
$this->enabled = $enabled;
return $this;
}
/**
* Get enabled
*
* @return boolean
*/
public function getEnabled()
{
return $this->enabled;
}
/**
* Set analytics
*
* @param string $analytics
* @return Site
*/
public function setAnalytics($analytics)
{
$this->analytics = $analytics;
return $this;
}
/**
* Get analytics
*
* @return string
*/
public function getAnalytics()
{
return $this->analytics;
}
/**
* Get ID from Filter
*
* @return string
*/
public function getIdByFilter()
{
return $this->idByFilter;
}
/**
* Get name from Filter
*
* @return string
*/
public function getNameByFilter()
{
return $this->nameByFilter;
}
/**
* Set image
*
* @param string $image
* @return Site
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* @return string
*/
public function getImage()
{
return $this->image;
}
/**
* Set file
*
* @param string $file
* @return Site
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Get file
*
* @return string
*/
public function getFile()
{
return $this->file;
}
/**
*
* Tree functions
*/
public function setParent(Site $parent = null)
{
$this->parent = $parent;
}
public function getParent()
{
return $this->parent;
}
public function getRoot()
{
return $this->root;
}
public function getLvl()
{
return $this->lvl;
}
public function getChildren()
{
return $this->children;
}
public function getLft()
{
return $this->lft;
}
public function getRgt()
{
return $this->rgt;
}
/**
* Add a method to the entity class that shows the name indented by nesting level
*/
public function getLeveledName()
{
return str_repeat(
html_entity_decode(' ', ENT_QUOTES, 'UTF-8'),
($this->getLvl()) * 3
) . $this->getName();
}
public function getLeveledPosition()
{
return str_repeat(
html_entity_decode(' ', ENT_QUOTES, 'UTF-8'),
($this->getLvl()) * 3
);
}
}
这是 SiteTranslation
实体:
namespace Pnet\ConlocoBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* @ORM\Entity
*/
class SiteTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* @ORM\Column(type="string", length=60)
* @Assert\NotBlank(message="site.name.notBlank", groups={"edit"})
* @Assert\Length(max = "60", maxMessage = "site.name.maxLength", groups={"edit"})
*/
protected $name;
/**
* @ORM\Column(type="string", length=100)
* @Assert\NotBlank(message="site.title.notBlank", groups={"edit"})
* @Assert\Length(max = "100", maxMessage = "site.title.maxLength", groups={"edit"})
*/
protected $title;
/**
* @ORM\Column(type="string", length=200)
* @Assert\NotBlank(message="site.longTitle.notBlank", groups={"edit"})
* @Assert\Length(max = "200", maxMessage = "site.longTitle.maxLength", groups={"edit"})
*/
protected $longTitle;
/**
* @ORM\Column(type="string", length=250, nullable=true)
* @Assert\Length(max = "250", maxMessage = "site.keywords.maxLength", groups={"edit"})
*/
protected $keywords;
/**
* @ORM\Column(type="string", length=500, nullable=true)
* @Assert\Length(max = "500", maxMessage = "site.description.maxLength", groups={"edit"})
*/
protected $description;
/**
* Set name
*
* @param string $name
* @return Site
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set title
*
* @param string $title
* @return Site
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set longTitle
*
* @param string $longTitle
* @return Site
*/
public function setLongTitle($longTitle)
{
$this->longTitle = $longTitle;
return $this;
}
/**
* Get longTitle
*
* @return string
*/
public function getLongTitle()
{
return $this->longTitle;
}
/**
* Set keywords
*
* @param string $keywords
* @return Site
*/
public function setKeywords($keywords)
{
$this->keywords = $keywords;
return $this;
}
/**
* Get keywords
*
* @return string
*/
public function getKeywords()
{
return $this->keywords;
}
/**
* Set description
*
* @param string $description
* @return Site
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
}
请您参考如下方法:
长话短说:
作为(可能很脏的)解决方法,使用
{{ item.getName }}
在你的 Twig 模板中而不是
{{ item.name }}
解释:
我遇到了同样的问题,我认为当与 Twig 一起使用时,这应该被视为 Knp DoctrineBehaviors 文档中的错误。当您在 Twig 模板中调用它时:
{{ item.name }}
这就是 Twig 在幕后获取 name
属性所做的事情:
- 尝试获取
item
对象的name
公共(public)属性 - 如果没有找到,检查
item
对象的name
公共(public)方法 - 如果没有找到,检查“item”对象的
getName()
公共(public)方法 - 如果没有找到,检查
__call()
魔术方法(并使用name
参数调用它)
这里的问题是第 4 步。您定义的魔法 __call()
方法(如官方 DoctrineBehaviors 文档所推荐的那样)是使用 name
参数而不是获取名称
。然后它会调用 proxyCurrentLocaleTranslation()
方法,该方法会尝试调用翻译类的 name
公共(public)方法。当然,它不存在,因为您只有一个 getName()
方法。
在 Twig 中查看此问题:https://github.com/twigphp/Twig/issues/342
通过直接使用 Twig 中的 {{ item.getName }}
代码,将调用正确的方法名称。