我制作了一个 DataTransformer,它基本上不是针对提交的可用选择。
我的问题是我的变压器收到
['INFO' => 'INFO', 'WARN' => 'WARN']
或 [0 => 'INFO', 1 => 'WARN']
。当所有复选框均未选中(又称选择的模型数据为 ['INFO'、'WARN'])并且我选中任何复选框并提交表单时,通常会发生这种情况。
我使用的是 Symfony 2.6.6。
这是表格:
$choice = $builder->create('choice', 'choice', array(
'choices' => array(
'INFO' => 'INFO',
'WARN' => 'WARN'
),
'multiple' => true,
'expanded' => true
);
$choice->addModelTransformer(new ReverseChoiceFieldTransformer($choice));
$builder->add($choice);
这是变压器:
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);
}
}
我不太清楚为什么在这种情况下你要使用
DataTransformer
。它们用于简化复杂的表单,其中输入的表单数据必须转换为其他内容。您可能想查看有关数据转换器的 Symfony 官方文档。
此外,您的
ReverseChoiceFieldTransformer
类未正确实现。 transform
方法旨在将 Object
转换为简单类型,如 string
、int
等,稍后以 ViewData
的形式显示。相反,reverseTransform
方法用于将数据从简单类型反向转换回相同的Object
。你可以在下图中看到这一点(取自 Symfony 官方文档)
话虽如此,我相信您解决问题的方法可能是错误的。如果您在控制器或表单事件中执行此操作可能会更好。以下是如何获取控制器类中的数据的示例:
// 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());
}
}
跟进评论:
你说对了一部分。
transform
方法接收用于构建表单的模型数据,而 reverseTransform
方法接收提交给表单的数据。尽管在您的情况下,两种情况下收到的数据都是 array
,但 array
本身包含不同的数据结构:
transform
将会收到:
array (
'INFO' => 'Info label',
'WARN' => 'Warn label',
'CRIT' => 'Crit label'
)
reverseTransform
将收到选中的选项,即:
array (
0 => 'INFO',
1 => 'CRIT'
)
虽然,如果这可以通过 FormEvents 完成,我会选择控制器或研究,但以下代码应该可以完成工作:
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));
}
}