web-dev-qa-db-fra.com

Symfony2 Formidation de la validation basée sur deux champs

Je développe actuellement un site Web dans lequel l'utilisateur peut acheter des cartes-cadeaux. J'utilise un formulaire en trois étapes en utilisant le paquet CraeformFlow et tout concerne les étapes. Je suis capable de valider tout simple assert (comme non vide, email, champs répétés, etc.) mais je suis confronté à la situation où, l'utilisateur peut sélectionner 0 cartes-cadeaux et passer à la page suivante.

Les utilisateurs peuvent choisir la quantité de cartes-cadeaux qu'ils veulent acheter en utilisant deux séparés: un pour 25 cartes-cadeaux de $ et un pour 50 cartes-cadeaux de $. Je ne peux donc pas simplement mettre un validateur disant "la valeur 0 n'est pas autorisée". Le validateur doit empêcher un utilisateur de quitter la quantité "0" à la fois (25 $ et 50 $).

Est-ce que quelqu'un sait faire une validation personnalisée à la recherche des valeurs dans deux champs?

Merci d'avance!

21

Vous avez de nombreuses solutions pour cela.

Le plus facile est d'ajouter une contrainte de rappel à votre classe modèle.

Une autre façon de le faire serait de créer votre contrainte personnalisée et son validateur associé. Vous avez un Cookbook expliquant comment créer une contrainte de validation personnalisée . C'est la meilleure approche pour le faire.

Au fur et à mesure que votre contrainte ne s'applique pas à une propriété mais à une classe, vous devez spécifier qu'il remplace la méthode ->getTargets() méthode de votre classe de contrainte:

class MyConstraint extends Constraint
{
    // ...

    public function getTargets()
    {
        return Constraint::CLASS_CONSTRAINT;
    }
}

Donc, la valeur passée en tant que $value Argument de la méthode ->isValid() contiendra des valeurs de la classe entière et non seulement d'une seule propriété.

38
Herzult

Lorsque vous n'avez pas de classe de données attachée à votre formulaire, vous pouvez mettre en œuvre des contraintes dépendantes dans des formulaires comme celui-ci:

    $startRangeCallback = function ($object, ExecutionContextInterface $context) use ($form)
    {
        $data = $form->getData();
        $rangeEnd = $data['range_end'];
        if($object && $rangeEnd){
            if ($object->getTimestamp() > $rangeEnd->getTimestamp()) {
                $context->addViolation('Start date should be before end date!', array(), null);
            }
        }

    };

    $form->add('range_start', 'bootstrap_datepicker', array(
            'format' => 'dd-MM-yyyy',
            'required' => false,
            'attr' => array('class' => "col-xs-2"),
            'calendar_weeks' => true,
            'clear_btn' => true,
            'constraints' => array(
                new Callback(array($startRangeCallback)),
            )
        )
    );

    $form->add('range_end', 'bootstrap_datepicker', array(
            'format' => 'dd-MM-yyyy',
            'required' => false,
            'attr' => array('class' => "col-xs-2"),
            'calendar_weeks' => true,
            'clear_btn' => true,

        )
    );
12
user3048950

C'est comme ça que j'ai fait cela dans mes contraintes de validation, pour vérifier la validité des cartes de crédit avec les propriétés de l'expiration et des propriétés de l'année.

Dans cette classe, je vérifie la valeur de l'expirationyear Property et la comparer avec la valeur de la propriété expirationMonth gère de contextObject.

/**
 * Method to validate
 * 
 * @param string                                  $value      Property value    
 * @param \Symfony\Component\Validator\Constraint $constraint All properties
 * 
 * @return boolean
 */
public function validate($value, Constraint $constraint)
{
    $date               = getdate();
    $year               = (string) $date['year'];
    $month              = (string) $date['mon'];

    $yearLastDigits     = substr($year, 2);
    $monthLastDigits    = $month;
    $otherFieldValue    = $this->context->getRoot()->get('expirationMonth')->getData();

    if (!empty($otherFieldValue) && ($value <= $yearLastDigits) && 
            ($otherFieldValue <= $monthLastDigits)) {
        $this->context->addViolation(
            $constraint->message,
            array('%string%' => $value)
        );            
        return false;            
    }

    return true;
}

Bien sûr, vous devez autoriser des contraintes de classe et de propriétés dans votre méthode GetTartgets, formez le fichier de contrainte principale.

/**
 * Get class constraints and properties
 * 
 * @return array
 */
public function getTargets()
{
    return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT);
} 

Explications supplémentaires et tutoriel complet ici: http://creativcoders.wordpress.com/2014/07/19/symfony2-two-fields-comparison-with-Constom-validation-constraint/

7
Edouard Kombo

Utilisez une expression régulière dans l'utilisateur pour empêcher zéro

Dans votre classe d'entité, écrivez la fonction de remplacement ci-dessous et spécifiez votre propriété que vous devez valider.

L'exemple ci-dessous consiste à valider un PinCode, ici dans le champ Pincode, j'admet que les numéros 0 à 9 combinaisons jusqu'à 10 chiffres.

"^\d + $" C'est l'expression régulière que j'ai utilisée pour empêcher d'autres personnages.

Pour remplacer cette fonction, vous devez inclure les classes ci-dessous

use Symfony\Component\Validator\Mapping\ClassMetadata;// for overriding function loadValidatorMetadata()

use Symfony\Component\Validator\Constraints\NotBlank;// for notblank constrain

use Symfony\Component\Validator\Constraints\Email;//for email constrain

use Symfony\Component\Validator\Constraints\MinLength;// for minimum length

use Symfony\Component\Validator\Constraints\MaxLength; // for maximum length

use Symfony\Component\Validator\Constraints\Choice; // for choice fields

use Symfony\Component\Validator\Constraints\Regex; // for regular expression



public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('pincode', new NotBlank(array('message' => 'Does not blank')));
        $metadata->addPropertyConstraint('pincode', new Regex(array('pattern'=>'/^\d+$/','message' => 'must be number')));
        $metadata->addPropertyConstraint('pincode', new MaxLength(array('limit'=>'6','message' => 'must maximum 6 digits')));
        $metadata->addPropertyConstraint('pincode', new MinLength(array('limit'=>'6','message' => 'must minimum 6 digits')));


    }

Pas oublier ces tous doivent

inclus dans votre classe d'entité

que vous devez valider. Donc, dans votre cas, utilisez une expression régulière appropriée qui ne permet pas '0'.

Joyeux codage

3
Asish AP

Je suggérerais d'utiliser contrainte d'expression . Cette contrainte peut être appliquée sur le champ de formulaire ou (de préférence) en entité:

   /**
     * @var int
     * @Assert\Type(type="integer")
     */
    private $amountGiftCards25;

    /**
     * @var int
     * @Assert\Type(type="integer")
     * @Assert\Expression(expression="this.getAmountGiftCards25() > 0 or value > 0", message="Please choose amount of gift cards.")
     */
    private $amountGiftCards50;
3
Draex_