Knp DoctrineBehaviors抛出ContextErrorException:警告:call_user_func_array()期望参数1是有效的回调

时间:2014-02-16 20:28:35

标签: symfony doctrine twig translation

我使用symfony2.4和KNP教义行为可翻译。

我有实体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,主机和已启用字段,这很容易:

{{ item.id }}

但是我无法打印翻译的字段(名称,描述,......)

{{ item.name }}

它不起作用。

错误讯息:

  

ContextErrorException:警告:call_user_func_array()期望参数1是有效的>回调,类'Net \ ConBundle \ Entity \ SiteTranslation'在> D:\ Users ...中没有方法'name' vendor \ knplabs \ doctrine-> behavior \ src \ Knp \ DoctrineBehaviors \ Model \ Translatable \ TranslatableMethods.php第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;
}
}

3 个答案:

答案 0 :(得分:5)

<强> TL; DR:

作为(可能是脏的)解决方法,请使用

{{ item.getName }}
在您的Twig模板中

而不是

{{ item.name }}

<强>解释

我遇到了同样的问题,我认为在与Twig一起使用时,这应该被认为是Knp DoctrineBehaviors文档中的一个错误。当你在Twig模板中调用它时:

{{ item.name }}

这是Twig在幕后获取name属性的原因:

  1. 尝试获取name对象
  2. item公共属性
  3. 如果找不到,请检查name对象的item公共方法
  4. 如果找不到,请检查&#34;项目&#34;的getName()公共方法。对象
  5. 如果找不到,请检查__call()魔术方法(并使用name参数调用它)
  6. 此处的问题是第4步。您定义的神奇__call()方法(正如DoctrineBehaviors官方文档所推荐)使用name参数而不是getName进行调用。然后,它会调用尝试调用翻译课程的proxyCurrentLocaleTranslation()公共方法的name方法。当然,它不存在,因为你只有getName()方法。

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

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

答案 1 :(得分:2)

这项工作对我来说:

public function __call($method, $arguments)
{
    try {
        return $this->proxyCurrentLocaleTranslation($method, $arguments);
    } catch (\Symfony\Component\Debug\Exception\ContextErrorException $e) {
        return $this->proxyCurrentLocaleTranslation('get' . ucfirst($method), $arguments);
    }

}

答案 2 :(得分:0)

您尚未将所有可翻译属性/方法移至<Name>Translation类。

该异常明确指出您的SiteTranslation类中没有name / getName方法。

请阅读my answer over here,了解如何正确使用Knp \ DoctrineBehaviors的魔术翻译代理。