【问题标题】:Symfony2 merge multi step form to one resultSymfony2 将多步表单合并为一个结果
【发布时间】:2013-03-08 04:34:19
【问题描述】:

这是我在 SF2 上的第一步。我想在包含其他实体的实体上设置多步骤表单。

我有一个表单类型(缩短)

class ApplicationFormType extends AbstractType
{
    protected $_step = 1;

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if ($this->_step == 1) {
            $builder
                ->add('patient', new Type\PersonType())
                ->add('insurance', 'entity', array(
                    'class' => 'Acme\MainBundle\Entity\Insurance',
                ));
        } elseif ($this->_step == 2) {
            $nurse = new Type\PersonType();
            $nurse->requireBareData();
            $builder
                ->add('nurse', $nurse)
                ->add('nurse_type', 'entity', array(
                    'class' => 'Acme\MainBundle\Entity\NurseType',
                    'expanded' => true,
                    'multiple' => false,
                ))
                ->add('nursing_support', 'checkbox', array(
                    'required' => false,
                ));
        }
    }

    public function setStep($step)
    {
        $this->_step = $step;
    }

我的控制器看起来像

public function assistAction() {
    $request = $this->getRequest();

    $step = $this->getSession()->get('assist_step', 1);
    if ($request->getMethod() != 'POST') {
        $step = 1;
        $this->getSession()->set('assist_data', NULL);
    }
    $this->getSession()->set('assist_step', $step);
    $application = new Application();
    $type = new ApplicationFormType();
    $type->setStep($step);

    $form = $this->createForm($type, $application, array(
        'validation_groups' => array($step == 1 ? 'FormStepOne' : 'FormStepTwo'),
    ));
    if ($request->getMethod() == 'POST') {
        $form->bindRequest($request);
        if ($form->isValid()) {
            if ($step == 1) {

                $data = $form->getData();
                $this->getSession()->set('assist_data', serialize($data));
                $this->getSession()->set('assist_step', ++$step);
                $type = new ApplicationFormType();
                $type->setStep($step);
                $form = $this->createForm($type, $application, array(
                    'validation_groups' => array('FormStepTwo'),
                ));

            } else {

                $step_1 = unserialize($this->getSession()->get('assist_data', ''));
                $data = $form->getData();
=>                $data->setPatient($step_1->getPatient());
=>                $data->setInsurance($step_1->getInsurance());
                $this->getSession()->set('assist_data', NULL);
                $this->getSession()->set('assist_step', 1);

            }
        }
    }

    return $this->render('Acme:Default:onlineassist.html.twig', array(
        'form' => $form->createView(),
        'step' => $step,
    ));
}

我的问题是,如果我必须单独“复制”第一个表单步骤的属性,例如:

$data->setPatient($step_1->getPatient());
$data->setInsurance($step_1->getInsurance());

或者我可以将会话中的未序列化数据与第二个表单步骤中的数据合并吗? 还是有完全不同的方法?

【问题讨论】:

  • 多步表单的最终目的是什么?您希望在整个过程中保留提交的数据(如果它是有效的),并且一旦客户审查数据然后您将其注入数据库,对吗?
  • @ThomasPotaire:不完全是。客户不审查数据。如您所见(在 FormType 中),第二步提供了另一个由用户填写的实体字段。 (还有第三步。)当用户完成所有步骤时(顺便说一句:第二个步骤很快就会成为可选的)Application 实体和所有相关实体应该被持久化到数据库中。

标签: forms symfony entity symfony-2.2


【解决方案1】:

实体可以根据stackoverflow上的响应序列化并放入会话中。

如果每个表单都是不同的类型,我建议您将类型拆分为多种类型。

这是我的设想:

public function submitAction($step = 1)
{
    switch ($step) {
        case 1:
            $entity = new EntityOne();
            $form = $this->createForm(new EntityOneType(), $entity);
            $template = "template_one.html.twig";
            $redirect = $urlToStepTwo; // which redirects to this controller action with $step = 2
            break;
        case 2:
            $entity = new EntityTwo();
            $form = $this->createForm(new EntityTwoType(), $entity);
            $template = "template_two.html.twig";
            $redirect = $urlToStepThree; // which redirects to this controller action with $step = 3
            break;
        case 3:
            $entity = new EntityThird();
            $form = $this->createForm(new EntityThreeType(), $entity);
            $template = "template_three.html.twig";
            $redirect = $urlToConfirmPage; // which redirects to another controller action that unserialize all entities and save them in the DB
            break;
        default:
            throw $this->createNotFoundException();
            break;
    }

    $request = $this->get('request');
    $session = $this->get('session');

    if ($request->isMethod('post') === true) {

        $form->bind($request);

        if ($form->isValid() === true) {
            $session->set('entity_'. $step, serialize($entity));

            return $this->redirect($redirect);
        }
    }

    $params = array(
        'form'    => $form->createView(),
        'entity'  => $entity
    );

    return $this->render($template, $params);
}

【讨论】:

  • 您的解决方案肯定适用于单独的实体。但是我在三个步骤中的两个步骤中使用了一个大实体。 ApplicationFormType 代表 Application 实体。 (顺便说一句:您的代码不符合 SF2.2,即 bindRequest vs bindgetMethod() vs isMethod('post')
  • 您可以创建两种表单类型,代表Application 的一组数据,然后将它们融合(感谢不推荐使用的调用)。
  • 这正是我正在做的(看看我的帖子)。这正是我的问题。如何合并这两个步骤。是否可以使用 PHP 中的一条语句来完成,还是让我在第二步中手动设置第一步的每个属性?
【解决方案2】:

好的,除了单独设置pre-step字段没有别的办法,比如

$pre_step = unserialize($this->getSession()->get('assist_data', ''));
$data->setPatient($pre_step->getPatient());
$data->setInsurance($pre_step->getInsurance());
$data->setInsuranceNumber($pre_step->getInsuranceNumber());
$data->setInsuranceLevel($pre_step->getInsuranceLevel());

这就是我迄今为止所做的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-15
    相关资源
    最近更新 更多