How to disable one transformer validation error "dynamically" in Symfony2

1.5k views Asked by At

I have a form with many fields and validation groups, these fields contain some view data transformers too.

I need suppress the validation form partially (Groups based on the Submitted Data):

use AppBundle\Entity\Client;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

// ...
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => function (FormInterface $form) {
            $data = $form->getData();

            if (Client::TYPE_PERSON == $data->getType()) {
                return array('person');
            }

            return array('company');
        },
    ));
}

When you do that, the form will execute the basic integrity checks (Disabling Validation) and the validation errors that coming from the transformers were still thrown (Creating the Transformer).

Use the POST_SUBMIT event and preventing the ValidationListener from being called (Suppressing Form Validation):

use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
        $event->stopPropagation();
    }, 900); // Always set a higher priority than ValidationListener

    // ...
}

It is not a solution for me, since accidentally it disables something more than just the form validation.

The question is: How to disable one transformer validation error "dynamically"?

Example:

I have a form field RepeatedType belonging to person validation group and contains a view transformer (RepeatedType), this transformer throws an exception when the values in the array aren't the same (ValueToDuplicatesTransformer).

So, even when validation group is company, the form shows errors belong to RepeatedType field coming from transformers.

The question here is: How to disable the ValueToDuplicatesTransformer errors when validation group is not person?

3

There are 3 answers

0
Rvanlaak On BEST ANSWER

Because the buildForm misses the code related to adding the fields I assume:

  1. you don't relate the form to an Entity via data_class directly, but set values in your controller
  2. the repeated type has required => true as an option and is there to validate a password
  3. the $data that is passed to the formbuilder contains a value for the repeated field.

The problem basically is that validation is triggered. If there is any data, then the type will always do it's basic validations (the repeated field should have the same value twice).

What you should do to solve this is do not pass the value to $data in the first place, and make sure required => false for the repeated field. Your form will only do the group validation after that, as you already explained.

Maybe the most robust solution is even different, and would it be best to make two FormTypes instead of using the groups. This will remove most of the complexity you describe in your question.

0
jvasseur On

You can't really deactivate errors from a DataTransformer, these errors are added by FormValidator and this behavior is not customizable. This is quite logical since transformation errors leads to the model data being in a broken state.

What I would do in this case is use 2 field instead of a repeated field with the second one with mapped => false and an event listener that add the error manually when needed.

0
Dmitry Malyshenko On

Maybe I'm wrong, but the validation group is not a right tool to solve the problem at all. The dependency of validation rules you want to solve is based on data, while the validation group is not about it, it's about the same data being validating differently depending on context.

If you want to apply some rules only for person (or, the opposite, only for company), I would rather implement custom checking in Client Entity

namespace AppBundle\Entity;

class Client {
....
/**
* @Assert\IsTrue(message="Person should have a valid Title")
*/
public function isPersonTitleValid()
{
  return $this->type != Client::TYPE_PERSON || $this->isTitleValid();
}

public function isTitleValid()
{
  // Here implement your validation applicable only for person;
}