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.
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
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);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.