嵌入表单集合错误:无法确定属性的访问类型

问题描述 投票:19回答:8

根据Tag,我试图将Service形式的集合嵌入this tutorial形式。 TagService实体有多对多的关系。

表单正确呈现。但是当我提交表格时,我得到了

无法确定属性“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(),
    ));
}
doctrine-orm symfony symfony-forms
8个回答
4
投票

您可以尝试从此网址实施代码吗?

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#owning-and-inverse-side-on-a-manytomany-association

首先,请尝试更改映射/反向边,并从$service->addTag($this);方法中删除Tag::addService


2
投票

也许问题是Symfony无法访问该属性?

如果你看一下抛出异常的位置(PropertyAccessor类中的writeProperty方法),它会说它可以被抛出:

如果财产不存在或不公开。

在你提到的教程中,它有属性$ tags和方法addTag。我只是在这里猜测,但也许有一个惯例,它试图调用方法名称add($singularForm),这对你来说是失败的,因为属性是tagList,方法是addTag

我不是百分百肯定,但您可以通过在Symfony方法中设置停止点来尝试调试,以查看它被抛出的原因。


2
投票

精简版:

我刚遇到这个问题并通过为受影响的属性添加一个setter来解决它:

无法确定属性“tagList”的访问类型

public function setTagList(Array $tagList)
{
    $this->tagList = $tagList;
}

长版:

错误消息表明Symfony正在尝试修改对象的状态,但由于其类的设置方式无法弄清楚如何实际进行更改。

Taking a look at Symfony's internals,我们可以看到Symfony为您提供了5次机会,可以从上到下按顺序选择最佳的:

  1. 一个名为setProperty()的setter方法,带有一个参数:

这是Symfony检查的第一件事,也是实现这一目标的最明确的方法。据我所知,这是最好的做法:

class Entity {

    protected $tagList;

    //...

    public function getTagList()
    {
        return $this->tagList;
    }

    //...
}
  1. 在一个方法中使用一个参数组合的getter和setter:

重要的是要意识到Symfony也将访问此方法以获取对象的状态。由于这些方法调用不包含参数,因此此方法中的参数必须是可选的。

class Entity {

    protected $tagList;

    //...

    public function tagList($tags = null)
    {
        if($reps){
            $this->tagList = $tags;
        } else {
            return $this->tagList;
        }
    }

    //...
}
  1. 受影响的财产被宣布为公共: class Entity { public $tagList; //... other properties here }
  2. 一个__set魔法:

这将影响所有属性,而不仅仅是您想要的属性。

class Entity {

    public $tagList;

    //...

    public function __set($name, $value){
        $this->$name = $value;
    }
    //...
}
  1. 一种__call魔法(在某些情况下):

我无法确认这一点,但内部代码表明,当在PropertyAccessor的构造上启用magic时,这是可能的。


只需使用上述策略之一即可。


1
投票

也许你忘了在Service类和Tag类的__construct()中初始化$ tagList和$ serviceList这样?

$this->tagList = new ArrayCollection();

$this->serviceList = new ArrayCollection();


1
投票

这似乎是构造函数的错误。试试这个 :

public function __construct()
{
    $this-> tagList = new \Doctrine\Common\Collections\ArrayCollection();
}

1
投票

这是一个很长的镜头,但看着你的注释我认为问题可能与你的manyToMany关系有关。尝试更改拥有方和反方(交换关系),除非您特别需要从两端更新(在这种情况下,我认为唯一的解决方案是手动添加对象或使用oneToMany关系)。

仅忽略关联的反面更改。确保更新双向关联的两面(或者至少从拥有者的角度来看,从Doctrine的角度来看)

这是一个与我之前遇到过的学说相关的问题,请参阅:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html


0
投票

基于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为我自动创建方法时,就会发生这种情况


0
投票

如果您正在使用symfony,并使用EntityRepository而不是CollectionType,请确保在表单构建中使用'multiple' => true,,否则输入将用于一个实体而不是多个,因此它将调用setTagList而不是使用方法addTagListremoveTagList

© www.soinside.com 2019 - 2024. All rights reserved.