Symfony 3.3表单集合主题:编辑时渲染已有City实体
这问题我之前在Symfony 3.x里也碰到过,核心原因是你搞混了FormView对象和背后的实体数据——直接遍历form.cities拿到的是表单视图项,不是City实体,所以访问name才会报错。给你两种靠谱的解决思路:
方法一:修改集合主题,自动渲染已有城市项
你原来的collection_widget主题只处理了原型生成,完全没管已有的城市项渲染。其实可以在主题里直接遍历表单的子视图,再从子视图里拿到对应的City实体:
修改后的cities集合主题文件:
{% block collection_widget %} {% import '@Prototype/prototype.city.twig' as proto %} {% spaceless %} <div class="collection"> {% if prototype is defined %} {% set attr = attr|merge({'data-prototype': proto.city(prototype)|escape }) %} {% endif %} <div {{ block('widget_container_attributes') }}></div> <div id="container-cities"> {# 新增:渲染已关联的城市项 #} {% for child in form.children %} {% set city = child.vars.data %} {{ proto.city(child, city.id, city.name, city.zip) }} {% endfor %} </div> </div> {% endspaceless %} {% endblock collection_widget %}
这里的关键是child.vars.data——每个子表单视图(child)的vars.data属性就是对应的City实体,这样就能拿到id、name、zip这些实体属性,完美匹配你的宏参数。
方法二:在表单渲染模板中手动结合实体与表单视图
如果你不想修改集合主题,也可以在主模板里直接获取Voyage实体,再把实体集合和表单子视图配对渲染:
修改后的表单渲染精简代码:
{% extends "@User/layout.html.twig" %} {% import '@Prototype/prototype.city.twig' as proto %} {% block content %} {{ form_start(form) }} {{ form_errors(form) }} <div id="container-cities"> {% set voyage = form.vars.data %} {# 用zip过滤器把实体集合和表单子视图配对 #} {% for city, child in voyage.cities|zip(form.cities.children) %} {{ proto.city(child, city.id, city.name, city.zip) }} {% endfor %} </div> {# 手动输出原型数据给JS用 #} {% if form.cities.vars.prototype is defined %} <div style="display: none" data-prototype="{{ proto.city(form.cities.vars.prototype)|escape }}"></div> {% endif %} {{ form_rest(form) }} {{ form_end(form) }} {% endblock content %}
额外注意事项
- 确保你的City实体有
getId()、getName()、getZip()这些公共的 getter 方法,不然从child.vars.data拿属性会报错。 - 新建Voyage时,
voyage.cities是空集合,循环不会执行,JS添加城市的逻辑完全不受影响。 - Symfony 3.3里
FormView的vars.data属性是稳定的,只要表单绑定了实体就能正常获取数据。
内容的提问来源于stack exchange,提问作者Soumacouette
相关产品推荐
相关产品推荐

