【问题标题】:How to 'validate' a Symfony form in steps - instead of calling $form->isValid()如何分步“验证”一个 Symfony 表单——而不是调用 $form->isValid()
【发布时间】:2010-08-23 07:12:34
【问题描述】:

我在 Ubuntu 上使用 Symfony 1.3.6。

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

为此,我需要为表单编写自定义方法,例如:

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

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

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

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

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

【问题讨论】:

  • Haim:不完全相关,就我而言,我想使用一个单一的表单来处理不同的步骤。您发布的链接为跨 SEPARATE 表单的步骤提供了解决方案。

标签: php symfony1 symfony-forms


【解决方案1】:

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

第 1 步:在表单中添加阶段小部件

public function 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 => array('stage1field1', 'stage1field2',
  2 => array('stage2field1', ... //etc for as many stages you have
);

第 3 步:在表单中添加 configure as stage 方法

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
    }
  }
}

第 4 步:覆盖 doBind

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

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

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

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);
}

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

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
}

我完全是在飞行中编造的。我认为它应该可以工作,但我还没有测试过,所以可能会有一些错误!

【讨论】:

  • 如果你发现自己在多个表单中这样做,这段代码可以放在 BaseForm 中。
【解决方案2】:

isValid() 函数实际上并没有做任何事情,除了检查关联的表单是否已绑定并且验证器错误的总数为 0。实际验证是在“绑定”阶段完成的 ($form->bind() )。

绑定后,验证器错误存储在表单的每个字段中(sfFormField)。因此,要获取表单字段的个别错误,您可以执行以下操作:

<?php
  foreach ($form as $formField) { // $formField is an instance of sfFormField
    if ($formField->hasError()) {
      // do something
    }
  }
?>

或者,由于在您的情况下您只需要处理一组受限制的字段,请尝试迭代一个字段名称数组:

<?php
  $fieldNames = array('name', 'email', 'address');
  foreach ($fieldNames as $fieldName) {
    if ($form[$fieldName]->hasError()) {
      // do something
    }
  }
?>

这可以很容易地调整为满足 DRY 期望的函数,例如 validateFields($fieldNames)

查看sfFormField 的文档,了解您可以从字段中获得哪些其他信息。

【讨论】:

    猜你喜欢
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 2021-10-05
    • 2016-02-18
    相关资源
    最近更新 更多