Проверка формы Symfony2 на основе двух полей

В настоящее время я занимаюсь разработкой веб-сайта, на котором пользователь может покупать подарочные карты. Я использую трехэтапную форму, используя пакет CraueFormFlow, и все касается шагов. Я могу проверить каждый простой Assert (например, не пустое, электронное письмо, повторные поля и т. Д.), Но я сталкиваюсь с ситуацией, когда пользователь может выбрать 0 подарочных карт и перейти на следующую страницу.

Пользователи могут выбрать количество подарочных карт, которые они хотят купить, используя две отдельные: одну за 25$ подарочные карты и одну за 50$ подарочные карты. Поэтому я не могу просто поставить валидатор, говорящий "значение 0 не разрешено". Валидатор должен запретить пользователю оставлять количество "0" в обеих суммах (25$ и 50$).

Кто-нибудь знает, как сделать пользовательскую проверку, ища значения в двух полях?

Заранее спасибо!

5 ответов

Решение

У вас есть много решений для этого.

Самый простой - добавить ограничение Callback в класс вашей модели.

Еще один способ сделать это - создать собственное ограничение и связанный с ним валидатор. У вас есть кулинарная книга, объясняющая, как создать пользовательское ограничение проверки. Это лучший подход для этого.

Поскольку ваше ограничение относится не к свойству, а к классу, вы должны указать его, переопределяя ->getTargets() метод вашего класса ограничений:

class MyConstraint extends Constraint
{
    // ...

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

Таким образом, значение передается как $value аргумент ->isValid() Метод будет содержать значения всего класса, а не только одного свойства.

Если у вас нет класса данных, присоединенного к вашей форме, вы можете реализовать зависимые ограничения в формах, подобных этой:

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

        )
    );

Вот как я сделал это в моих ограничениях проверки, чтобы проверить действительность кредитной карты со свойствами месяца и года истечения срока действия.

В этом классе я проверяю значение свойства expirationYear и сравниваю его со значением свойства expirationMonth, полученного из 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;
}

Конечно, вы должны авторизовать ограничения класса и свойств в вашем методе getTargets, сформировать основной файл ограничений.

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

Дополнительные объяснения и полный учебник здесь: http://creativcoders.wordpress.com/2014/07/19/symfony2-two-fields-comparison-with-custom-validation-constraints/

Используйте Регулярное выражение, чтобы предотвратить Ноль

В своем классе Entity запишите приведенную ниже функцию переопределения и укажите свойство, которое необходимо проверить.

Приведенный ниже пример предназначен для проверки пин-кода. Здесь, в поле пин-кода, я допускаю только комбинации чисел от 0-9 до 10 цифр.

"^ \ d + $" - это регулярное выражение, которое я использовал для предотвращения появления других символов.

Для переопределения этой функции вы должны включить следующие классы

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


    }

Не забывай это все должны

включен в ваш класс Entity

что вы должны подтвердить. Так что в вашем случае используйте правильное регулярное выражение, которое не допускает '0'.

Удачного кодирования

Я бы предложил использовать ограничение Expression. Это ограничение может быть применено к полю формы или (предпочтительно) в сущности:

   /**
     * @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;
Другие вопросы по тегам