Symfony 3:基于Traits构建实体表单。

3

我在用特性构建实体时遇到了困难,无法为这些实体构建表单。

例如,我的“文章”实体只包含类别链接和2张图片,其余属性位于SeoTrait(标题、meta_title、meta_desc、content等)和ValidTrait(isValid true/false)中,我希望将其用于其他实体。

对于Doctrine来说,这一切都很好,它会为使用这些特性的每个实体生成包含特性字段的模式。但问题出现在表单上:

我已经为“SEO”属性创建了SeoTraitType:

class SeoTraitType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class, array(
                'label' => 'Nom'
            ))
            ->add('metaTitle', TextType::class, array(
                'label' => 'Meta Title'
            ))
            ->add('metaDescription', TextareaType::class, array(
                'label' => 'Meta Description'
            ))
            ->add('metaKeywords', TextType::class, array(
                'label' => 'Keywords'
            ))
            ->add('content', TextareaType::class, array(
                'label' => 'Content'
            ))
        ;
    }
}

然后我将其用于我的ArticleType中:

class ArticleType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('seo', SeoTraitType::class, array(
                'label' => 'Seo',
                'mapped' => false
            ))
            ->add('isValid',    ValidTraitType::class,      array(
                'label' => 'Valid',
                'mapped' => false
            ))
            ->add('save',       SubmitType::class,          array(
                'label' => 'form_save',
                'translation_domain' => 'back_default'
            ));
        ;
    }
}

我的问题是,当我想在主实体的表单中嵌入两个TraitTypes时,必须将mapped => false设置为这两个TraitTypes。然后在我的表单中,我使用article[seo][name]来获取SeoTrait的字段,因此我不能真正使用$form->handleRequest()方法来处理表单提交...如何解决这个问题?是否可以在表单组件提供的方法中以特殊方式处理它,还是我必须自己处理请求并解析trait数组以在保存实体之前构建它?我在互联网上找不到任何相关信息:(

Jean,你看过Symfony文章如何嵌入表单集合吗?我一直想写一篇关于这个的文章,因为文档不是很好。你可能可以通过嵌入表单来实现你需要的功能。需要花费一些时间来熟悉所有操作,所以我建议你先阅读这篇文章。 - Alvin Bunk
3
不要这样做。Symfony的表单组件内置了一种机制,用于重用表单。您可以通过在父表单中将“inherit_data”选项设置为“true”,轻松地重用/嵌套子表单提供一组字段,无需使用trait!与使用trait相比,使用嵌入式类型和“inherit_data”有多个好处-例如,嵌入表单的事件侦听器将继续工作。当使用trait时,良好的可测试性会受到损失。请尝试熟悉可嵌入的子表单类型和Doctrine Embeddables-有一种更清晰的方法来实现您的目标。 - Nicolai Fröhlich
我读了上面的文章,但它只谈到了嵌入相关实体的表单,无论是一个对象还是一组对象,这对我以后会有用,但我没有看到任何关于能够导入另一个表单而不需要它具有字段名称的内容,然后所有继承的字段都在该字段名称中...我将在周一重新查看它,谢谢大家! - Jb R.
nifr,你太棒了!https://symfony.com/doc/current/form/inherit_data_option.html 这正是我所需要的,而且它也完美地完成了工作! - Jb R.
2个回答

4

解决您的问题的一种方法是将类SeoTraitType转换为Trait

例如:

trait SeoTraitType
{
    public function buildSEOForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class, array(
                'label' => 'Nom'
            ))
            ->add('metaTitle', TextType::class, array(
                'label' => 'Meta Title'
            ))
            ->add('metaDescription', TextareaType::class, array(
                'label' => 'Meta Description'
            ))
            ->add('metaKeywords', TextType::class, array(
                'label' => 'Keywords'
            ))
            ->add('content', TextareaType::class, array(
                'label' => 'Content'
            ))
        ;
    }
}

然后:

class ArticleType extends AbstractType
{
    use SeoTraitType;

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $this->buildSEOForm($builder, $options);

        $builder
            ->add('isValid',    ValidTraitType::class,      array(
                'label' => 'Valid',
                'mapped' => false
            ))
            ->add('save',       SubmitType::class,          array(
                'label' => 'form_save',
                'translation_domain' => 'back_default'
            ));
        ;
    }
}

您也可以使用静态方法来完成此操作。个人不太喜欢Trait。

哇塞,你真是太厉害了!!非常感谢;)它完全做到了我想要的! - Jb R.
@JeanBaptisteRacoupeau 谢谢;-) 如果这对您有用,您可以接受这个问题。 - GiDo

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接