访问视图中的嵌套表单字段(嵌入表单集合)
Posted
技术标签:
【中文标题】访问视图中的嵌套表单字段(嵌入表单集合)【英文标题】:Access nested form fields in view (Embed a Collection of Forms) 【发布时间】:2018-06-02 19:25:45 【问题描述】:我尝试使用CollectionType
在 symfony 3 中构建一个巨大的表单。我必须定义多个子表单,一些是多个,一些是单个。
这是我的 FormType:
public function buildRegistrationForm(FormBuilderInterface $builder, array $options)
$builder->add('userRegistration', CollectionType::class, [
'entry_type' => UserRegistrationType::class,
'entry_options' => ['label' => true],
]);
$builder->add('meters', CollectionType::class, [
'entry_type' => MeterType::class,
'entry_options' => ['label' => true],
'allow_add' => true,
]);
...
现在我尝试访问视图中的 CollectionType 字段。代码如下:
form_label(registrationForm.email, null, 'label_attr': 'class': 'form-label')
form_widget(registrationForm.email, 'attr': 'class': 'form-control')
但我得到了错误:
Neither the property "email" nor one of the methods "email()", "getemail()"/"isemail()"/"hasemail()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView".
我知道 Symfony 试图直接从主表单 (registrationForm
) 中获取电子邮件字段,但我不知道如何访问子表单。在文档 (http://symfony.com/doc/current/form/form_collections.html) 中描述了我可以使用 registrationForm.userRegistration.email
简单地访问子表单。但这给了我错误:
Neither the property "userRegistration" nor one of the methods ...
如何访问视图中的子字段?
【问题讨论】:
【参考方案1】:第一步是了解我们为什么要使用collectionType? 如果你有一对多或多对多的关系,你应该使用 CollectionType。 示例:
/**
* Class Team
*
* @ORM\Entity
* @ORM\Table(name="example_project_team")
*/
class Team
// ...
/**
* Unidirectional Many-To-Many
*
* Many Teams has many users accounts.
*
* @var ArrayCollection $users
*
* @ORM\ManyToMany(
* targetEntity="AppBundle\Entity\User",
* cascade="persist", "remove",
* orphanRemoval=true
* )
*
* @ORM\JoinTable(name="teams_to_users",
* joinColumns=@ORM\JoinColumn(name="team_id", referencedColumnName="id", onDelete="CASCADE"),
* inverseJoinColumns=@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
* )
*/
protected $users;
// ...
在这个例子中,我们有一个名为 team 的实体。每个团队都有很多用户(这只是与您相关的示例)。我猜,您已经创建了用户实体。
想象一下,您的用户实体拥有 UserRegistrationType。
/**
* Class UserRegistrationType
*/
class UserRegistrationType extends AbstractType
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
$builder
->add('username', 'Symfony\Component\Form\Extension\Core\Type\TextType', [
'label' => false,
'translation_domain' => 'messages'
])
->add('email', 'Symfony\Component\Form\Extension\Core\Type\TextType', [
'label' => false,
'translation_domain' => 'messages'
])
// ... the other fields
;
/**
* @return string
*/
public function getName()
return 'app_user_registration_type';
/**
* @return null|string
*/
public function getBlockPrefix()
return 'app_user_registration';
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
$resolver->setDefaults(array(
'data_class' => User::class,
'csrf_protection' => true,
'validation' => true,
));
请注意!!!
我们在这里使用'data_class' => User::class,
如您所见,我们在 userRegistrationType 中使用了 User 对象。这意味着,我们可以为每个对象使用此表单,该对象具有 User 类型的字段或 CollectionType 类型的字段(您的情况!)但用户集合!
我们的团队实体有字段用户。
现在,由于我们已经创建了 userRegistrationType,我们可以将它添加到 TeamFormType。
public function teamRegistrationFormType(FormBuilderInterface $builder, array $options)
$builder->add('users', CollectionType::class, [
'entry_type' => UserRegistrationType::class,
'entry_options' => [
'label' => false,
],
'label' => false,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
]);
// ...
最后。您在树枝中的表格:
# you can add this form in your twig file #
<div class="box">
% block team_form %
form_start(team_form, 'attr': 'class': 'form-horizontal', 'role' : 'form')
<div class="box-body">
<div class="form-group">
% block users_collection %
<label for="" class="col-sm-2 control-label">
'admin.label.phones'|trans
</label>
<div class="col-sm-10 users" data-prototype=" form_widget(team_form.users.vars.prototype)|e('html_attr') ">
% for user in users %
<div>
form_widget(user)
</div>
% endfor %
</div>
<span class="help-block">
form_errors(users)
</span>
% endblock users_collection %
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-danger">
'admin.button.submit'|trans
</button>
</div>
</div>
form_end(team_form)
</div>
% endblock team_form %
</div>
这里有奇怪的小部件 form_widget(user)
。我猜,你想编辑这个小部件的样式。你可以使用 Symfony 内置的表单样式来做到这一点。创建文件(如果您还没有创建它)path_to_your_project/src/AppBundle/Resources/views/Form/fields.html.twig
并添加您的 userRegistrationType 的样式。请注意,这个小部件的名称是根据您的名称形成的块前缀和字符串“_widget”(public function getBlockPrefix()
)
% file fields.html.twig %
% trans_default_domain 'messages' %
% block app_user_registration_widget %
% spaceless %
<div class="form-group" block('widget_container_attributes') >
<div class="col-sm-2">
form_widget(form.username, 'attr' : 'class' : 'form-control' )
</div>
<div class="col-sm-4">
form_widget(form.email, 'attr' : 'class' : 'form-control' )
</div>
</div>
% endspaceless %
% endblock %
当然,您必须设置添加和删除按钮。为此,我建议您使用官方文档:How to Embed a Collection of Forms 或者您可以使用捆绑包(但不是官方的):ninsuo/symfony-collection
【讨论】:
以上是关于访问视图中的嵌套表单字段(嵌入表单集合)的主要内容,如果未能解决你的问题,请参考以下文章