根据Tag
,我试图将Service
形式的集合嵌入this tutorial形式。 Tag
和Service
实体有多对多的关系。
表单正确呈现。但是当我提交表格时,我得到了
无法确定属性“tagList”的访问类型
错误。我不明白为什么新的Tag
对象没有通过调用Service
方法添加到addTag()
类。
服务类型
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, array(
'label' => 'Title'
))
;
$builder->add('tagList', CollectionType::class, array(
'entry_type' => TagType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
)));
}
服务类
{
....
/**
* @ORM\ManyToMany(targetEntity="Tag", mappedBy="serviceList",cascade={"persist"})
*/
private $tagList;
/**
* @return ArrayCollection
*/
public function getTagList()
{
return $this->tagList;
}
/**
* @param Tag $tag
* @return Service
*/
public function addTag(Tag $tag)
{
if ($this->tagList->contains($tag) == false) {
$this->tagList->add($tag);
$tag->addService($this);
}
}
/**
* @param Tag $tag
* @return Service
*/
public function removeTag(Tag $tag)
{
if ($this->tagList->contains($tag)) {
$this->tagList->removeElement($tag);
$tag->removeService($this);
}
return $this;
}
}
标签类
{
/**
* @ORM\ManyToMany(targetEntity="Service", inversedBy="tagList")
* @ORM\JoinTable(name="tags_services")
*/
private $serviceList;
/**
* @param Service $service
* @return Tag
*/
public function addService(Service $service)
{
if ($this->serviceList->contains($service) == false) {
$this->serviceList->add($service);
$service->addTag($this);
}
return $this;
}
/**
* @param Service $service
* @return Tag
*/
public function removeService(Service $service)
{
if ($this->serviceList->contains($service)) {
$this->serviceList->removeElement($service);
$service->removeTag($this);
}
return $this;
}
}
的ServiceController
public function newAction(Request $request)
{
$service = new Service();
$form = $this->createForm('AppBundle\Form\ServiceType', $service);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($service);
$em->flush();
return $this->redirectToRoute('service_show', array('id' => $service->getId()));
}
return $this->render('AppBundle:Service:new.html.twig', array(
'service' => $service,
'form' => $form->createView(),
));
}
您可以尝试从此网址实施代码吗?
首先,请尝试更改映射/反向边,并从$service->addTag($this);
方法中删除Tag::addService
。
也许问题是Symfony无法访问该属性?
如果你看一下抛出异常的位置(PropertyAccessor类中的writeProperty方法),它会说它可以被抛出:
如果财产不存在或不公开。
在你提到的教程中,它有属性$ tags和方法addTag。我只是在这里猜测,但也许有一个惯例,它试图调用方法名称add($singularForm)
,这对你来说是失败的,因为属性是tagList
,方法是addTag
。
我不是百分百肯定,但您可以通过在Symfony方法中设置停止点来尝试调试,以查看它被抛出的原因。
精简版:
我刚遇到这个问题并通过为受影响的属性添加一个setter来解决它:
无法确定属性“tagList”的访问类型
public function setTagList(Array $tagList)
{
$this->tagList = $tagList;
}
长版:
错误消息表明Symfony正在尝试修改对象的状态,但由于其类的设置方式无法弄清楚如何实际进行更改。
Taking a look at Symfony's internals,我们可以看到Symfony为您提供了5次机会,可以从上到下按顺序选择最佳的:
setProperty()
的setter方法,带有一个参数:这是Symfony检查的第一件事,也是实现这一目标的最明确的方法。据我所知,这是最好的做法:
class Entity {
protected $tagList;
//...
public function getTagList()
{
return $this->tagList;
}
//...
}
重要的是要意识到Symfony也将访问此方法以获取对象的状态。由于这些方法调用不包含参数,因此此方法中的参数必须是可选的。
class Entity {
protected $tagList;
//...
public function tagList($tags = null)
{
if($reps){
$this->tagList = $tags;
} else {
return $this->tagList;
}
}
//...
}
class Entity {
public $tagList;
//... other properties here
}
__set
魔法:这将影响所有属性,而不仅仅是您想要的属性。
class Entity {
public $tagList;
//...
public function __set($name, $value){
$this->$name = $value;
}
//...
}
__call
魔法(在某些情况下):我无法确认这一点,但内部代码表明,当在PropertyAccessor的构造上启用magic
时,这是可能的。
只需使用上述策略之一即可。
也许你忘了在Service类和Tag类的__construct()
中初始化$ tagList和$ serviceList这样?
$this->tagList = new ArrayCollection();
$this->serviceList = new ArrayCollection();
这似乎是构造函数的错误。试试这个 :
public function __construct()
{
$this-> tagList = new \Doctrine\Common\Collections\ArrayCollection();
}
这是一个很长的镜头,但看着你的注释我认为问题可能与你的manyToMany关系有关。尝试更改拥有方和反方(交换关系),除非您特别需要从两端更新(在这种情况下,我认为唯一的解决方案是手动添加对象或使用oneToMany关系)。
仅忽略关联的反面更改。确保更新双向关联的两面(或者至少从拥有者的角度来看,从Doctrine的角度来看)
这是一个与我之前遇到过的学说相关的问题,请参阅:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html
基于Symfony 3.3.10
我实际上遇到过这个问题很多次,最后一旦我发现这个问题来自哪里,取决于你给你的实体属性的名称,你的收集属性的加法器和移除器可能不是你期待着。
示例:您的实体专有名称是“foo”,您可能希望将加法器称为“addFoo”并卸载“removeFoo”,但突然之间出现“无法确定属性的访问类型”。
因此,您开始担心在代码中搜索w / e问题,而只需在Symfony核心文件中查看此文件:
供应商/ symfony的/ symfony的/ SRC / Symfony的/组件/ PropertyAccess / PropertyAccessor.php
在这个文件里面有一个名为findAdderAndRemover的方法。用你的调试器去那里,你最终会发现symfony为你的加法器/去除器搜索奇怪的名字,它们实际上可能以“um”或“on”或“us”结尾,具体取决于你以前使用的语言(人类语言)命名他们。由于我是意大利人,这种情况经常发生。
请注意这一点,因为修复可能就像更改实体中用于添加/删除方法的名称一样简单,以使它们与Symfony核心所寻找的匹配。
当我使用bin / console doctrine:generate:entities为我自动创建方法时,就会发生这种情况
如果您正在使用symfony,并使用EntityRepository而不是CollectionType,请确保在表单构建中使用'multiple' => true,
,否则输入将用于一个实体而不是多个,因此它将调用setTagList
而不是使用方法addTagList
和removeTagList
。