3

I have form, and need to create inline validation:

$builder
        ->add('Count1', 'integer', [
            'data'        => 1,
            'constraints' => [
                new NotBlank(),
                new NotNull(),
            ],
        ])
        ->add('Count2', 'integer', [
            'constraints' => [
                new NotBlank(),
                new NotNull(),
            ],
        ])
        ->add('Count3', 'integer', [
            'data'        => 0,
            'constraints' => [
                new NotBlank(),
                new NotNull(),
            ],
        ])

How white inline validation Expression for rules

  1. Count2 >=Count1
  2. Count3 <=Count2
  3. Count2 >= $someVariable

4 Answers 4

9

Other solution by using Expression Constraint for cases 1 and 2.

use Symfony\Component\Validator\Constraints as Assert;

// ...

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'constraints' => [
            new Assert\Expression([
                'expression' => 'value["Count2"] >= value["Count1"]',
                'message' => 'count2 must be greater than or equal to count1'
            ]),
            new Assert\Expression([
                'expression' => 'value["Count3"] <= value["Count2"]',
                'message' => 'count3 must be less than or equal to count2'
            ]),
        ],
    ]);
}

For case 3 you can use Assert\GreaterThanOrEqual constraint directly on Count2 field.

I guess your form doesn't have a binding object model, otherwise to read the documentation referred is enough and better because you could use these expression on your properties directly.

Sign up to request clarification or add additional context in comments.

2 Comments

I actually like this answer more than mine own =)
Just a note: from symfony 3 on you should use configureOptions. I'm writing this as setDefaultOptions fails silently (as it's just a simple name)
4

You can utilize CallbackValidator (docs):

In your case, in order to validate one field againt another, you need to add constraint to a form type, not the field:

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'constraints' => array(
            new Assert\Callback(function($data){
                // $data is instance of object (or array) with all properties
                // you can compare Count1, Count2 and Count 3 
                // and raise validation errors
            });
        )
    ));
}

You can also pass constraints option while creating a form if you don't want to set it in setDefaultOptions.

3 Comments

Just a note: from symfony 3 on you should use configureOptions. I'm writing this as setDefaultOptions fails silently (as it's just a simple name)
@DonCallisto very good point. The approach above was first deprecated and then removed altogether...
Please update your answer with an edit for those version of symfony: it would be great! :)
3

Starting from easiest

3) Count2 >= $someVariable

    ->add('Count3', 'integer', [
        'data'        => 0,
        'constraints' => [
            new NotBlank(),
            new NotNull(),
            new GreaterThanOrEqual($someVariable),
        ],
    ])

1) As for two first, you must implement constraint for a class scope, rather than property scope. And assign these constraints for a whole form

public function buildForm(FormBuilderInterface $builder, array $options)
{
   $builder
    ->add('Count1', 'integer', [
        'data'        => 1,
        'constraints' => [
            new NotBlank(),
            new NotNull(),
        ],
    ])
    ->add('Count2', 'integer', [
        'constraints' => [
            new NotBlank(),
            new NotNull(),
        ],
    ])
    ->add('Count3', 'integer', [
        'data'        => 0,
        'constraints' => [
            new NotBlank(),
            new NotNull(),
        ],
    ])
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
     $resolver->setDefaults(['constraints' => [
            new YourCustomConstraint(),
          ]]);
}

How to implement validator, see in the documentation. But in your YourCustomConstraintValidator you will have something like

public function validate($value, Constraint $constraint)
{
     if ($value->getCount1() > $value->getCount2() {
           $this->context->addViolation(...);
     }
}

1 Comment

Just a note: from symfony 3 on you should use configureOptions. I'm writing this as setDefaultOptions fails silently (as it's just a simple name)
1

I had some problem comparing two dates using Symfony's Expressions.

This is the code that works:

 $builder->add(
            'end',
            DateTimeType::class,
            [
                'label' => 'Campaign Ends At',
                'data' => $entity->getEnd(),
                'required' => true,
                'disabled' => $disabled,
                'widget'  => 'single_text',
                'constraints' => [
                    new Assert\GreaterThan(['value' => 'today']),
                    new Assert\Expression(
                                [
                                    //here end and start are the name of two fields
                                    'expression' => 'value > this.getParent()["start"].getData()',
                                    'message' => 'my.form.error.end.date.bigger.than.start'
                                ]
                            ),
                ]

            ]
        );

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.