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 br
The function isValid()
doesn't really do anything, except check if the associated form has been bound and that the total number of validator errors is 0. The actual validation is done during the "binding" stage ($form->bind()
).
After binding, validator errors are stored in each field of the form(sfFormField). So, to get the individual errors of form fields, you can do something like this:
<?php
foreach ($form as $formField) { // $formField is an instance of sfFormField
if ($formField->hasError()) {
// do something
}
}
?>
Or, since in your case you need to deal with only a restricted set of fields, try to iterate over an array of field names instead:
<?php
$fieldNames = array('name', 'email', 'address');
foreach ($fieldNames as $fieldName) {
if ($form[$fieldName]->hasError()) {
// do something
}
}
?>
This can easily be adapted into a function, say validateFields($fieldNames)
that meets DRY expectations.
Check the documentation for sfFormField to see what other information you can get from a field.
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!