3

I'm building a small tool on symfony 3.4, I'm experiencing two issue with a form that I cannot find a solution for.

For the context, the form that is causing me some difficulties is based on a doctrine entity : Event. This event reference another entity : a Doctrine (nothing do to with the ORM). A doctrine references multiples Fittings. For a given Event with a given Doctrine, I want to display a collectiontype built from the doctrine fittings that expose a number meant to be the required number of this fitting for this event.

This lead to 3 entities in my form : the event itself, the doctrine, and a collectiontype of fittingRequirements built on my end.

Here is how it looks

The right panel content is meant to change each time the doctrine change.

Here is the 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';
    }
}

I'm building the list of eventFittingRequirements and adding it on PRE_SET_DATA and POST_SUBMIT As you can see, I use a CollectionType of FittingRequirementType you can see bellow :

<?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';
    }
}

This is only used to expose the number of required fittings.

All this works well when I display the form, however when I submit the form using javascript to refresh the requirement part, the field are indeed replaced, but the returned form has no value in the inputs.

The $eventRequirements variable from my $formModifier contains a proper set of data, with the number value. However, when I check the XHR with the symfony profiler, the form has no values, even if I select the original doctrine again. I don't understand what is going on and how to fix this.

Thanks for reading

0

1 Answer 1

1

I just found out what was going on and fixed my issue.

My forms are fine, however the handleRequest method clears the unmapped fields I set with my custom fittingRequirement list.

I had to manually submit my form with the clearmissing parameter to false like bellow :

$form->submit($request->request->get($form->getName()), false);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.