symfony 形式的另一个日期之后的日期

Date after another date in symfony form

我有一个包含 2 个日期的表单:开始日期 (datedebut) 和结束日期 (datefin)。 我希望结束日期始终在开始日期之后。我该怎么做?

我的表单类型:

class ReservationType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('datedebut',DateType::class,array(
                'widget' => 'choice',
                'years' => range(date('Y'), date('Y')+20),
            ))
            ->add('datefin',DateType::class,array(
                'widget' => 'choice',
                'years' => range(date('Y'), date('Y')+20),
            ))
            ->add('nbplaces')
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Bridge\TravelBundle\Entity\Reservation'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'Bridge_TravelBundle_Reservation';
    }
}

通常这类任务是通过添加验证约束来检查一个字段的值是否大于另一个字段来解决的。按照文档中的说明实施 callback 验证约束:http://symfony.com/doc/current/reference/constraints/Callback.html You can also create your custom class constraint validator and place validation logic there: http://symfony.com/doc/current/validation/custom_constraint.html

这样,每当用户尝试提交小于选定值 datedebutdatefin 值时,他将看到验证错误并且不会处理表单。

之后,您始终可以添加一些 javascript 代码,以便在 datedebut 字段中的值更改后过滤 datefin 字段中的可用日期。

您也可以使用动态表单修改来呈现第二个日期字段(并在服务器端过滤其可用日期),仅当第一个日期字段的值已提交时。看看这个:http://symfony.com/doc/current/form/dynamic_form_modification.html

您可以为此使用 Callback Validator。注入该回调的是一个 ExecutionContextInterface,您可以通过它访问表单,从而访问其他表单参数。

这是一个例子:

use Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

// …

$builder
    ->add('start', 'datetime', 
        'constraints' => [
            new Constraints\NotBlank(),
            new Constraints\DateTime(),
        ],
    ])
    ->add('stop', 'datetime', [
        'constraints' => [
            new Constraints\NotBlank(),
            new Constraints\DateTime(),
            new Constraints\Callback(function($object, ExecutionContextInterface $context) {
                $start = $context->getRoot()->getData()['start'];
                $stop = $object;

                if (is_a($start, \DateTime::class) && is_a($stop, \DateTime::class)) {
                    if ($stop->format('U') - $start->format('U') < 0) {
                        $context
                            ->buildViolation('Stop must be after start')
                            ->addViolation();
                    }
                }
            }),
        ],
    ]);