web-dev-qa-db-fra.com

Comment autoriser les valeurs vides dans les validateurs symfony2

Je voudrais appliquer des validateurs sur les propriétés d'un objet uniquement lorsque la valeur n'est pas vide, c'est-à-dire.

Maintenant comportement standard de symfony:

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

cet objet ne passera pas la validation si un email a la valeur null, ou une chaîne vide, existe-t-il un moyen d'indiquer au validateur d'affirmer que la valeur est valide, vide et qu'elle n'est validée que si le champ contient des données?

PS Je sais que je peux écrire un validateur de rappel, mais écrire un rappel pour chaque champ juste pour avoir la fonction "allowEmpty" n'est pas très agréable.

25
canni

Vous devez explicitement définir 'required' => false dans votre classe FormBuilder pour tous les champs facultatifs. Voici un paragraphe décrivant les options de type de champ .


Modifier. Obtenir quelques critiques négatives. Par défaut, tous validateurs traitent les valeurs null comme valides, saufNotNull et NotEmpty. Aucune des deux n'a été utilisée dans la question. La question porte implicitement sur la façon de désactiver l'attribut required côté client activé par défaut.

25
gilden

La définition de l'option required n'est pas la solution:

Notez également que la définition de l'option requise sur true n'entraînera pas l'application d'une validation côté serveur. En d'autres termes, si un utilisateur soumet une valeur vide pour le champ (avec un ancien navigateur ou un service Web, par exemple), elle sera acceptée comme valeur valide sauf si vous utilisez la contrainte de validation NotBlank ou NotNull de Symfony.

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

Pour mes validateurs personnalisés, j'ajoute un 

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

à la méthode isValid(). Cependant, je ne sais pas quel serait le meilleur moyen pour les classes de validateur standard.

20
David de Boer

si je comprends bien, vous voulez une validation côté serveur uniquement si la valeur est entrée. Je suis exactement dans le même scénario. Je souhaite valider une URL uniquement si celle-ci est fournie. Le meilleur moyen que j'ai rencontré était d'écrire ma propre classe de validation personnalisée. Vous pouvez écrire une classe de validation personnalisée générique.

J'ai suivi ce lien https://symfony-docs-chs.readthedocs.org/en/2.0/cookbook/validation/custom_constraint.html à l'exception de quelques modifications en raison de la dernière version de symfony. Voici la mise en oeuvre

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 ne fait que lier la contrainte que vous feriez normalement

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

Je suis sûr qu'il existe d'autres moyens de le faire, mais pour le moment, je pense que cela fait bien son travail.

3
Ahad Ali

Juste au cas où quelqu'un d'autre rencontrerait la même question. Je préfère le résoudre personnellement en ajoutant l'attribut suivant à l'intérieur de mon modèle Twig:

{{ form_row(form.<field>, {'required': false}) }}
2
Anton Babushkin

Voici le truc que j'ai trouvé en réalité:

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

Vous devez écrire un transformateur de données qui ne fait rien, puis l'ajouter à votre champ . Après cela, appelez simplement la méthode submit () avec le deuxième paramètre sur false.

Notez que ça va avec Symfony 2.3.

1
choomz

Le type de champ Guessing gère cela . http://symfony.com/doc/current/book/forms.html#field-type-guessing

Cela dépend de votre déclaration de formulaire: "Le" devin "est activé lorsque vous omettez le deuxième argument de la méthode add () (ou si vous lui passez la valeur null). Si vous passez un tableau d'options comme troisième argument (fait pour dueDate ci-dessus), ces options sont appliquées au champ deviné. "

0
David