Symfony集合类型和类继承

5
我将翻译以下关于IT技术的内容:

我正在处理一个Symfony项目,由于我对这个框架不是很熟悉,所以我无法确定是否存在设计缺陷,是否Symfony无法处理我的使用情况,或者我只需要找到正确的方法。

这是它:

我有一个实体行,它应该包含1到n个具有不同内容(如“标题”,“文本”,“图像”等)的项目。

由于每个内容具有不同的特点,我通过单表继承从名为RowContent的抽象类扩展了每种内容类型。下面是实体的编辑版本:

类 Row
class Row
{
    //.....

    /**
     * @var ArrayCollection $rowContents
     *
     * @ORM\OneToMany(targetEntity="RowContent", mappedBy="row", cascade={"persist", "remove", "merge"})
     */
    private $rowContents;

    //...
}

类 RowContent:

/**
 * RowContent
 *
 * @ORM\Table(name="row_content")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({
 *     "title" = "Kinkinweb\BaseBundle\Entity\Content\Title",
 *     "text" = "Kinkinweb\BaseBundle\Entity\Content\Text",
 *     "image" = "Kinkinweb\BaseBundle\Entity\Content\Image",
 * })
 * @ORM\Entity(repositoryClass="Kinkinweb\BaseBundle\Repository\RowContentRepository")
 */

abstract class RowContent
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    
    //...
}

例如 Text 类:
/**
 * Text
 *
 * @ORM\Table(name="content_text")
 * @ORM\Entity(repositoryClass="Kinkinweb\BaseBundle\Repository\Content\TextRepository")
 */
class Text extends RowContent
{
    /**
     * @var string
     *
     * @ORM\Column(name="text", type="string", length=255)
     */
    private $text;

    //...
}

目前为止都很好,但是我无法处理带有这些实体的表单提交......为了处理带有这些实体的表单,到目前为止我有以下的FormType:

class RowType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            //...
            ->add('rowContents', CollectionType::class, array(
                'entry_type'   => RowContentType::class,
                'allow_add'    => true,
                'allow_delete' => true,
                'label' => 'Contenu Flexible',
                'by_reference' => false,
                'block_name' => 'rows',
            ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Kinkinweb\BaseBundle\Entity\Row',
        ));
    }
}

我已经处理了buildForm部分,就像这样:

    public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->addEventListener(FormEvents::PRE_SET_DATA, function($e) {
                if (null === $e->getData()) { return; }
                $form = $e->getForm();
                if ($e->getData() instanceof Text){
                    $form->add('text',TextType::class);
                }
            });
        }
public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Kinkinweb\BaseBundle\Entity\RowContent';
        ));
    }

但是当我使用jQuery添加表单中的内容并提交表单时,框架无法处理已提交的RowContent对象(这对我来说似乎是很合理的,因为RowContent是抽象的)。

因此,在我一个个拔掉头发之前,我想知道是否有人遇到过这种情况或者有任何关于如何提交表单的见解。

谢谢!

1个回答

2
我知道这个问题很老,但我也遇到了同样的问题,并且成功地解决了它。如果有人以后遇到同样的问题,我将分享我的解决方案。

在发布时间,我正在使用symfony 5。

  1. 我为每种类型创建了一个表单。例如,在您的情况下,应该为Title创建一个表单,为Text创建一个表单,为Image创建另一个表单(我们将它们分别称为RowTitleContentType、RowTextContentType和RowImageContentType)。

我创建了一个AbstractRowContentType并从中扩展。这样,我就不必在每个表单类型中重复常规字段。

  1. Then, in your RowType form, you add a CollectionType for each form type you've created and set the 'mapped' property to false. In other words, it'd look like this:

     public function buildForm(FormBuilderInterface $builder, array $options)
     {
         $builder
             //...
             ->add('rowTitleContents', CollectionType::class, array(
                 'entry_type'   => RowTitleContentType::class,
                 'mapped' => false,
                 'allow_add'    => true,
                 'allow_delete' => true,
                 'by_reference' => false,
             ))
            ->add('rowTextContents', CollectionType::class, array(
                 'entry_type'   => RowTextContentType::class,
                 'mapped' => false,
                 'allow_add'    => true,
                 'allow_delete' => true,
                 'by_reference' => false,
             ))
            ->add('rowImageContents', CollectionType::class, array(
                 'entry_type'   => RowImageContentType::class,
                 'mapped' => false,
                 'allow_add'    => true,
                 'allow_delete' => true,
                 'by_reference' => false,
             ))
         ;
     }
    
  2. Now we need to set a listener in order to merge the contents and add them to a RowContent object:

     public function buildForm(FormBuilderInterface $builder, array $options)
     {
         //..
         $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
             $row = $event->getData();
             $form = $event->getForm();
    
             //let's get every content from the form
    
             $rowTitleContents = $form->get('rowTitleContents')->getData();
             $rowTextContents = $form->get('rowTextContents')->getData();
             $rowImageContents = $form->get('rowImageContents')->getData();
    
             //Let's merge everything
             $mergedRowContents = array_merge($rowTitleContents, 
             $rowTextContents, $rowImageContents);
    
             // And now we add everything to the object.
             $row->setRowContents(new ArrayCollection($mergedRowContents));
         });
     }
    
这就是全部内容了。希望能对某些人有所帮助。
顺便说一下,我的解决方案基于这篇文章:使用单表继承构建表单

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