如何验证 Symfony 表单中的日期,以便用户无法选择当前日期之后的任何日期

问题描述 投票:0回答:1

我有一个面板来获取一些交易,用户可以选择月份和年份并获取该月份和年份的交易。问题是,如果你错误地选择了未来的日期,我会收到一个 sql 错误,因为未来那个月份的表显然不在数据库中。

如何在构建表单中使月份的 ChoiceType 和年份的 IntegerType 不允许用户选择当前月份之后的任何月份或年份?我试图用验证器来完成此操作,但不知道如何使其工作。

我的构建形式是这样的:

       public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $currentDate = $this->myDateTime->getNewDate();

    $builder
        ->add('month', ChoiceType::class, [
            'choices' => array_combine(range(1, 12), range(1, 12)),
            'label' => 'Month:',
            'required' => true,
            'data' => $currentDate->format('m'),
            'attr' => ['class' => 'form-control'],
            'constraints' => [
                new Assert\NotBlank(),
                new Assert\Range([
                    'max' => ($currentDate->format('Y'))
                        ? intval($currentDate->format('m'))
                        : 12,
                    'maxMessage' => 'Please select a valid month.',
                ]),
            ],
        ])
        ->add('year', IntegerType::class, [
            'label' => 'Year:',
            'required' => true,
            'data' => $currentDate->format('Y'),
            'attr' => ['class' => 'form-control'],
            'constraints' => [
                new Assert\NotBlank(),
                new Assert\Range([
                    'max' => intval($currentDate->format('Y')),
                    'maxMessage' => 'Please select a valid year.',
                ]),
            ],
        ])
        ->add('submit', SubmitType::class, [
            'label' => 'Search',
            'attr' => ['class' => 'btn btn-primary ml-2'],
        ]);
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'data_class' => null,
    ]);
}

在我的面板中它看起来像这样:

我有这个验证..但是你现在甚至不能选择1之后的一个月,甚至在2024年之前......而且你仍然可以选择2024年之后的任何一年..

symfony symfony-forms symfony-validator
1个回答
0
投票

我会创建一个自定义验证器。您需要自定义所选月份和年份是否为过去的逻辑。

您可以相应地删除表单定义中的约束定义。

搜索日期约束

namespace App\Validator;

use Symfony\Component\Validator\Constraint;

#[\Attribute]
class SearchDate extends Constraint
{
    public function validatedBy(): string
    {
        return SearchDateValidator::class;
    }

    public function getTargets(): array|string
    {
        return self::CLASS_CONSTRAINT;
    }
}

搜索日期验证器

namespace App\Validator;

use App\Entity\SearchFormEntity;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class SearchDateValidator extends ConstraintValidator
{
    /**
     * @param SearchFormEntity $value
     * @param Constraint $constraint
     *
     * @return void
     */
    public function validate($value, Constraint $constraint): void
    {
        $currentDate = new \DateTime(
            (new \DateTime())->format('Y-m-1 00:00:00')
        );

        $formDate = new \DateTime();
        $formDate->setDate(
            $value->getYear(),
            $value->getMonth(),
            1
        )->setTime(0, 0 , 0);

        if ($formDate >= $currentDate) {
            return;
        }

        $this->context->buildViolation(
            'My error message'
        )->addViolation();
    }
}

搜索表单实体

您在类中定义 SearchDate 约束 (

#[SearchDate]
)。

namespace App\Entity;

use App\Validator\SearchDate;

#[SearchDate]
class SearchFormEntity
{
    private string $month;
    private string $year;

    public function getMonth(): string
    {
        return $this->month;
    }

    public function setMonth(string $month): void
    {
        $this->month = $month;
    }

    public function getYear(): string
    {
        return $this->year;
    }

    public function setYear(string $year): void
    {
        $this->year = $year;
    }
}

功能测试

use App\Entity\SearchFormEntity;
use App\Validator\SearchDate;
use App\Validator\SearchDateValidator;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;

class SearchDateValidatorTest extends ConstraintValidatorTestCase
{
    public function createValidator(): SearchDateValidator
    {
        return new SearchDateValidator();
    }

    public function testMonthInFuture()
    {
        $entity = new SearchFormEntity();
        $entity->setMonth('8');
        $entity->setYear('2024');

        $this->validator->validate($entity, new SearchDate());
        $this->assertNoViolation();
    }

    public function testCurrentMonth()
    {
        $entity = new SearchFormEntity();
        $entity->setMonth('1');
        $entity->setYear('2024');

        $this->validator->validate($entity, new SearchDate());
        $this->assertNoViolation();
    }

    public function testMonthInPast()
    {
        $entity = new SearchFormEntity();
        $entity->setMonth('12');
        $entity->setYear('2023');

        $this->validator->validate($entity, new SearchDate());
        $this->buildViolation('My error message')
            ->assertRaised();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.