Symfony 表单:如何在 Doctrine 实体中包含实体本身使用的可嵌入 Doctrine 的表单

Symfony forms: how to include in the Doctrine entity form a form for a Doctrine embeddable used by the entity itself

我有一个使用 Doctrine embeddable 的学说 Entity

我想创建一个表单来编辑 EntityEmbeddable

我的Entity:

/**
 * MyEntity
 *
 * @ORM\Table(name="my_entities")
 * @ORM\Entity(repositoryClass="\AppBundle\Entity\MyEntityRepository")
 * @ORM\HasLifecycleCallbacks
 */
class MyEntity
{
    ...

    /**
     * @var MyEmbeddableInfo
     *
     * @ORM\Embedded(class="AppBundle\Entity\Embeddable\MyInfoEmbeddable")
     */
    private $myInfo;

    ...

我的Embeddable:

/**
 * @ORM\Embeddable
 */
class MyInfoEmbeddable
{
    /**
     * @var string
     *
     * @ORM\Column(name="info1", type="string", nullable=true)
     *
     * @Assert\NotBlank(groups={"setUp"})
     */
    private $info1;

    /**
     * @var string
     *
     * @ORM\Column(name="info2", type="string", nullable=true)
     *
     * @Assert\NotBlank(groups={"setUp"})
     */
    private $info2;

    /**
     * @var
     *
     * @ORM\Column(name="info3", type="string", nullable=true)
     *
     * @Assert\NotBlank(groups={"setUp"})
     */
    private $info3;

    ...

我尝试了什么

我发现了这个 question here on Whosebug 似乎用户遇到了我同样的问题,但不同的是我从来没有得到 Warning 因为我根本不了解创建可嵌入对象的形式。

我进行了两项测试:一项是将可嵌入对象直接传递给 MyEntityType 表单生成器,一项是创建 MyInfoType() 表单类型。

测试 1:直接传递可嵌入对象

这是我的代码 MyEntityTypeclass:

class MyEntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ...
            ->add('myInfo', 'entity', ['class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable'])
            ...
    }

    public function getName()
    {
        return 'MyEntity';
    }
}

此解决方案抛出 RuntimeException:

Class \AppBundle\Entity\Embeddable\MyInfoEmbeddable seems not to be a managed Doctrine entity. Did you forget to map it?

测试 2:通过 MyInfoType 对象

我做的第二个测试是使用表单类型(如 linked SO question 中所建议的):

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ...
            ->add('myInfo', new MyInfoType())
            ...
    }

这是MyInfoType的代码:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('infoField1', 'text', ['required' => false])
        ->add('infoField2', 'text', ['required' => false])
        ->add('infoField3', 'choice', [
                'choices'   => [
                    '' => '',
                    'choice1' => 'Choice 1',
                    'choice2' => 'Choice 2',
                    'choice3' => 'Choice 3'
                ],
                'required' => false
            ]
        );
}

这个 returns Symfony\Component\PropertyAccess\Exception\NoSuchIndexException:

Cannot read index infoField1 from object of type AppBundle\Entity\Embeddable\MyInfoEmbeddable because it doesn't implement \ArrayAccess.

所以,这个解决方案也行不通。

我的目标是为 MyEntity 创建一个表单,并在该表单中创建要更新的字段 MyInfoEmbeddable

正确的步骤是什么?

在使用不同 keywords 进行了一些其他搜索后,我想出了 this answer here on SO 帮助我解决了问题。

我真的很接近解决方案。我只是省略了构建表单所需的参数。

解决方法是将data_class参数传递给FormBuilderadd()方法:

...
$builder
    ->add('myInfo', new MyInfoType(), ['data_class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable'])
...

而不是在你的主表单中这样:

$builder->add('myInfo', new MyInfoType(), 
['data_class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable'])

您可以将此添加到您的 MyInfoType 表单中(我相信它与可嵌入实体链接):

public function configureOptions(OptionsResolver $resolver)
{
   $resolver->setDefaults([
      'data_class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable',
   ]);
}

然后在您的主表单中简单地调用可嵌入表单类型,如下所示:

$builder->add('myInfo', new MyInfoType())