简体   繁体   English

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

[英]Embed a Collection of Forms Error: Could not determine access type for property

I am trying to embed collection of Tag forms to Service form, according to this tutorial .根据本教程,我正在尝试将Tag表单集合嵌入到Service表单中。 Tag and Service entities have many-to-many relationship. TagService实体具有多对多关系。

Form is rendering correctly.表单呈现正确。 But when I submit form, I get但是当我提交表单时,我得到

Could not determine access type for property "tagList"无法确定属性“tagList”的访问类型

error.错误。 I don't understand why new Tag object is not added to the Service class by calling the addTag() method.我不明白为什么没有通过调用addTag()方法将新的Tag对象添加到Service类中。

ServiceType服务类型

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
    )));
}

Service class服务类

{
....
 /**
 * @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;
}
}

Tag class标签类

 {
  /**
 * @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(),
    ));
}

Could you please try to implement code from this URL?你能尝试从这个 URL 实现代码吗?

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

First, please try to change mapped/inverse sides, and remove $service->addTag($this);首先,请尝试更改映射/ $service->addTag($this); ,并删除$service->addTag($this); from Tag::addService method.来自Tag::addService方法。

Short version:精简版:

I just ran into this problem and solved it by adding a setter for the affected property:我刚刚遇到了这个问题,并通过为受影响的属性添加一个 setter 来解决它:

Could not determine access type for property "tagList"无法确定属性“tagList”的访问类型

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

Long version:长版:

The error message is signaling that Symfony is trying to modify the object's state, but cannot figure out how to actually make the change due to the way its class is set up.该错误消息表明 Symfony 正在尝试修改对象的状态,但由于其类的设置方式,无法弄清楚如何实际进行更改。

Taking a look at Symfony's internals , we can see that Symfony gives you 5 chances to give it access and picks the best one in this order from top to bottom: 看一看 Symfony 的内部结构,我们可以看到 Symfony 给了你 5 次访问的机会,并按照这个顺序从上到下挑选最好的一个:

  1. A setter method named setProperty() with one argument:一个名为setProperty() setter 方法,带有一个参数:

This is the first thing Symfony checks for and is the most explicit way to achieve this.这是 Symfony 检查的第一件事,也是实现这一目标的最明确的方式。 As far as I'm aware this is the best practice:据我所知,这是最佳做法:

class Entity {

    protected $tagList;

    //...

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

    //...
}
  1. A combined getter and setter in one method with one argument:一个方法中的组合 getter 和 setter,带有一个参数:

It's important to realize that this method will also be accessed by Symfony in order to get the object's state.重要的是要意识到这个方法也将被 Symfony 访问以获取对象的状态。 Since those method calls don't include an argument, the argument in this method must be optional.由于这些方法调用不包含参数,因此此方法中的参数必须是可选的。

class Entity {

    protected $tagList;

    //...

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

    //...
}
  1. The affected property being declared as public:受影响的财产被宣布为公共:

     class Entity { public $tagList; //... other properties here }
  2. A __set magic method: __set魔法方法:

This will affect all properties rather than just the one you intended.这将影响所有属性,而不仅仅是您想要的属性。

class Entity {

    public $tagList;

    //...

    public function __set($name, $value){
        $this->$name = $value;
    }
    //...
}
  1. A __call magic method (in some cases): __call魔术方法(在某些情况下):

I wasn't able to confirm this, but the internal code suggests this is possible when magic is enabled on PropertyAccessor's construction.我无法确认这一点,但内部代码表明,当在 PropertyAccessor 的构造上启用magic时,这是可能的。


Only using one of the above strategies is required.只需要使用上述策略之一。

Maybe the problem is that Symfony can't access that property?也许问题是 Symfony 无法访问该属性?

If you look at where that exception is thrown (writeProperty method in the PropertyAccessor class) it says it can be thrown:如果您查看抛出异常的位置(PropertyAccessor 类中的 writeProperty 方法),它会说它可以抛出:

If the property does not exist or is not public.如果该属性不存在或不公开。

In the tutorial you mentioned it has property $tags, and method addTag.在您提到的教程中,它具有属性 $tags 和方法 addTag。 I'm just guessing here, but maybe there's a convention where it tries to call a method names add($singularForm) and this is failing for you because the property is tagList and the method is addTag .我只是在这里猜测,但也许有一个约定,它尝试调用方法名称add($singularForm)并且这对您来说失败了,因为属性是tagList而方法是addTag

I'm not 100% sure, but you could try debugging by setting a stop point in that Symfony method to see why it's being thrown.我不是 100% 确定,但是您可以通过在该 Symfony 方法中设置停止点来尝试调试,以查看它被抛出的原因。

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

$this->tagList = new ArrayCollection();

$this->serviceList = new ArrayCollection();

This seems like an error with your constructor.这似乎是您的构造函数的错误。 Try this :尝试这个 :

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

It's a long shot, but looking at your annotations I think the problem might be related to your manyToMany relationship.这是一个远景,但查看您的注释,我认为问题可能与您的多对多关系有关。 Try to change the owning side and inverse side (Swap the relationship) unless you specifically need to update from both ends (In that case I think the only solution is to add the objects manually or use oneToMany relationships).尝试更改拥有方和反向方(交换关系),除非您特别需要从两端更新(在这种情况下,我认为唯一的解决方案是手动添加对象或使用 oneToMany 关系)。

Changes made only to the inverse side of an association are ignored.仅对关联的反面所做的更改将被忽略。 Make sure to update both sides of a bidirectional association (or at least the owning side, from Doctrine's point of view)确保更新双向关联的双方(或至少是拥有方,从 Doctrine 的角度来看)

This is a problem related to Doctrine I have suffered before, see: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html这是我之前遇到的与 Doctrine 相关的问题,请参阅: http : //docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html

Based on Symfony 3.3.10基于 Symfony 3.3.10

I actually faced this problem many and many times, finally once i discovered where this problem was coming from, depending on the name you give to your entity property it can happen that the adder and the remover for your collection property aren't exactly what you are expecting.我实际上多次遇到过这个问题,最后,一旦我发现了这个问题的来源,根据您给实体属性的名称,可能会发生您的集合属性的加法器移除与您不完全相同正在期待。

Example: Your entity properity name is "foo" and you would expect the adder to be called "addFoo" and remover "removeFoo", but then all of a sudden the "Could not determine access type for property" appear.示例:您的实体属性名称是“foo”,并且您希望加法器被称为“addFoo”,移除器被称为“removeFoo”,但是突然出现“无法确定属性的访问类型”

So you start going into fear searching for w/e problems in your code, instead you just have to look this file inside Symfony core files:所以你开始害怕在你的代码中搜索 w/e 问题,而你只需要在 Symfony 核心文件中查看这个文件:

vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php供应商/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Inside this file there's a method called findAdderAndRemover .在这个文件中有一个叫做findAdderAndRemover的方法。 Go there with your debugger and you will eventually find out that symfony searches for weird name for your adder/remover, they may actually end with "um" or "on" or "us" depending on the language (human language) you used to name them.和你的调试器一起去那里,你最终会发现 symfony 为你的加法器/去除器搜索奇怪的名字,它们实际上可能以“嗯”或“开”或“我们”结尾,这取决于你曾经使用的语言(人类语言)命名它们。 Since i'm Italian this happen quite often.因为我是意大利人,这种情况经常发生。

Watch out for that, since the fix may be as simple as changing the name used for your add/remove method inside your entity to make them match with what Symfony core is looking for.请注意这一点,因为修复可能就像更改实体中用于添加/删除方法的名称一样简单,以使它们与 Symfony 核心正在寻找的内容相匹配。

This happens to me when i use bin/console doctrine:generate:entities to create the methods automatically for me当我使用bin/console 原则:生成:实体为我自动创建方法时,这发生在我身上

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM