本文介绍了Symfony DataTransformers 与选择形式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了一个 DataTransformer,它基本上不是提交的可用选择.

我的问题是我的变压器接收到 ['INFO' =>;'信息', '警告' =>'WARN'][0 =>'信息', 1 =>'警告'].这通常发生在所有复选框都未选中(也就是选择的模型数据是 ['INFO', 'WARN'])并且我选中任何复选框并提交表单时.

我使用的是 Symfony 2.6.6.

表格如下:

$choice = $builder->create('choice', 'choice', array('选择' =>大批('信息' =>'信息','警告' =>'警告'),'多个' =>真的,'扩展' =>真的);$choice->addModelTransformer(new ReverseChoiceFieldTransformer($choice));$builder->add($choice);

这是变压器:

class ReverseChoiceFieldTransformer 实现 DataTransformerInterface {私人$选择;公共函数 __construct(FormBuilderInterface $fbi) {$this->choices = $fbi->getOption('choices');}公共函数变换($值){返回 $this->reverseTransform($value);}公共函数 reverseTransform($value) {返回 $value === '' ?null : array_diff_key($this->choices, $value);}}
解决方案

我不太确定在这种情况下为什么要使用 DataTransformer.它们用于简化必须将输入的表单数据转换为其他内容的复杂表单.您可能想查看官方,下面的代码应该做的工作:

class ReverseChoiceFieldTransformer 实现 DataTransformerInterface {私人$选择;公共函数 __construct(FormBuilderInterface $fbi) {$this->choices = $fbi->getOption('choices');}/*** 从 FormBuilder 接收到的数据将按原样"传递** @param 混合 $value* @return 混合*/公共函数变换($值){返回 $value;}/*** 从提交的接收到的数据将被修改.正在做* $form->get('choice')->getData() 在控制器中只会返回* 未选择的选项.** @param 混合 $value* @return null|数组*/公共函数 reverseTransform($value) {返回 $value === '' ?null : array_diff(array_keys($this->choices),array_values($value));}}

I made a DataTransformer that is made to basically NOT the available choices with the submitted ones.

My issue is that my transformer receives either ['INFO' => 'INFO', 'WARN' => 'WARN'] or [0 => 'INFO', 1 => 'WARN']. This usually happens when all the checkboxes are unchecked (AKA the model data of the choice is ['INFO', 'WARN']) and that I check any and submit the form.

I am using Symfony 2.6.6.

Here is the form :

$choice = $builder->create('choice', 'choice', array(
    'choices' => array(
        'INFO' => 'INFO',
        'WARN' => 'WARN'
    ),
    'multiple' => true,
    'expanded' => true
);
$choice->addModelTransformer(new ReverseChoiceFieldTransformer($choice));
$builder->add($choice);

And here is the transformer :

class ReverseChoiceFieldTransformer implements DataTransformerInterface {
    private $choices;

    public function __construct(FormBuilderInterface $fbi) {
        $this->choices = $fbi->getOption('choices');
    }

    public function transform($value) {
        return $this->reverseTransform($value);
    }

    public function reverseTransform($value) {
        return $value === '' ? null : array_diff_key($this->choices, $value);
    }
}
解决方案

I'm not quite sure why you'd want to use a DataTransformer in this case. They're used to simplify complex forms where the entered form data has to be transformed into something else. You might want to checkout the official documentation of Symfony, regarding Data Transformers.

Furthermore, your ReverseChoiceFieldTransformer class is not correctly implemented. The transform method is meant to transform an Object to a simple type like string,int,etc which is later displayed in the form as ViewData. On the contrary, the reverseTransform method is used to reverse transform the data from simple type back into the same Object. You can see this in the illustration below (taken from Symfony official docs)

Having said that, I believe your approach to the problem might be wrong. It would probably better if you do this in the controller or in a form event. Here's an example of how to get the data in your controller class:

// MyFormType
class MyFormType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('choice', 'choice', array(
            'choices' => array(
                'INFO' => 'Info label',
                'WARN' => 'Warn label',
                'CRIT' => 'Crit label',
            ),
            'multiple' => true,
            'expanded' => true,
            'required' => false,
            'mapped'   => false
        ))
        ->add('submit', 'submit', array(
            'attr' => array('class' => 'save'),
        ));;
    }

    public function getName() {
        return "my_form";
    }
}


// MyController
class MyController extends Controller {
    /**
     * @Route("/test")
     * @Template()
     */
    public function testAction(Request $request) {
        $form = $this->createForm(new MyFormType());
        $form->handleRequest($request);

        if($form->isValid())
        {
            // Get selected
            $selectedChoices = $form->get('choice')->getData();
            // outputs the checked values, i.e.
            // array (size=2)
            //    0 => string 'INFO' (length=4)
            //    1 => string 'WARN' (length=4)

            // All choices with their labels
            $allChoices = $form->get('choice')->getConfig()->getOption('choices');
            // outputs all choices, i.e.
            // array (size=3)
            //   'INFO' => string 'Info label' (length=10)
            //   'WARN' => string 'Warn label' (length=10)
            //   'CRIT' => string 'Crit label' (length=10)

            // All unchecked choices. Pay attention to the difference
            // in the arrays.
            $unchecked = array_diff(array_keys($allChoices), array_values($selectedChoices));

        }

        return array('form' => $form->createView());
    }
}


Follow up on comments:

You're partly correct. The transform method receives the model data which was used to build the form, while the reverseTransform method receives the data submitted to the form. Although in your case the received data in both cases is an array, the array itself contains different data structure:

  1. transform will receive:

    array (
        'INFO' => 'Info label',
        'WARN' => 'Warn label',
        'CRIT' => 'Crit label'
    )
    

  2. reverseTransform will receive the checked choices i.e.:

    array (
        0 => 'INFO',
        1 => 'CRIT'
    )
    


Although, I would go for a controller or research if this could be done with FormEvents, the following code should do the work:

class ReverseChoiceFieldTransformer implements DataTransformerInterface {
    private $choices;

    public function __construct(FormBuilderInterface $fbi) {
        $this->choices = $fbi->getOption('choices');
    }

    /**
     * The received data from the FormBuilder will be passed "AS IS"
     *
     * @param mixed $value
     * @return mixed
     */
    public function transform($value) {
        return $value;
    }

    /**
     * The received data from the submitted from will be modified. Doing
     * $form->get('choice')->getData() in the controller will return only
     * the unselected choices.
     *
     * @param mixed $value
     * @return null|array
     */
    public function reverseTransform($value) {
        return $value === '' ? null : array_diff(array_keys($this->choices),array_values($value));
    }
}

这篇关于Symfony DataTransformers 与选择形式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-12 12:20