Question

I am trying to cancel validation in embedded forms based on a value from main form.

By default, embedded forms fields have validator option set to 'required'=>true. So it gets validated like that. If user leave any field blank, the form does not pass validation and blank fields get marked in template (different style).

What I am trying to do is to change option:"required" to false for all fields in embedded form.

I tried to do that in post validator callback method, but it seems that it is not possible that way.

The main form code:

class TestForma extends sfForm
{
  public function configure()
  {

    $this->setWidgets(array(
    'validate_items'    => new sfWidgetFormChoice(array(
            'choices'   => array('no' => 'No', 'yes' => 'Yes'),
            'multiple'   => false,'expanded'=>true,'default' => 'no')),
    ));

   $this->setValidators(array('validate_items' => new sfValidatorPass()));

    $this->widgetSchema->setNameFormat('testforma[%s]');


    $subForm = new sfForm();

    for ($i = 0; $i < 2; $i++)
    {
        $form = new ItemForma();

        $subForm->embedForm($i, $form);
    }
    $this->embedForm('items', $subForm);



    $this->validatorSchema->setPostValidator(
        new sfValidatorCallback(array('callback' => array($this,    'postValidate')))
    );

  }

Post-validator code:

public function postValidate($validator,$values)
{
    $validatorSchema = $this->getValidatorSchema();

    if($values['validate_items']=='no')
    {
        $itemsValidatorSchema = $validatorSchema['items'];
        $itemsFieldsValidatorSchemes = $itemsValidatorSchema->getFields();
        foreach($itemsFieldsValidatorSchemes as $itemValidatorScheme)
        {
            $itemValidatorScheme['color']->setOption('required',false);
            $itemValidatorScheme['shape']->setOption('required',false);
        }
    }

    return $values;
}

Embedded form class:

class ItemForma extends sfForm
{
  public function configure()
  {

    $this->setWidgets(array(
      'color'    => new sfWidgetFormInputText(),
      'shape'   => new sfWidgetFormInput(),
    ));

    $this->setValidators(array(
      'color'    => new sfValidatorString(array('required'=>true)),
      'shape'   => new sfValidatorEmail(array('required'=>true)),
      ));

    $this->widgetSchema->setNameFormat('items[%s]');
  }
}

Template code:

<form action="<?php echo url_for('weather/formiranje')?>" method="post">
        <?php 
        foreach($form->getErrorSchema()->getErrors() as $e)
        {
            echo $e->__toString();
        }
        ?>

  <table>
    <tfoot>
      <tr>
        <td colspan="2">
          <input type="submit" value="OK" />
        </td>
      </tr>
    </tfoot>
    <tbody>
            <tr><th>Main form</th></tr>
      <tr><td><?php echo $form['validate_items']->renderLabel() ?>
                        <span class="<?php echo $form['validate_items']->hasError() ? 'rowError' : ''?>">
                        <?php echo $form['validate_items'] ?></span>

                </td></tr>
            <tr><td>&nbsp;</td></tr>
            <tr><th>Embedded forms</th></tr>
            <?php

            foreach($form['items'] as $item)
            {
                ?>
            <tr>
                <td><span class="<?php echo $item['color']->hasError() ? 'rowError' : ''?>">
                                                    <?php echo $item['color']->renderLabel() ?>
                                                    <?php echo $item['color'] ?></span>
                </td>
            </tr>
            <tr>
                <td><span class="<?php echo $item['shape']->hasError() ? 'rowError' : ''?>">
                    <?php echo $item['shape']->renderLabel() ?>
                        <?php echo $item['shape'] ?></span>
                </td></tr>
                <?php
            }
            echo $form['_csrf_token'];
            ?>
    </tbody>
  </table>
</form>
Was it helpful?

Solution

The way you organised it won't work because the post validator is run after all the field validators, so they've already been checked and marked as failed. (because the fields were required).

You could try the same approach you have here but with setting a preValidator instead of a postValidator. I think it should work then.

If it still won't work as expected what I would do is to change the default settings on the embedded form's fields to 'required' = false and use the postValidator. In the validator you could check whether or not you need to validate the embedded fields. If you need to validate them you can check if their values are set and if not you can throw errors for those fields. (I hope this is explained clearly)

Another thing you could try is to re-run the validation for the chosen fields. So something like that in your postValidator:

$itemValidatorScheme['color']->setOption('required',false);
$itemValidatorScheme['color']->clean($values['name_of_the_field']);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top