Symfony形式|动态集合类型值

时间:2018-01-09 22:45:15

标签: php forms symfony

我正在symfony 3.4上构建一个小工具,我遇到了一个我无法找到解决方案的问题。

对于上下文,导致我一些困难的形式基于一个学说实体:事件。 此事件引用另一个实体:一个Doctrine(与ORM无关)。一个学说引用了多重拟合。 对于具有给定Doctrine的给定事件,我想显示根据doctrine配件构建的集合类型,该集合类型公开一个数字,该数字是此事件的所需数量。

这导致了我的形式中的3个实体:事件本身,学说以及在我的基础上构建的fittingRequirements的集合类型。

Here is how it looks

正确的面板内容意味着每次学说发生变化时都会改变。

这是EventType:

<?php

namespace AppBundle\Form;

use AppBundle\Entity\Doctrine;
use AppBundle\Entity\Event;
use AppBundle\Form\DataTransformer\FittingRequirementTransformer;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EventType extends AbstractType
{
    protected $requirementTransformer;

    public function __construct(FittingRequirementTransformer $transformer)
    {
        $this->requirementTransformer = $transformer;
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder
            ->setMethod('POST')
            ->add('name')
            ->add(
                'date',
                DateTimeType::class,
                [
                    'widget' => 'single_text',
                    'format' => 'yyyy-MM-dd HH:mm',
                ]
            )
            ->add('startLocation')
            ->add(
                'eventType',
                ChoiceType::class,
                [
                    'choices' => [
                        'PvE'   => 'PvE',
                        'PvP'   => 'PvP',
                        'Other' => 'Other',
                    ],
                ]
            )
            ->add('target')
            ->add('description')
            ->add(
                'doctrine',
                EntityType::class,
                [
                    'class'         => 'AppBundle\Entity\Doctrine',
                    'choice_label'  => 'name',
                    'query_builder' => function (EntityRepository $repository) {
                        return $repository->createQueryBuilder('d')->orderBy('d.name', 'ASC');
                    },
                    'required'      => false,
                ]
            );


        $formModifier = function (FormInterface $form, Doctrine $doctrine = null, Event $event) {

            $eventRequirements = [];

            if ($doctrine) {

                $doctrineFittings     = $doctrine->getFittings();
                $doctrineRequirements = $event->getDoctrineFittingRequirements($doctrine);

                $eventRequirements = $this->requirementTransformer->dataToForm(
                    $doctrineFittings,
                    $doctrineRequirements,
                    $event
                );

            }

            $form->add(
                'eventRequirements',
                CollectionType::class,
                [
                    'entry_type'    => FittingRequirementType::class,
                    'label'         => false,
                    'entry_options' => ['label' => false],
                    'data'          => $eventRequirements,
                    'mapped'        => false,
                ]
            );

        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {

                $formupEvent = $event->getData();
                $formModifier($event->getForm(), $formupEvent->getDoctrine(), $formupEvent);
            }
        );

        $builder->get('doctrine')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {

                $eventForm = $event->getForm()->getParent();
                $doctrine  = $event->getForm()->getData();
                $formModifier($event->getForm()->getParent(), $doctrine, $eventForm->getData());
            }
        );
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
            [
                'data_class' => 'AppBundle\Entity\Event',
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'event';
    }
}

我正在构建eventFittingRequirements列表并将其添加到PRE_SET_DATA和POST_SUBMIT上 如您所见,我使用了FittingRequirementType的CollectionType,您可以在下面看到:

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class FittingRequirementType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('number', NumberType::class);
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\FittingRequirement'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'appbundle_fittingrequirement';
    }
}

这仅用于公开所需配件的数量。

当我显示表单时,所有这些都很有效,但是当我使用javascript提交表单来刷新需求部分时,字段确实被替换,但返回的表单在输入中没有值。

我的$ formModifier中的$ eventRequirements变量包含a proper set of data,其中包含数字值。但是,当我使用symfony探查器the form has no values检查XHR时,即使我再次选择原始学说。我不明白发生了什么以及如何解决这个问题。

感谢您阅读

1 个答案:

答案 0 :(得分:1)

我刚刚发现了正在发生的事情并解决了我的问题。

我的表单很好,但handleRequest方法清除了我使用自定义fittingRequirement列表设置的未映射字段。

我必须手动将带有clearmissing参数的表单提交为false,如下所示:

$cartItem->name