How to allow empty values in symfony2 validators

34,744

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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}) }}

Solution 5

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.

Share:
34,744

Related videos on Youtube

canni
Author by

canni

Just another salsa dancer ;)

Updated on July 09, 2022

Comments

  • canni
    canni almost 2 years

    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.

  • Vlad
    Vlad over 11 years
    This is not the correct answer. 'required' option enforces only client-side validation.
  • kgilden
    kgilden over 11 years
    @TyrionLannister You are indeed correct. However, none of the default validators result in an empty value being treated invalid except when having NotNull() and NotEmpty() constraints. Seeing as the asker had neither of those constraints, it was implicit that the problem was with the client-side HTML5 required attribute.
  • Luke
    Luke over 10 years
    I don't think you want to hard code this in your template. If you want to use the required approach, use gilden's suggestion instead and add it to the form builder..
  • Anton Babushkin
    Anton Babushkin over 10 years
    Yeah in most circumstances I think that would be a better approach (that way the attribute validation requirements propagate across other templates), however in some situations (i.e. simple apps) placing it into a Twig template isn't too terrible :)
  • pscheit
    pscheit about 10 years
    this shouldl be the accepted answer, because the accepted answer only applies for simple fields not for embedded type fields
  • Andrzej Ośmiałowski
    Andrzej Ośmiałowski about 10 years
    @gilden with all due respect, required attribute have nothing common with empty value approved. It's only used by HTML5 client-side validation and it's not related to the validation (the server-side one) at all.
  • kgilden
    kgilden about 10 years
    @AndrzejOśmiałowski absolutely, please check the comment above yours. That's exactly what I said :)
  • tom10271
    tom10271 over 5 years
    What if he simply does not know the correct way to achieve it is to set NotNull or NotEmpty constraint? I found this explanation is hilarious. Even so I am sure he will regret how many bugs he made when he tries to send the form data via XHR with data in JSON format, The form will be passed and you will get nothing. This is exactly what I am facing now. This is an answer to a certain extent only, not a full answer.