【问题标题】: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 ...

如何访问视图中的子字段?

【问题讨论】:

    标签: php symfony symfony-forms symfony-3.3


    【解决方案1】:
    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 的实体。每个团队都有很多用户(这只是与您相关的示例)。我猜,您已经创建了用户实体。

    1. 想象一下,您的用户实体拥有 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 类型的字段(您的情况!)但用户集合! 我们的团队实体有字段用户。

    2. 现在,由于我们已经创建了 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,
          ]);
      
          // ...
      
      }
      
    3. 最后。您在树枝中的表格:

      {# 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>
      
    4. 这里有奇怪的小部件{{ 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 %}
      
    5. 当然,您必须设置添加和删除按钮。为此,我建议您使用官方文档:How to Embed a Collection of Forms 或者您可以使用捆绑包(但不是官方的):ninsuo/symfony-collection

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多