Scenario: I have a form with 2 selects. When user selects something from the first select, the second select gets populated with new values. This part works fine.
场景:我有一个有2个选择的表单。当用户从第一个选择中选择某些内容时,第二个选择将填充新值。这部分工作正常。
But the form does not get validated since it contains some choices that are not allowed in the initial form.
但是表单没有得到验证,因为它包含初始表单中不允许的一些选项。
Form:
形成:
<?php
class MyType extends AbstractType
{
private $category;
public function __construct($category = null)
{
$this->category = $category;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', 'choice', array(
'choices' => array(
'foo' => 'foo',
'bar' => 'bar'
)
);
$builder->add('template', 'choice', array(
'choices' => $this->loadChoices()
);
}
private function loadChoices()
{
// load them from DB depending on the $this->category
}
}
Initially the category is foo
. So the templates for foo get loaded and set as choices. But if the user selects bar
, the bar templates get loaded. But the form still has the foo choices and does not validate.
最初的类别是foo。因此foo的模板被加载并设置为选项。但是,如果用户选择了条形,则会加载条形模板。但是表单仍然有foo选择而且没有验证。
What is the best way to solve this?
解决这个问题的最佳方法是什么?
One way I found was to just reinitiate the form in the controller:
我找到的一种方法是重新启动控制器中的表单:
<?php
$form = $this->createForm(new MyType());
if ($request->getMethod() === 'POST') {
if ($request->request->has($form->getName())
&& isset($request->request->get($form->getName())['category'])) {
$form = $this->createForm(new MyType($request->request->get($form->getName())['category']));
}
// ...
}
This works, but I cannot test it because it throws IllegalArgumentException
when setting the value and just assumes default. Is there any better solution to this? Thanks in advance!
这可行,但我无法测试它,因为它在设置值时抛出IllegalArgumentException并且只是假定为默认值。有没有更好的解决方案呢?提前致谢!
1 个解决方案
#1
21
I think u have to use Events to manage this, which is more correct way
我认为你必须使用事件来管理这个,这是更正确的方法
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', 'choice', array(
'choices' => array(
'foo' => 'foo',
'bar' => 'bar'
)
));
$ff = $builder->getFormFactory();
// function to add 'template' choice field dynamically
$func = function (FormEvent $e) use ($ff) {
$data = $e->getData();
$form = $e->getForm();
if ($form->has('template')) {
$form->remove('template');
}
$cat = isset($data['category'])?$data['category']:null;
// here u can populate ur choices in a manner u do it in loadChoices
$choices = array('1' => '1', '2' => '2');
if ($cat == 'bar') {
$choices = array('3' => '3', '4' => '4');
}
$form->add($ff->createNamed('template', 'choice', null, compact('choices')));
};
// Register the function above as EventListener on PreSet and PreBind
$builder->addEventListener(FormEvents::PRE_SET_DATA, $func);
$builder->addEventListener(FormEvents::PRE_BIND, $func);
}
#1
21
I think u have to use Events to manage this, which is more correct way
我认为你必须使用事件来管理这个,这是更正确的方法
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', 'choice', array(
'choices' => array(
'foo' => 'foo',
'bar' => 'bar'
)
));
$ff = $builder->getFormFactory();
// function to add 'template' choice field dynamically
$func = function (FormEvent $e) use ($ff) {
$data = $e->getData();
$form = $e->getForm();
if ($form->has('template')) {
$form->remove('template');
}
$cat = isset($data['category'])?$data['category']:null;
// here u can populate ur choices in a manner u do it in loadChoices
$choices = array('1' => '1', '2' => '2');
if ($cat == 'bar') {
$choices = array('3' => '3', '4' => '4');
}
$form->add($ff->createNamed('template', 'choice', null, compact('choices')));
};
// Register the function above as EventListener on PreSet and PreBind
$builder->addEventListener(FormEvents::PRE_SET_DATA, $func);
$builder->addEventListener(FormEvents::PRE_BIND, $func);
}