Php 如何在Symfony 3中使用嵌套表单处理程序

Php 如何在Symfony 3中使用嵌套表单处理程序,php,forms,symfony,Php,Forms,Symfony,我正在学习Symfony将一个旧网站从平面PHP移动到一个框架 在旧网站中,我有一个包含两级表单的页面:第一级只是一个按钮,用户可以通过它接受一些条件,而第二级则向网站管理员发送消息。当用户单击第一个表单中的按钮时,页面将刷新,并显示第二个表单。重要的是,用户不按第一个按钮就无法访问第二个表单 现在,行动方法是这样的: /** * @Route("/ask-consultation", name="ask_consultation") */ public function askConsul

我正在学习Symfony将一个旧网站从平面PHP移动到一个框架

在旧网站中,我有一个包含两级表单的页面:第一级只是一个按钮,用户可以通过它接受一些条件,而第二级则向网站管理员发送消息。当用户单击第一个表单中的按钮时,页面将刷新,并显示第二个表单。重要的是,用户不按第一个按钮就无法访问第二个表单

现在,行动方法是这样的:

/**
 * @Route("/ask-consultation", name="ask_consultation")
 */
public function askConsultationAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $form = $form = $this->createFormBuilder()
        ->add('submit', SubmitType::class, array('label' => 'Confermo'))
        ->getForm();

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $consultation = new Consultation;
        $form = $this->createForm(AskConsultationType::class, $consultation);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $consultation = $form->getData();
            $em = $this->getDoctrine()->getManager();
            $em->persist($consultation);
            $em->flush();
            return $this->redirectToRoute('homepage');
        }

        return $this->render('visitor/consultation/ask_step2.html.twig', [
            'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
            'sidebars' => $em->getRepository('AppBundle:Sidebar')->findAllOrderedBySortingPosition(),
            'form' => $form->createView(),
        ]);
    }
当我进入
/询问咨询
时,它会显示接受特定条件的按钮;当我单击按钮时,它会显示要发送消息的表单,但当我发送它时,我不会被重定向到
主页
,而是再次重定向到
/ask consultation
的第一页

我明白为什么这个代码不起作用,但我不明白如何使它起作用。一种解决方案可以是第一种形式的某种模态对话框,但如果可能的话,我更愿意用PHP处理所有的段落。是否可以在不更改路线的情况下拆分表单处理


在我的例子中,最重要的一点是,如果用户没有首先单击第一个按钮,就无法访问第二个表单。

在单个表单中呈现所有内容,但使用javascript(jQuery)隐藏表单的询问咨询部分。当用户单击“确认”时,取消隐藏表单。这避免了控制器进行确认步骤。不管怎样,您似乎没有记录这个确认,所以让客户端来处理事情。您仍然可以检查(表单提交时)是否接受“确认”,例如通过javascript设置隐藏变量。

在单个表单中呈现所有内容,但使用javascript(jQuery)隐藏表单的询问咨询部分。当用户单击“确认”时,取消隐藏表单。这避免了控制器进行确认步骤。不管怎样,您似乎没有记录这个确认,所以让客户端来处理事情。您仍然可以(在表单提交时)检查“确认”是否被接受,例如通过javascript设置一个隐藏变量。

结果证明答案非常简单

在我看来,我必须在第一个
if($form->isSubmitted()&&&$form->isValid())
中处理第二个表单,但这当然不是PHP采用的路径。每次加载路由时,
askConsultationAction()
从其第一条指令开始运行。我只需初始化两个表单(显然,使用不同的变量名),然后一个接一个地处理表单,而不是一个接一个地处理表单

此代码就像一个符咒:

/**
 * @Route("/ask-consultation", name="ask_consultation")
 */
public function askConsultationAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $consultation = new Consultation;

    $conditions_form = $this->createFormBuilder()
        ->add('submit', SubmitType::class, array('label' => 'Confermo'))
        ->getForm();
    $consultation_form = $this->createForm(AskConsultationType::class, $consultation);

    $consultation_form->handleRequest($request);
    $conditions_form->handleRequest($request);

    if ($conditions_form->isSubmitted() && $conditions_form->isValid()) {
        return $this->render('visitor/consultation/ask_step2.html.twig', [
            'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
            'sidebars' => $em->getRepository('AppBundle:Sidebar')->findAllOrderedBySortingPosition(),
            'form' => $consultation_form->createView(),
        ]);
    }

    if ($consultation_form->isSubmitted() && $consultation_form->isValid()) {
        $consultation = $consultation_form->getData();
        $em = $this->getDoctrine()->getManager();
        $em->persist($consultation);
        $em->flush();
        return $this->redirectToRoute('homepage');
    }

    return $this->render('visitor/consultation/ask_step1.html.twig', [
        'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
        'sidebars' => $em->getRepository('AppBundle:Sidebar')->findAllOrderedBySortingPosition(),
        'form' => $conditions_form->createView(),
    ]);
}

也许,如果我用
的话会更好。。。如果…

结果是答案很简单

在我看来,我必须在第一个
if($form->isSubmitted()&&&$form->isValid())
中处理第二个表单,但这当然不是PHP采用的路径。每次加载路由时,
askConsultationAction()
从其第一条指令开始运行。我只需初始化两个表单(显然,使用不同的变量名),然后一个接一个地处理表单,而不是一个接一个地处理表单

此代码就像一个符咒:

/**
 * @Route("/ask-consultation", name="ask_consultation")
 */
public function askConsultationAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $consultation = new Consultation;

    $conditions_form = $this->createFormBuilder()
        ->add('submit', SubmitType::class, array('label' => 'Confermo'))
        ->getForm();
    $consultation_form = $this->createForm(AskConsultationType::class, $consultation);

    $consultation_form->handleRequest($request);
    $conditions_form->handleRequest($request);

    if ($conditions_form->isSubmitted() && $conditions_form->isValid()) {
        return $this->render('visitor/consultation/ask_step2.html.twig', [
            'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
            'sidebars' => $em->getRepository('AppBundle:Sidebar')->findAllOrderedBySortingPosition(),
            'form' => $consultation_form->createView(),
        ]);
    }

    if ($consultation_form->isSubmitted() && $consultation_form->isValid()) {
        $consultation = $consultation_form->getData();
        $em = $this->getDoctrine()->getManager();
        $em->persist($consultation);
        $em->flush();
        return $this->redirectToRoute('homepage');
    }

    return $this->render('visitor/consultation/ask_step1.html.twig', [
        'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
        'sidebars' => $em->getRepository('AppBundle:Sidebar')->findAllOrderedBySortingPosition(),
        'form' => $conditions_form->createView(),
    ]);
}

也许,如果我用
的话会更好。。。如果…

您想过创建吗?这在你的例子中似乎是恰当的。Once类可以是
条件
表单,其他
咨询
表单。使用类是更好的做法-我以前在控制器中使用过,但代码可能会变得混乱。我将每个表单都作为一个类编写,但我将第一个表单保留在控制器中,因为它包含一个简单的按钮。然而,你是对的:保持一致并将每个表单作为一个类来编写更有意义。你想过创建吗?这在你的例子中似乎是恰当的。Once类可以是
条件
表单,其他
咨询
表单。使用类是更好的做法-我以前在控制器中使用过,但代码可能会变得混乱。我将每个表单都作为一个类编写,但我将第一个表单保留在控制器中,因为它包含一个简单的按钮。然而,你是对的:保持一致并将每个表单作为一个类来编写更有意义。这当然是一个解决方案。然而,由于它在客户端可能会失败,所以我希望在这类任务中至少依赖Javascript。这肯定是一个解决方案。然而,由于它在客户端可能会失败,因此我希望在这类任务中至少依赖Javascript。