我尝试使用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 ...
如何访问视图中的子字段?
答案 0 :(得分:0)
第一步是了解我们为什么要使用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;
// ...
}
在这个例子中,我们有一个叫做团队的实体。每个团队都有很多用户(这只是与您相关的示例)。我想,你已经创建了User实体。
想象一下,您的用户实体拥有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或者您可以使用bundle(但不是官方文档):ninsuo/symfony-collection