如何逐步“验证”Symfony表单 - 而不是调用$ form-> isValid()

时间:2010-08-23 07:12:34

标签: php symfony1 symfony-forms

我在Ubuntu上使用Symfony 1.3.6。

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

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

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

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

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

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

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

2 个答案:

答案 0 :(得分: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);
}

步骤5:向表单添加一些辅助方法

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
}

我在飞行中完全做到了这一点。我认为它应该可行,但我没有测试过,所以可能会有一些错误!

答案 1 :(得分:1)

函数isValid()实际上没有做任何事情,除了检查关联的表单是否已被绑定以及验证器错误的总数是否为0.实际验证是在“绑定”阶段完成的({ {1}})。

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

$form->bind()

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

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

这可以很容易地适应一个符合DRY预期的<?php $fieldNames = array('name', 'email', 'address'); foreach ($fieldNames as $fieldName) { if ($form[$fieldName]->hasError()) { // do something } } ?> 函数。

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