Symfony2基于两个字段进行表单验证

时间:2022-10-22 18:22:14

I am currently developing a Website in which user may buy gift cards. I am using a three step form using the CraueFormFlow bundle and everything is concerning the steps. I am able to validate every simple Assert (like not blank, email, repeated fields, etc) but I am facing the situation where, user may select 0 gift cards and proceed to the next page.

我目前正在开发一个用户可以购买礼品卡的网站。我正在使用一个使用CraueFormFlow bundle的三步表单,所有内容都与步骤相关。我可以验证每个简单的断言(比如不空白、电子邮件、重复字段等),但我面临的情况是,用户可能选择0礼品卡并继续进入下一页。

The users may choose the quantity of giftcards they want to buy using two separate : one for 25$ gift cards and one for 50$ gift cards. So I can't just put a validator saying "value 0 is not allowed". The validator must prevent a user from leaving the quantity "0" in both amount (25$ and 50$).

用户可以使用两种不同的礼品卡:一种是25美元的礼品卡,另一种是50美元的礼品卡。所以我不能只放一个验证器说“值0是不允许的”。验证器必须防止用户将两个数量(25美元和50美元)都保留为“0”。

Does anyone know how to make a custom validation looking for the values in two fields?

有人知道如何在两个字段中进行自定义验证吗?

Thanks in advance!

提前谢谢!

5 个解决方案

#1


31  

You have many solutions for this.

你有很多解。

The easiest one is to add a Callback constraint to your model class.

最简单的方法是向模型类添加回调约束。

Another way to do it would be to create your custom constraint and its associated validator. You have a cookbook explaining how to create a custom validation constrain. This is the best approach to do it.

另一种方法是创建自定义约束及其关联的验证器。您有一本说明如何创建自定义验证约束的食谱。这是最好的方法。

As your constraint does not apply to a property but to a class, you must specify it overriding the the ->getTargets() method of your constraint class:

由于约束不适用于属性,而是应用于类,所以必须指定它覆盖约束类的->getTargets()方法:

class MyConstraint extends Constraint
{
    // ...

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

So the value passed as $value argument of the ->isValid() method will contain values of the whole class and not only of a single property.

因此,作为->isValid()方法的$value参数传递的值将包含整个类的值,而不仅仅是单个属性的值。

#2


12  

When you don't have a data class attached to your form you can implement dependent constraints in forms like this:

当您的表单没有附加数据类时,您可以以如下形式实现依赖约束:

    $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,

        )
    );

#3


5  

This is how I've done this in my validation constraints, to check credit card validity with expiration month and year properties.

这就是我在验证约束中所做的,用过期月份和年份属性检查信用卡有效性。

In this class, I check the value of expirationYear property and compare it with value of expirationMonth property got from contextObject.

在这个类中,我检查expirationYear属性的值,并将其与上下文中的expirationMonth属性的值进行比较。

/**
 * 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;
}

Of course, you have to authorize class and properties constraints in your getTargets method, form the main constraint file.

当然,您必须在getTargets方法中授权类和属性约束,形成主约束文件。

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

Further explanations and complete tutorial here: http://creativcoders.wordpress.com/2014/07/19/symfony2-two-fields-comparison-with-custom-validation-constraints/

这里有进一步的解释和完整的教程:http://creativcoders.wordpress.com/2014/07/19/symfony2-two-fields-comparison-with-custom-validation-constraints/

#4


3  

Use Regular expression inorder to prevent Zero

使用正则表达式来防止零

In your Entity class write down the below override function , and specify your property which you need to validate.

在实体类中写下下面的重写函数,并指定需要验证的属性。

The below example is for validating a pincode ,here in pincode field I admit only numbers 0-9 combinations upto 10 digits .

下面的示例用于验证一个pincode,在这里的pincode字段中,我只允许数字0-9组合到10位。

" ^\d+$ " this is the regular expression I used to prevent other characters.

“^ \ d + $”这是我用来防止其他字符的正则表达式。

For overriding this function you must include the below classes

要覆盖此函数,必须包含以下类

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')));


    }

Not forget these all must

别忘了这些都是必须的

included in your Entity class

包含在实体类中

that you have to validate. So in your case use a proper regular expression which does not permit '0'.

你必须验证。因此,在你的例子中,使用一个不允许“0”的正则表达式。

Happy coding

快乐的编码

#5


2  

I'd suggest using Expression constraint. This constraint can be applied on form field or (preferably) in entity:

我建议使用表达式约束。此约束可应用于表单字段或(最好)实体:

   /**
     * @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;

#1


31  

You have many solutions for this.

你有很多解。

The easiest one is to add a Callback constraint to your model class.

最简单的方法是向模型类添加回调约束。

Another way to do it would be to create your custom constraint and its associated validator. You have a cookbook explaining how to create a custom validation constrain. This is the best approach to do it.

另一种方法是创建自定义约束及其关联的验证器。您有一本说明如何创建自定义验证约束的食谱。这是最好的方法。

As your constraint does not apply to a property but to a class, you must specify it overriding the the ->getTargets() method of your constraint class:

由于约束不适用于属性,而是应用于类,所以必须指定它覆盖约束类的->getTargets()方法:

class MyConstraint extends Constraint
{
    // ...

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

So the value passed as $value argument of the ->isValid() method will contain values of the whole class and not only of a single property.

因此,作为->isValid()方法的$value参数传递的值将包含整个类的值,而不仅仅是单个属性的值。

#2


12  

When you don't have a data class attached to your form you can implement dependent constraints in forms like this:

当您的表单没有附加数据类时,您可以以如下形式实现依赖约束:

    $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,

        )
    );

#3


5  

This is how I've done this in my validation constraints, to check credit card validity with expiration month and year properties.

这就是我在验证约束中所做的,用过期月份和年份属性检查信用卡有效性。

In this class, I check the value of expirationYear property and compare it with value of expirationMonth property got from contextObject.

在这个类中,我检查expirationYear属性的值,并将其与上下文中的expirationMonth属性的值进行比较。

/**
 * 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;
}

Of course, you have to authorize class and properties constraints in your getTargets method, form the main constraint file.

当然,您必须在getTargets方法中授权类和属性约束,形成主约束文件。

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

Further explanations and complete tutorial here: http://creativcoders.wordpress.com/2014/07/19/symfony2-two-fields-comparison-with-custom-validation-constraints/

这里有进一步的解释和完整的教程:http://creativcoders.wordpress.com/2014/07/19/symfony2-two-fields-comparison-with-custom-validation-constraints/

#4


3  

Use Regular expression inorder to prevent Zero

使用正则表达式来防止零

In your Entity class write down the below override function , and specify your property which you need to validate.

在实体类中写下下面的重写函数,并指定需要验证的属性。

The below example is for validating a pincode ,here in pincode field I admit only numbers 0-9 combinations upto 10 digits .

下面的示例用于验证一个pincode,在这里的pincode字段中,我只允许数字0-9组合到10位。

" ^\d+$ " this is the regular expression I used to prevent other characters.

“^ \ d + $”这是我用来防止其他字符的正则表达式。

For overriding this function you must include the below classes

要覆盖此函数,必须包含以下类

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')));


    }

Not forget these all must

别忘了这些都是必须的

included in your Entity class

包含在实体类中

that you have to validate. So in your case use a proper regular expression which does not permit '0'.

你必须验证。因此,在你的例子中,使用一个不允许“0”的正则表达式。

Happy coding

快乐的编码

#5


2  

I'd suggest using Expression constraint. This constraint can be applied on form field or (preferably) in entity:

我建议使用表达式约束。此约束可应用于表单字段或(最好)实体:

   /**
     * @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;