如何分步“验证"Symfony 表单 - 而不是调用 $form->isValid() [英] How to 'validate' a Symfony form in steps - instead of calling $form->isValid()

查看:21
本文介绍了如何分步“验证"Symfony 表单 - 而不是调用 $form->isValid()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Ubuntu 上使用 Symfony 1.3.6.

我有一个包含很多字段的表单 - 与其一次性显示所有字段(这可能会吓到用户),我想将表单分解为多个阶段,以便用户只能填写在每个步骤/阶段显示的字段(有点像向导).

为了做到这一点,我需要为表单编写自定义方法,例如:

validateStep1();验证步骤2();...验证 StepN();

在上述每个函数中,我只验证可用小部件的一个子集 - 即我只验证在该步骤中向用户显示的小部件.

为了做到这一点,如果我可以在小部件上调用 isValid() 方法会很有用,但是,我查看了 sfWidget 类并且在小部件级别没有这样的 isValid() 方法.

我不想对我使用的每个小部件进行硬编码验证,因为这不是 DRY

有谁知道我如何检查表单中的各个小部件以查看用户输入的值是否有效?

解决方案

我将使用不同的方法在 Symfony 中实现多部分表单.希望以下 shell 足以让您入门.

第 1 步:向表单添加舞台小部件

公共函数configure(){$this->setWidget('stage', new sfWidgetFormInputHidden(array('default' => 1));$this->setValidator('stage', new sfValidatorFormInteger(array('min' => 1, 'max' => $maxStages, 'required' => true));}

第 2 步:在表单中添加有关阶段的一些信息

protected $stages = array(1 =>数组('stage1field1', 'stage1field2',2 =>array('stage2field1', ...//等你有多少阶段);

第 3 步:向表单添加配置为阶段方法

公共函数 configureAsStage($currentStage){foreach($this->stages as $stage => $field){如果 ($currentStage > $stage){$this->setWidget($stage, new sfWidgetFormInputHidden());//所以这些值通过}如果 ($stage > $currentStage){未设置($this[$stage]);//我们还不想要这个阶段}}}

第 4 步:覆盖 doBind

你可能需要直接覆盖 bind(),我忘了.

公共函数 doBind(array $taintedValues){$cleanStage = $this->getValidator('stage')->clean($taintedValues['stage']);$this->configureAsStage($cleanStage);parent::doBind($taintedValues);}

第五步:在表单中添加一些辅助方法

公共函数advanceStage(){如果 ($this->isValid()){$this->values['stage'] += 1;$this->taintedValues['stage'] += 1;$this->resetFormFields();}}公共函数 isLastStage(){返回 $this->getValue('stage') == count($this->stages);}

第 6 步:在您的操作中根据需要调用 configureAsStage/advanceStage

公共函数executeNew(sfWebRequest $request){$form = new MultiStageForm($record);$form->configureAsStep(1);}公共函数 executeCreate(sfWebRequest $request){$record = new Record();$form = new MultiStageForm($record);$form->bind($request[$form->getName()]);如果 ($form->isValid()){if ($form->isLastStage()){$form->save();//重定向或你在这里做的任何事情}$form->advanceStage();}//渲染表单}

我完全是即时编造的.我认为它应该可以工作,但我没有测试过,所以可能会有一些错误!

I am using Symfony 1.3.6 on Ubuntu.

I have a form with a lot of fields on it - rather than showing all the fields in one go (which may intimidate the user), I want to break up the form into stages, so that a user can fill in only the fields displayed, at each step/stage (kinda like a wizard).

In order to do that, I need to write custom methods for the form, e.g.:

validateStep1();
validateStep2();
...
validate StepN();

Where in each of the functions above, I only validate a subset of the available widgets - i.e. I validate only the widgets displayed to the user in that step.

In order to do that, it would be useful if I could call an isValid() method on widgets, however, I have looked at the sfWidget classes and there is no such isValid() method at the widget level.

I don't want to hard code validation for each widget I am using, since this is not DRY

Does anyone know how I can check individual widgets in a form to see whether the user entered value(s) are valid?

解决方案

I would utilize a different method to implement multi part forms in Symfony. Hopefully, the following shell is enough to get you started.

Step 1: Add a stage widget to your form

public function configure()
{
  $this->setWidget('stage', new sfWidgetFormInputHidden(array('default' => 1));
  $this->setValidator('stage', new sfValidatorFormInteger(array('min' => 1, 'max' => $maxStages, 'required' => true));
}

Step 2: Add some information about the stages to your form

protected $stages = array(
  1 => array('stage1field1', 'stage1field2',
  2 => array('stage2field1', ... //etc for as many stages you have
);

Step 3: Add a configure as stage method to your form

public function configureAsStage($currentStage)
{
  foreach($this->stages as $stage => $field)
  {
    if ($currentStage > $stage)
    {
      $this->setWidget($stage, new sfWidgetFormInputHidden()); //so these values carry through
    }
    if ($stage > $currentStage)
    {
       unset($this[$stage]); //we don't want this stage here yet
    }
  }
}

Step 4: Override doBind

You might need to override bind() directly, I forget.

public function doBind(array $taintedValues)
{
  $cleanStage = $this->getValidator('stage')->clean($taintedValues['stage']);
  $this->configureAsStage($cleanStage);
  parent::doBind($taintedValues);
}

Step 5: Add some auxiliary methods to the form

public function advanceStage()
{
  if ($this->isValid())
  {
    $this->values['stage'] += 1;
    $this->taintedValues['stage'] += 1;
    $this->resetFormFields();
  }
}

public function isLastStage()
{
  return $this->getValue('stage') == count($this->stages);
}

Step 6: Call configureAsStage/advanceStage as necessary in your action

public function executeNew(sfWebRequest $request)
{
  $form = new MultiStageForm($record);
  $form->configureAsStep(1);
}

public function executeCreate(sfWebRequest $request)
{
  $record = new Record();
  $form = new MultiStageForm($record);
  $form->bind($request[$form->getName()]);
  if ($form->isValid())
  {
    if ($form->isLastStage())
    {
      $form->save();
      //redirect or whatever you do here
    }
    $form->advanceStage(); 
  }
  //render form
}

I made this up completely on the fly. I think it should work, but I haven't tested it so there may be some mistakes!

这篇关于如何分步“验证"Symfony 表单 - 而不是调用 $form->isValid()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆