2

我在 Ubuntu 上使用 Symfony 1.3.6。

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

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

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

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

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

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

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

4

2 回答 2

3

我将使用不同的方法在 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
}

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

于 2010-08-24T01:42:39.753 回答
1

该函数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
    }
  }
?>

这可以很容易地适应一个函数,比如validateFields($fieldNames)满足 DRY 的期望。

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

于 2010-08-23T09:49:45.603 回答