嵌入表单集合错误:无法确定属性的访问类型
Posted
技术标签:
【中文标题】嵌入表单集合错误:无法确定属性的访问类型【英文标题】:Embed a Collection of Forms Error: Could not determine access type for property 【发布时间】:2017-07-03 22:55:06 【问题描述】:根据this tutorial,我正在尝试将Tag
表单的集合嵌入Service
表单。 Tag
和 Service
实体具有多对多关系。
表单正在正确呈现。但是当我提交表单时,我得到了
无法确定属性“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
而不是使用addTagList
和removeTagList
方法。
【讨论】:
以上是关于嵌入表单集合错误:无法确定属性的访问类型的主要内容,如果未能解决你的问题,请参考以下文章
nodejs/mongoDB - 类型错误:无法读取未定义的属性“集合”
Ef core LazyLoading - 访问集合类型的嵌套导航属性引发 DetachedLazyLoadingWarning 错误
Ef核心LazyLoading - 类型集合的访问嵌套导航属性抛出DetachedLazyLoadingWarning错误