我想为实体创建一个表单,该表单包含同一实体的两个集合,但每个集合在一个属性中保存具有特定值的权限。
我的数据库表如下所示:
Table 1: base
| id | foo | bar |
|----|-----|-----|
Table 2: extended
| id | table_1_id | type | baz |
|----|------------|------|-----|
表1和表2采用1:n关系,因此“基础”实体可以容纳任意数量的“扩展”实体。
我已经定义了实体:
class Base {
private $id;
private $foo;
private $baz;
private $extendedCollection;
/*...*/
public function getTypeA() {
$result = new ArrayCollection();
foreach ($extendedCollection->toArray() as $item) {
if ($item->getType() == "A") {
$result->add($item);
}
}
return $result;
}
/* respective for type "B" */
public function addExtendedA(Extended $a) {
if (!$this->extendedCollection->contains($a)) {
$a
->setBase($this)
->setType("A");
$this->extendedCollection->add($a);
}
return $this;
}
/* respective for type "B" */
}
class Extended {
private $id;
private $base;
private $type;
private $baz;
/*...*/
}
最后,我还创建了两个表单类:
class BaseType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('foo')
->add('bar')
->add('typeA', CollectionType::class, array(
'entry_type' => ExtendedType::class,
'entry_options' => array(
'type' => "A"
),
'allow_add' => true,
'allow_delete' => true,
'required' => false,
'by_reference' => false
)
->add('typeB', CollectionType::class, array(
'entry_type' => ExtendedType::class,
'entry_options' => array(
'type' => "B"
),
'allow_add' => true,
'allow_delete' => true,
'required' => false,
'by_reference' => false
);
/*...*/
}
}
class ExtendedType extends AbstractType {
private $type;
public function buildForm(FormBuilderInterface $builder, array $options) {
$this->type = $options['type'];`enter code here`
$builder
->add('type', HiddenType::class, array(
'data' => $this->type
)
->add('baz');
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => Extended::class,
'type' => ""
));
}
}
期望的结果如下: 当请求“Base”实体时,数据库内容被解析为实体,并且“Extended”实体的ArrayCollection按照集合项的类型被分类为两个集合“A”和“B”,并且两个集合作为单独的表单列表呈现。 这有效。
当更新“Base”实体时,两个“Extended”集合都应该融合到新的extendedCollection中,并且该实体应该被持久化。 这不起作用。
如果我手动将一些扩展行添加到数据库中,我可以呈现模板并显示所有内容 - 但是,当我尝试通过HTML表单应用某些更改时,会抛出NoSuchPropertyException
,其中包含消息Could not determine access type for "typeA"
说。我到底错过了什么?我可以做些什么来优化这个模型吗?
更新 14.09.2017 我添加了一个setter函数来应用新的“扩展”集合:
class Base {
/* see above for reference code */
public function setTypeACollection(ArrayCollection $typeAExtended)
{
$this->setExtendedCollection($typeAExtended, "A");
return $this;
}
/* Respective for type "B" */
private function setExtendedCollection(ArrayCollection $newExtended, $type)
{
$newExtendedCollection = new ArrayCollection();
$extendedArray = $this->extendedCollection->toArray();
foreach ($extendedArray as $k => $v) {
if ($v->getType() == $type) {
unset($extendedArray[$k]);
} else {
$newExtendedCollection->add($v);
}
}
foreach ($newExtended->toArray() as $newExt) {
$newExt->setType($type);
$newExtendedCollection->add($item);
}
$this->extendedCollection = $newExtendedCollection;
}
}
现在,NoSuchPropertyException
已消失,但新问题仍然存在:
当我从数据库加载Base实体时,扩展集合应用得很干净,但是通过HTML表单更新实体会导致以下错误,具体取决于是否有更改:
ORMInvalidArgumentException
,消息为A new entity was found through the relationship 'Acme\Bundle\Entity\Base#extendedCollection' that was not configured to cascade persist operations for entity: Acme\Bundle\Entity\Extended@0000000011153bff000000006bb39f24. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Acme\Bundle\Entity\Extended#__toString()' to get a clue.
我的Extended
类在引用@ORM\ManyToOne(targetEntity="Acme\Bundle\Entity\Base", inversedBy="extendedCollection", cascade={"persist"})
属性中包含注释$base
。
答案 0 :(得分:1)
表单字段是从表单的基础对象/类映射的,因此当表单组件尝试映射提交时,Could not determine access type for "typeA"
引用typeA
类中的遗漏属性Base
这个属性的价值。
尝试解决此问题,在setTypeA(Collection $items)
课程中添加Base
方法,并根据extendedCollection
手动更新type
属性。