Symfony CollectionType中如何用数据对象属性作为字段标签?
Symfony CollectionType嵌套表单动态设置子表单标签问题
问题场景
在Symfony框架中,使用CollectionType嵌套ShapeFractionType构建表单时,尝试通过options['data']获取ShapeFraction对象的name属性作为value字段的标签,出现'data'索引不存在的错误。直接使用ShapeFractionType时该逻辑正常,需实现每个输入框以对应ShapeFraction的name作为标签的效果,例如“A: <输入框>、B: <输入框>”。
相关代码
主表单类ShapeType
class ShapeType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('shape_fractions', CollectionType::class, [ 'entry_type' => ShapeFractionType::class, 'entry_options' => ['label' => false], ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Shape::class, ]); } }
Shape数据类
class Shape { public array $shape_fractions; // ... 其他代码 }
ShapeFractionType类
class ShapeFractionType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { // 集合模式下'data'索引不可用,此处报错 $shapeFraction = $options['data']; $builder ->add('value', NumberType::class, [ 'label' => $shapeFraction->name // 错误发生位置 ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => ShapeFraction::class, ]); } }
ShapeFraction数据类
class ShapeFraction { public string $name; public string $type; public float $value; // ... 其他代码 }
表单渲染代码
$shapeFractions = [ new ShapeFraction('A', 'length', 10), new ShapeFraction('B', 'length', 20), ]; $shape = new Shape($shapeFractions); $form = $formFactory->create(ShapeType::class, $shape); // 使用Twig渲染表单...
解决方案
方法一:通过entry_options回调动态传递标签
在ShapeType中配置CollectionType时,利用回调函数将每个子项的name传递给ShapeFractionType:
class ShapeType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('shape_fractions', CollectionType::class, [ 'entry_type' => ShapeFractionType::class, 'entry_options' => function (FormInterface $child, $index) { /** @var ShapeFraction $shapeFraction */ $shapeFraction = $child->getData(); return [ 'label' => $shapeFraction->name, ]; }, ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Shape::class, ]); } }
修改ShapeFractionType直接使用传入的标签:
class ShapeFractionType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('value', NumberType::class, [ 'label' => $options['label'], ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => ShapeFraction::class, 'label' => '', // 设置默认标签避免报错 ]); } }
方法二:利用FormEvents动态设置标签
在ShapeFractionType中监听PRE_SET_DATA事件,待数据绑定后设置标签:
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; class ShapeFractionType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('value', NumberType::class); // 数据加载完成后设置标签 $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { /** @var ShapeFraction $shapeFraction */ $shapeFraction = $event->getData(); $form = $event->getForm(); $form->add('value', NumberType::class, [ 'label' => $shapeFraction->name, ]); }); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => ShapeFraction::class, ]); } }
方法三:Twig模板手动渲染标签
无需修改表单类,直接在视图层控制显示:
{% for fraction in form.shape_fractions %} <label>{{ fraction.vars.data.name }}:</label> {{ form_widget(fraction.value) }} {% endfor %}
问题原因
使用CollectionType时,Symfony初始化子表单阶段尚未完成数据绑定,此时options['data']不存在;而单独使用ShapeFractionType时,表单初始化已绑定数据,因此可正常获取。
内容的提问来源于stack exchange,提问作者sanderbee
相关产品推荐
相关产品推荐

