You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Symfony DateType表单POST_SUBMIT事件中获取DateTime对象而非字符串?

如何在自定义Symfony DateType字段中获取验证后的DateTime对象

我想要创建一个基于DateType的自定义Symfony表单字段类型,以便在表单提交时对数据执行特定逻辑。

class CustomDateType extends AbstractType {
        ...

        public function getParent(): string {
            return DateType::class;
        }

        public function buildForm(FormBuilderInterface $builder, array $options) {
            $builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
            $data = $event->getData();                
            $this->logger->info('PRE: '.gettype($data));
        });

        $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
            $data = $event->getData();                
            $this->logger->info('POST: '.gettype($data));
        });
    }
}

输出结果:

PRE: string
POST: string

在PRE_SUBMIT和POST_SUBMIT事件中,数据均为普通字符串而非DateTime实例。是否有办法获取经过验证后的最终DateTime对象?

编辑1:
当然我可以自行将字符串转换为DateTime对象。但底层的DateType类可配置为仅接受特定格式、日期范围等。自行重新实现所有这些转换、校验等逻辑虽然可行,但非常繁琐,相当于重复造轮子。是否有某个事件或方式可以获取底层DateType处理完成后的最终DateTime对象?

编辑2:
尝试从数据字符串手动创建DateTime对象的另一个问题是格式未知。虽然可以从DateType字段的选项中查询格式,但它使用的是ICU日期格式字符串,而PHP使用的是不同的格式字符串。例如,如果日期字段使用dd.MM.yyyy格式,将其用于DateTime::createFromFormat('dd.MM.yyyy', $data)会是无效格式。


解决方案:监听FormEvents::SUBMIT事件

你需要使用FormEvents::SUBMIT事件,该事件会在字段完成数据转换(字符串→DateTime)和验证后触发,此时能直接获取到最终的DateTime对象。调整代码如下:

use Symfony\Component\Form\FormEvents;

class CustomDateType extends AbstractType {
    // ... 注入logger等依赖

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->addEventListener(FormEvents::SUBMIT, function(FormEvent $event) {
            $data = $event->getData();                
            $this->logger->info('SUBMIT: '.gettype($data)); // 输出: SUBMIT: object
            if ($data instanceof \DateTimeInterface) {
                // 在这里编写针对DateTime对象的自定义逻辑
                $this->logger->info('处理后的日期: '.$data->format('Y-m-d'));
            }
        });
    }

    public function getParent(): string {
        return DateType::class;
    }
}

事件优先级说明

  • PRE_SUBMIT:仅能获取原始提交的字符串数据,未经过DateType的转换处理
  • SUBMIT:字段专属事件,在父类DateType的转换器完成数据转换后触发,确保拿到转换后的DateTime对象
  • POST_SUBMIT:针对整个表单树的后置事件,若监听优先级高于父类处理逻辑,仍可能拿到未转换的原始数据

复用内置转换器(可选)

若因特殊需求需手动处理格式转换,可直接复用Symfony内置的StringToDateTimeTransformer,它已封装了ICU格式与PHP格式的转换逻辑,无需重复造轮子:

use Symfony\Component\Form\Extension\Core\DataTransformer\StringToDateTimeTransformer;

public function buildForm(FormBuilderInterface $builder, array $options) {
    // 初始化内置转换器,复用DateType的配置参数
    $transformer = new StringToDateTimeTransformer(
        $options['model_timezone'],
        $options['view_timezone'],
        $options['input'],
        $options['format']
    );

    $builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) use ($transformer) {
        $rawData = $event->getData();
        try {
            $dateTime = $transformer->reverseTransform($rawData);
            // 处理转换后的DateTime对象
        } catch (\Exception $e) {
            // 复用DateType的错误处理逻辑,避免自定义校验重复造轮子
        }
    });
}

内容的提问来源于stack exchange,提问作者Andrei Herford

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:54:17