Symfony 7:如何将EffectType表单所有字段转为拼接字符串
问题:将自定义FormType的多字段合并为字符串持久化到数据库
我自定义了一个名为EffectType的FormType,代码如下,该表单被另一个FormType通过->add('effect', EffectType::class)引用。我希望将EffectType的所有字段(action、element、effect_str)转换为If {action} {element} Then {effect_str}格式的字符串并持久化到数据库中。尝试使用DataTransformers但不知如何操作,不清楚应将其添加到父表单还是EffectType本身,参考DateType也因不理解其流程未成功。
class EffectType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('action', ChoiceType::class, [ 'choices' => [ 'Test' => [ 'Take'=>'Take', 'Ok'=>'Ok' ] ] ]) ->add('element', ChoiceType::class, [ 'choices' => [ 'Other' => [ 'Test'=>'Test', ] ] ]) ->add('effect_str', TextType::class) ; } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'project' => null ]); } public function getBlockPrefix(): string { return 'effect'; } }
解决方案
1. 创建数据转换器
写一个转换器类,负责在表单提交的数组数据和数据库存储的字符串之间双向转换:
// src/Form/DataTransformer/EffectToStringTransformer.php namespace App\Form\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; class EffectToStringTransformer implements DataTransformerInterface { // 把数据库的字符串转成表单需要的数组格式 public function transform($value) { if (null === $value) { return ['action' => '', 'element' => '', 'effect_str' => '']; } // 解析目标格式的字符串,提取字段值 preg_match('/If (\w+) (\w+) Then (.+)/', $value, $matches); if (count($matches) !== 4) { throw new TransformationFailedException('无效的effect格式'); } return [ 'action' => $matches[1], 'element' => $matches[2], 'effect_str' => $matches[3], ]; } // 把表单提交的数组转成数据库存储的字符串 public function reverseTransform($value) { if (!is_array($value) || empty($value['action']) || empty($value['element']) || empty($value['effect_str'])) { throw new TransformationFailedException('请填写所有effect字段'); } return sprintf('If %s %s Then %s', $value['action'], $value['element'], $value['effect_str']); } }
2. 在EffectType中注册转换器
直接在EffectType的buildForm方法里给整个表单添加转换器,这样所有字段的提交数据都会经过转换:
// 修改后的EffectType.php namespace App\Form\Type; use App\Form\DataTransformer\EffectToStringTransformer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class EffectType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('action', ChoiceType::class, [ 'choices' => [ 'Test' => [ 'Take'=>'Take', 'Ok'=>'Ok' ] ] ]) ->add('element', ChoiceType::class, [ 'choices' => [ 'Other' => [ 'Test'=>'Test', ] ] ]) ->add('effect_str', TextType::class) ; // 给整个表单添加数据转换器 $builder->addModelTransformer(new EffectToStringTransformer()); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'project' => null, // 设置空数据为数组,适配转换器的输入格式 'empty_data' => [], ]); } public function getBlockPrefix(): string { return 'effect'; } }
3. 父表单使用说明
父表单中引用EffectType的代码不需要修改,保持->add('effect', EffectType::class)即可。数据库中对应的effect字段设置为字符串类型(比如VARCHAR(255)或TEXT),框架会自动处理转换逻辑:
- 表单提交时,转换器把三个字段的数组转成目标字符串,存入数据库
- 从数据库读取数据时,转换器把字符串解析成数组,自动填充到表单的三个字段中
内容的提问来源于stack exchange,提问作者Julien Gidel
相关产品推荐
相关产品推荐

