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

Posted

技术标签:

【中文标题】嵌入表单集合错误:无法确定属性的访问类型【英文标题】:Embed a Collection of Forms Error: Could not determine access type for property 【发布时间】:2017-07-03 22:55:06 【问题描述】:

根据this tutorial,我正在尝试将Tag 表单的集合嵌入Service 表单。 TagService 实体具有多对多关系。

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

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

错误。我不明白为什么没有通过调用addTag() 方法将新的Tag 对象添加到Service 类中。

服务类型

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;

 

服务控制器

  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(),
    ));

【问题讨论】:

***.com/questions/41213014/… 这是导致错误的失败测试,​​也许理解它会有所帮助:github.com/symfony/property-access/blob/master/Tests/… @craigh 如果我这样做mapped => false 我将无法编辑tagList,因为它会写入,但不会读取值 【参考方案1】:

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

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

如果属性不存在或不公开。

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

我不能 100% 确定,但是您可以尝试通过在 Symfony 方法中设置停止点来进行调试,以查看它被抛出的原因。

【讨论】:

【参考方案2】:

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

$this->tagList = new ArrayCollection();

$this->serviceList = new ArrayCollection();

【讨论】:

您好!不,我没有忘记在类构造函数中初始化标签和服务列表【参考方案3】:

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

public function __construct()

    $this-> tagList = new \Doctrine\Common\Collections\ArrayCollection();

【讨论】:

您好!不,我没有忘记将类构造函数中的标记和服务列表初始化为 ArrayCollection()【参考方案4】:

您能否尝试从该 URL 实现代码?

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

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

【讨论】:

【参考方案5】:

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

仅对关联的反面所做的更改将被忽略。 确保更新双向关联的双方(或在 从 Doctrine 的角度来看,至少是拥有方)

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

【讨论】:

【参考方案6】:

短版:

我刚刚遇到了这个问题,并通过为受影响的属性添加一个 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;
    

    //...

    一种方法中的组合 getter 和 setter,只有一个参数:

重要的是要意识到这个方法也将被 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 时,这是可能的。


只需要使用上述策略之一。

【讨论】:

我有一个多对多的教授-teacherAssistants,如果我只选择一个,表单会发送对象而不是数组,所以我做了这个 public function setProfessors($professors) if(gettype( $professors) == "object") $this->professors = new ArrayCollection(); $this->addTeacherAsistant($professors); 其他 $this->professors = $professors; 【参考方案7】:

基于 Symfony 3.3.10

我实际上多次遇到这个问题,最后一旦我发现这个问题来自哪里,根据你给实体属性的名称,加法器和remover 与您的收藏属性不完全一样。

示例:您的实体属性名称是“foo”,您希望添加器被称为“addFoo”和移除器“removeFoo”,但突然之间“无法确定属性的访问类型” 出现。

所以你开始害怕在你的代码中搜索 w/e 问题,而你只需要在 Symfony 核心文件中查看这个文件:

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

在这个文件中有一个名为 findAdderAndRemover 的方法。 用你的调试器去那里,你最终会发现 symfony 为你的加法器/删除器搜索奇怪的名字,它们实际上可能以 "um" 或 "on" 或 "us" 结尾,具体取决于语言(人类语言)你用来命名它们。由于我是意大利人,这种情况经常发生。

请注意这一点,因为修复可能很简单,只需更改实体中用于添加/删除方法的名称,以使它们与 Symfony 核心正在寻找的匹配。

当我使用 bin/console dictionary:generate:entities 自动为我创建方法时,我会遇到这种情况

【讨论】:

【参考方案8】:

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

【讨论】:

以上是关于嵌入表单集合错误:无法确定属性的访问类型的主要内容,如果未能解决你的问题,请参考以下文章

nodejs/mongoDB - 类型错误:无法读取未定义的属性“集合”

访问视图中的嵌套表单字段(嵌入表单集合)

Symfony 渲染一个集合表单类型原型

Ef core LazyLoading - 访问集合类型的嵌套导航属性引发 DetachedLazyLoadingWarning 错误

Ef核心LazyLoading - 类型集合的访问嵌套导航属性抛出DetachedLazyLoadingWarning错误

从 Symfony2 中的控制器访问集合表单字段