我使用 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('&nbsp;', ENT_QUOTES, 'UTF-8'), 
        ($this->getLvl()) * 3 
    ) . $this->getName(); 
} 
public function getLeveledPosition() 
{ 
    return str_repeat( 
        html_entity_decode('&nbsp;', 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 属性所做的事情:

  1. 尝试获取item对象的name公共(public)属性
  2. 如果没有找到,检查 item 对象的 name 公共(public)方法
  3. 如果没有找到,检查“item”对象的getName()公共(public)方法
  4. 如果没有找到,检查 __call() 魔术方法(并使用 name 参数调用它)

这里的问题是第 4 步。您定义的魔法 __call() 方法(如官方 DoctrineBehaviors 文档所推荐的那样)是使用 name 参数而不是获取名称。然后它会调用 proxyCurrentLocaleTranslation() 方法,该方法会尝试调用翻译类的 name 公共(public)方法。当然,它不存在,因为您只有一个 getName() 方法。

在 Twig 中查看此问题:https://github.com/twigphp/Twig/issues/342

通过直接使用 Twig 中的 {{ item.getName }} 代码,将调用正确的方法名称。


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!