Symfony 3 - 具有相同实体

时间:2017-09-13 14:28:25

标签: php forms symfony doctrine-orm entity

我想为实体创建一个表单,该表单包含同一实体的两个集合,但每个集合在一个属性中保存具有特定值的权限。

我的数据库表如下所示:

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表单更新实体会导致以下错误,具体取决于是否有更改:

  • 无变化:实体以错误的方式更新,因为所有类型“B”都变为“A”类型,因此全部显示在“A”类型的集合中。
  • 删除类型“B”:删除的类型“B”将变为“A”类型,而不是被删除。
  • 删除类型“A”:已删除的延期保留,此外所有类型“B”都变为“A”类型。
  • 添加类型“A”:添加的扩展名不会保留,此外所有类型“B”都会变为“A”类型。
  • 添加“B”类型:抛出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

1 个答案:

答案 0 :(得分:1)

表单字段是从表单的基础对象/类映射的,因此当表单组件尝试映射提交时,Could not determine access type for "typeA"引用typeA类中的遗漏属性Base这个属性的价值。

尝试解决此问题,在setTypeA(Collection $items)课程中添加Base方法,并根据extendedCollection手动更新type属性。