我有一个表单,其中包含未指定数量的子表单的集合。我希望有一个功能,允许用户向Collection中添加一个新的空白项,供他们填写。Symfony文档告诉我们如何使用Javascript客户端来添加新的空白表单控件,然后像往常一样提交和持久化,但我想在控制器的服务器端完成它,不使用Javascript。
我遇到的问题是与Symfony窗体的工作方式有关。我在主表单中添加了一个"Add"按钮,我打算检测是否已经单击了该按钮,这样我就可以将空白项添加到Collection中并重新呈现表单。但是要检测点击,我需要调用$this->createForm,在这一点上,表单是固定的原始集合的项目,它是来不及添加一个额外的。
//Symfony Action
//A Person has many Selections
$person = $this->getPerson($id)
//All fields are frozen at this point, according to data in $person!
$form = $this->createForm(new SelectionsType($lookups), $person);
$form->handleRequest($request);
//Ideally I'd somehow do this test earlier, but I need $form to do it...
if ($form->get('add')->isClicked() )
{
//TOO LATE!
$person->getSelections()->add(new Selection() );
}
if ($form->isValid())
{
if ($form->get('save')->isClicked() )
{
//Persist
}
}
//Render page etc
我想过的事情:
- 将Add按钮放在同一页面上完全不同的表单中,它提交给不同的Action,然后在转发到上面的主Action之前可以做一些准备工作
- 直接检查提交的HTTP数据,注意Add已被点击(遗憾没有使用标准的Symfony方法)
- 放弃并使用Javascript作为建议(它可能在这个例子中工作,但我想有执行服务器端活动的选项(没有AJAX…)作为添加新的空白项的一部分)
我怎样才能以适当的Symfony方式最好地实现这一点?
编辑刚刚看到这个:https://github.com/symfony/symfony/issues/5231,这本质上是一个功能请求,以允许我所追求的。一位评论者提出的一个建议是在集合中添加一个空白项,然后在不需要的时候将其删除——我不知道如何做到这一点,但这听起来很有希望。
我突然想到,因为我需要我正在创建的$form的两个不同方面,我可能只是制作$form,用它来处理请求,检测按钮单击,然后扔掉$form,然后改变我的模型并创建另一个$form。我不知道这是否会违反处理两次提交的规则。我不是100%,但我认为你可以这样做…
//Symfony Action with (Request $request, ...)
//A Person has many Selections
$person = $this->getPerson($id)
//All fields are frozen at this point, according to data in $person!
$form = $this->createForm(new SelectionsType($lookups), $person);
if ($request->isMethod('POST')) {
$form->submit($request);
if ($form->get('add')->isClicked()) {
// Add thing
} elseif ($form->isValid()) {
// or
// } elseif ($form->get('save')->isClicked() && $form->isValid()) {
// Persist and what not
}
}
//Render page etc
我还没有测试过,所以我不知道它是否会触发表单错误(或者它是否会实际工作),所以如果它会(或不),我道歉
我最后所做的是让我的Add按钮点击一个单独的Action,然后将一个标记委托给主Action,表示"添加一个新选择",如下所示:
public function selectionsAddAction(Request $request, $id)
{
return $this->selectionsAction($request, $id, true);
}
public function selectionsAction(Request $request, $id, $addNew = false)
{
$person = $this->getPerson($id);
//Also use "add mode" if we just deleted the last one!
if (!$person->getSelections()->count())
{
$addNew = true;
}
//$addNew is set by a separate action, hit by a different form with the Add button in
if ($addNew)
{
$person->getSelections()->add(new Selection() );
}
//We now have the right number of items, and can build the form!
$form = $this->createForm(new SelectionsType($lookups), $person);
//...
}