php - Symfony2 : transformationFailure "Compound forms expect an array or NULL on submission."

标签 php symfony

我有一个由 6 个字段组成的 Location 对象。其中一些字段是可选的。

所以我有一个 LocationSelectType,它根据位置、PRE_SET_DATA 和 PRE_SUBMIT 事件填充字段。这工作正常。

但是在 PRE_SUBMIT 上,我还想根据用户输入的数据创建 Location 对象。这似乎可行,但最后会触发错误:* transformationFailure“复合形式在提交时需要一个数组或 NULL。”*

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

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,
        ));
}

当我将表单转储到 Controller 中时,我看到:

-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

最佳答案

你的问题在这里

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);
}

$event->setData($location);中你犯了一个错误:在pre_submit事件中,$event->getData()是一个关联数组,不是一个实体(参见 https://symfony.com/doc/current/form/events.html#component-form-event-table ),因此您应该在 $event->setData() 中设置一个关联数组。尝试调用 dump($event->getData()) 并查看预期的格式。

关于php - Symfony2 : transformationFailure "Compound forms expect an array or NULL on submission.",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28631826/

相关文章:

php - 在 Symfony 3 中为集合的每个元素应用特定的验证组

php - Symfony 2 原型(prototype)内的原型(prototype) - 双 $$name 字段

php - 如何在json数据中添加javascript?

javascript - javascript 无法从表单获取数据

php - 如何在 PDO::FETCH_FUNC 中使用对象方法

php - 如何在 Laravel 5 中创建表迁移

javascript - 在javascript弹出窗口中显示php页面

symfony - SonataAdminBundle 中不存在函数 "is_granted"

php - symfony 2 - 尝试调用类 "findBy"的名为 "testBundle\Entity\test"的未定义方法

javascript - Symfony 5 调试工具栏未显示在错误页面上