27
votes

I would like to apply validators on a object properties only when value is not empty ie.

Now standard symfony behavior:

class Entity
{
    /**
     * @ORM\Column(type="string", nullable=true)
     * @Assert\Email()
     */
    protected $email;
    (...)
}

that object will not pass validation if an email is null, or empty string, is there a way to tell validator to assert as a valid, an empty value, and validate only if field has data?

PS I know that I can write callback validator, but writting callback for every field just to have "allowEmpty" feature isn't so nice.

6

6 Answers

27
votes

You must explicitly set 'required' => false in your FormBuilder class for all optional fields. Here's a paragraph describing field type options.


Edit. Getting quite a few downvotes. By default all validators treat null values as valid, except NotNull and NotEmpty. Neither of the two was used in the question. The question is implicitly about how to turn off the client-side required attribute that is turned on by default.

20
votes

Setting the required option is not the solution:

Also note that setting the required option to true will not result in server-side validation to be applied. In other words, if a user submits a blank value for the field (either with an old browser or web service, for example), it will be accepted as a valid value unless you use Symfony's NotBlank or NotNull validation constraint.

http://symfony.com/doc/current/book/forms.html#field-type-options

For my custom validators, I add a

if (null == $value) {
    return true;
}

to the isValid() method. However, I'm not sure what would be the best way for the standard validator classes.

3
votes

if i understand correctly you want server side validation only if value is entered. I am exactly in the same scenario. I want to validate a URL only if the URL is provided. The best way i came across was to write my own custom validation class. You can write a generic custom validation class.

I followed this link https://symfony-docs-chs.readthedocs.org/en/2.0/cookbook/validation/custom_constraint.html except for few changes because of symfony's latest version. Here is the implementation

Acme\BundleNameBundle\Validator\Constraints\cstmUrl

namespace Acme\BundleNameBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Url;

/**
 * @Annotation
 */
class CstmUrl extends Url
{
    public $message = 'The URL "%string%" is not valid';
}

Acme\BundleNameBundle\Validator\Constraints\cstmUrlValidator

namespace Acme\BundleNameBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Url;
use Symfony\Component\Validator\Constraints\UrlValidator;

class CstmUrlValidator extends UrlValidator
{
    public function validate($value, Constraint $constraint)
    {
        if(!$value || empty($value))
            return true;

        parent::validate($value, $constraint);
    }
}

Validtion.yml

Acme\BundleNameBundle\Entity\Student:
    Url:
        - Acme\BundleNameBundle\Validator\Constraints\CstmUrl: ~

inside Controller just bind the constraint you normally would do

'constraints'=> new CstmUrl(array("message"=>"Invalid url provided"))

I am sure there can be other better ways of doing it, but for now i feel this does the job well.

2
votes

Just in case anyone else comes across this same question. I prefer to personally solve it by adding the following attribute inside my Twig template:

{{ form_row(form.<field>, {'required': false}) }}
1
votes

Here is the trick I found actually :

https://github.com/symfony/symfony/issues/5906

You need to write a data transformer that does nothing, and then add it to your field. After that, juste call the submit() method with the second param to false.

Note that it's ok with Symfony 2.3.

0
votes

The Field Type Guessing handle this. http://symfony.com/doc/current/book/forms.html#field-type-guessing

It's depends on your form declaration : "The "guessing" is activated when you omit the second argument to the add() method (or if you pass null to it). If you pass an options array as the third argument (done for dueDate above), these options are applied to the guessed field."