i have a Location object made of 6 fields. Some of these fields are optional.
So i have a LocationSelectType that populate fields depending of Location, on PRE_SET_DATA and PRE_SUBMIT events. This is working fine.
But on PRE_SUBMIT, i would also like to create the Location object from the data the user entered. This seems to work, but trigger an error at the end : * transformationFailure "Compound forms expect an array or NULL on submission."*
class LocationSelectType extends AbstractType {
public $em;
private $router;
private $options;
public function __construct(EntityManager $em,Router $router)
{
$this->em = $em;
$this->router = $router;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$em = $this->em;
$builder
->add('country','choice',array(
'choices'=>$this->em->getRepository('MyWorldBundle:Country')->findCountryList();,
'required'=>false,
'mapped'=>false,
'empty_value'=>'Votre pays',
'attr'=>array('class'=>'geo-select geo-select-country geo-select-ajax','data-geo-level'=>'country','data-icon'=>'globe','data-ajax-url'=>$options['ajax_url'],'style'=>"width:100%"),
))
->add('region','choice',array(
'choices'=>array(), //populate on events
'required'=>false,
'mapped'=>false,
'empty_value'=>'Votre région',
'attr'=>array('class'=>'geo-select geo-select-region geo-select-ajax hide','data-geo-level'=>'region','data-icon'=>'globe','data-ajax-url'=>$options['ajax_url'],'style'=>"width:100%"),
))
->add('departement','choice',array(
'choices'=>array(), //populate on events
'required'=>false,
'mapped'=>false,
'empty_value'=>'Votre Département',
'attr'=>array('class'=>'geo-select geo-select-departement geo-select-ajax hide','data-geo-level'=>'departement','data-icon'=>'globe','data-ajax-url'=>$options['ajax_url'],'style'=>"width:100%"),
))
->add('district','choice',array(
'choices'=>array(), //populate on events
'required'=>false,
'mapped'=>false,
'empty_value'=>'Votre district',
'attr'=>array('class'=>'geo-select geo-select-district geo-select-ajax hide','data-geo-level'=>'district','data-icon'=>'globe','data-ajax-url'=>$options['ajax_url'],'style'=>"width:100%"),
))
->add('division','choice',array(
'choices'=>array(), //populate on events
'required'=>false,
'mapped'=>false,
'empty_value'=>'Votre division',
'attr'=>array('class'=>'geo-select geo-select-division geo-select-ajax hide','data-geo-level'=>'division','data-icon'=>'globe','data-ajax-url'=>$options['ajax_url'],'style'=>"width:100%"),
))
->add('city','choice',array(
'choices'=>array(), //populate on events
'required'=>false,
'mapped'=>false,
'empty_value'=>'Votre ville',
'attr'=>array('class'=>'geo-select geo-select-city geo-select-ajax hide','data-geo-level'=>'city','data-icon'=>'globe','data-ajax-url'=>$options['ajax_url'],'style'=>"width:100%"),
))
;
$this->options = $options;
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
$builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmit'));
$builder->addEventListener(FormEvents::POST_SUBMIT, array($this, 'onPostSubmit'));
}
public function onPreSetData(FormEvent $event)
{
$form = $event->getForm();
$location = $event->getData();
//populate geo fields
$this->addGeoFields($form, $location);
}
public function onPreSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
//find Location that fit the form data
$location = $this->em->getRepository('MyWorldBundle:Location')->findLocationFromData($data);
//populate all relevant geo field to render the form view
$this->addGeoFields($form, $location);
//replace data with the object location
$event->setData($location);
}
public function onPostSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
}
public function addGeoFields(FormInterface $form, $location)
{
if($location == NULL) return;
if($location->getCountry() != NULL) $this->addGeoField($form, $location, 'country', $location->getCountry()->getCode());
if($location->getRegion() != NULL) $this->addGeoField($form, $location, 'region', $location->getRegion()->getId());
if($location->getDepartement() != NULL) $this->addGeoField($form, $location, 'departement', $location->getDepartement()->getId());
if($location->getDistrict() !== NULL) $this->addGeoField($form, $location, 'district', $location->getDistrict()->getId());
if($location->getDivision() !== NULL) $this->addGeoField($form, $location, 'division', $location->getDivision()->getId());
if($location->getCity() != NULL) $this->addGeoField($form, $location, 'city', $location->getCity()->getId());
}
public function addGeoField(FormInterface $form, $location, $level, $value = '')
{
$list = $this->em->getRepository('MyWorldBundle:Location')->findStatesListFromLocationByLevel($location,$level);
if(empty($list)) return;
$form->add($list['level'],'choice',array(
'choices'=>$list['list'],
'required'=>false,
'mapped'=>false,
'empty_value'=>'Votre '.$list['level'],
'attr'=>array('class'=>'geo-select geo-select-'.$list["level"].' geo-select-ajax','data-geo-level'=>$list["level"],'data-icon'=>'globe','data-ajax-url'=>$this->options['ajax_url'],'style'=>"width:100%"),
'data'=>$value
));
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'My\WorldBundle\Entity\Location',
'ajax_url' => $this->router->generate('my_world_location_select_nextlevel'),
'allow_extra_fields' => true,
));
}
/**
* @return string
*/
public function getName()
{
return 'location_select';
}
The controller :
public function formSelectLocationAction(Request $request)
{
$location = new Location();
$form = $this->createForm('location_select',$location);
$form->handleRequest($request);
if($form->isValid()){ //form is not valid
$location = $form->getData();
}
//dump($form);
return $this->render('MyWorldBundle:Form:test_location_select.html.twig',array(
'form' => $form->createView(),
'location' => $location,
));
}
When i dump the form in the controller i see:
-transformationFailure: TransformationFailureException {
#message: "Compound forms expect an array or NULL on submission."
#code : 0
#file: "C:\App\wamp\www\WeSport-symfony\path\vendor\symfony\symfony\src\Symfony\Component\Form\Form.php"
##line: 565
Your problem is here
public function onPreSubmit(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData(); //find Location that fit the form data
$location = $this->em->getRepository('MyWorldBundle:Location')->findLocationFromData($data) ; //populate all relevant geo field to render the form view
$this->addGeoFields($form, $location); //replace data with the object location
$event->setData($location);
}
In $event->setData($location);
you made a mistake: in pre_submit event, $event->getData()
is an associative array, not an entity (see https://symfony.com/doc/current/form/events.html#component-form-event-table), so you should set an associative array in $event->setData()
. Try calling dump($event->getData())
and see the expected format.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With