如何在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
相关产品推荐
相关产品推荐

