【问题标题】:Symfony2 : Two forms in a same pageSymfony2:同一页面中的两个表单
【发布时间】:2014-07-22 13:44:39
【问题描述】:

我在同一个页面中有两个表单。

我的问题是当我尝试提交表单时,它就像尝试在页面下方提交第二个表单一样。

如下,你可以找到我的2个表格:

public function createSuiviForm() {

    return $form = $this->createFormBuilder(null)
            ->add('numero', 'text', array('label' => 'N° : ',
                'constraints' => array(
                    new Assert\NotBlank(array('message' => 'XXXX')),
                    new Assert\Length(array('min' => 19, 'max' => 19, 'exactMessage' => 'XXX {{ limit }} XXX')))))
            ->add('xxxx', 'submit')
            ->getForm();
}

public function createModificationForm() {

    return $form = $this->createFormBuilder(null)
            ->add('modification', 'submit', array('label' => 'XXXXXXXXXXXXXXXXXXXX'))
            ->getForm();
}

我的第二个表单只是一个提交按钮。

我将它们传递给我的渲染器并使用以下方法显示它们:

<div class="well">
    <form method="post" action='' {{form_enctype(form)}} >
        {{ form_widget(form) }}
        <input type="submit" class="btn btn-primary"/>
    </form>
    <div class='errors'>
        {{ form_errors(form) }}
     </div>
</div>

'form' 是我对第一个表单的变量的名称 并为我的第二种形式“更新”。

当我尝试提交我的第二个表单时,我需要点击两次,最后我得到了:

"This form should not contain extra fields."
And all non valid input for the remainding form.

我尝试将validation_group添加为false,但无济于事。

我不明白为什么会出现此错误,因为我的表单根本没有嵌入

希望你能理解……

【问题讨论】:

  • 显示第二个表单(更新)的 html - 它在源代码中的呈现方式、在控制器中处理表单的方式也可能很有用。

标签: php forms symfony


【解决方案1】:

您必须分别处理表格:

if('POST' === $request->getMethod()) {
 
    if ($request->request->has('form1name')) {
        // handle the first form  
    }

    if ($request->request->has('form2name')) {
        // handle the second form  
    }
}

这在Symfony2 Multiple Forms: Different From Embedded Forms 中有完美的解释(暂时不可用 - 见下文)

更新

由于上面提供的链接暂时不可用,您可以查看该资源的存档here

【讨论】:

  • 如何获取每个表单的数据?
  • @Amine Harbaoui:如果您在同一操作中创建和处理表单,您应该能够使用分配的表单变量访问表单数据,例如$suiviForm-&gt;getData() 。如果您在单独的操作中处理表单,则必须重新创建表单,例如调用$suiviForm = createSuiviForm();,通过$suiviForm-&gt;handleRequest($request)处理请求,然后访问数据。
  • 链接已损坏。有任何官方文档吗?谢谢:)
  • 您可以使用 Web 存档,直到它恢复 - 我已经编辑了我的答案 - 或者 - 转到 here
【解决方案2】:

问题是您有两个无名表单(输入名称,例如 inputname 而不是 formname[inputname],因此当您将请求绑定到表单并经过验证时,它会检测到一些额外的字段(另一个表单)和所以无效。

短期的解决方案是通过表单工厂创建一个命名构建器,而不是:

$form = $this->createFormBuilder(null)

你应该使用:

$form = $this->get("form.factory")->createNamedBuilder("my_form_name")

长期的解决方案是create your own form classes,这样您就可以将表单代码与控制器分开。

【讨论】:

    【解决方案3】:

    这两个表格将被发布。

    尝试使用:

        $this->createNamedBuilder 
    

    而不是

        $this->createFormBuilder
    

    然后在您的控制器中,按名称找到表单:

    if ($request->request->has("your form name") {
       $form->handleRequest($request);
    }
    

    【讨论】:

      【解决方案4】:

      这就是我在控制器上处理它们的方式:

      return $this->render('SgaDemandeBundle:Demande:suivi_avancement.html.twig', 
                           array('form' => $form->createView(), 
                                 ........
                                 'update' => $formModification->createView()));
      

      这是第二种形式的html:

      <div class="well">
          <form method="post">
              <div id="form">
                  <div>
                      <button type="submit" id="form_modification"  
                      name="form[modification]">Modification done
                      </button>
                  </div>
                  <input type="hidden" id="form__token" name="form[_token]" 
                  value="fFjgI4ecd1-W70ehmLHmGH7ZmNEHAMqXlY1WrPICtK4">
              </div>        
          </form>
      </div>
      

      这是我的树枝渲染:

      <div class="well">
          <form method="post" {{form_enctype(update)}} >
              {{ form_widget(update) }}
          </form>
      </div>
      
      <div class="well">
          <form method="post" action='' {{form_enctype(form)}} >
              {{ form_widget(form) }}
              <input type="submit" class="btn btn-primary"/>
          </form>
           <div class='errors'>
              {{ form_errors(form) }}
           </div>
      </div>
      

      希望对你有帮助。

      【讨论】:

        【解决方案5】:

        使用命名表单是处理多个表单的可行解决方案,但它可能会有点混乱,尤其是在动态生成表单时。

        从 Symfony 2.3 开始,另一种方法是检查单击了哪个提交按钮。

        例如,假设每个表单都有一个名为'save'的提交按钮:

        if ('POST' == $Request->getMethod())
        {
            $form1->handleRequest($Request);
            $form2->handleRequest($Request);
            $form3->handleRequest($Request);
        
            if ($form1->get('save')->isClicked() and $form1->isValid())
            {
                //Do stuff with form1
            }
        
            if ($form2->get('save')->isClicked() and $form2->isValid())
            {
                //Do stuff with form2
            }
        
            if ($form3->get('save')->isClicked() and $form3->isValid())
            {
                //Do stuff with form3
            }
        }
        

        我相信与命名的构建器方法相比,这会产生少量额外开销(由于多次handleRequest 调用),但在某些情况下,它会产生更清晰的代码。有多种解决方案可供选择总是好的。如有必要,可以通过嵌套 if/else 语句来减轻一些额外开销,但是,除非我们在每页讨论几十个表单,否则额外开销在任何情况下都可以忽略不计。

        这是一个使用匿名函数的替代实现,可以最大限度地减少代码重复:

        $form1Action = function ($form) use (&$aVar) {
                //Do stuff with form1
            };
        $form2Action = function ($form) use (&$anotherVar) {
                //Do stuff with form2
            };
        $form3Action = function ($form) use (&$yetAnotherVar) {
                //Do stuff with form3
            };
        $forms = [$form1 => $form1Action, 
                  $form2 => $form2Action,
                  $form3 => $form3Action];
        
        if ('POST' == $Request->getMethod())
        {
            foreach ($forms as $form => $action)
            {
                $form->handleRequest($Request);
                if ($form->get('save')->isClicked() and $form->isValid())
                {
                    $action($form);
                }
            }
        }
        

        【讨论】:

          【解决方案6】:

          这在 Symfony 3 中对我有用(应该也适用于 Symfony 2):

          $form1 = $this->createForm(
              MyFirstFormType::class
          );
          
          $form2 = $this->createForm(
              MySecondFormType::class
          );
          
          if ($request->isMethod('POST')) {
          
              $form1->handleRequest($request);
              $form2->handleRequest($request);
          
              if ($form1->isSubmitted()) {
                  // Handle $form1
              } else if ($form2->isSubmitted()) {
                  // Handle $form2
              }
          
          }
          

          【讨论】:

            【解决方案7】:

            查看块前缀:

            public function getBlockPrefix()
            {
                return 'app_x_form'.$form_id;
            }
            

            【讨论】:

              猜你喜欢
              • 2014-03-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-11-29
              • 2015-05-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多