访问视图中的嵌套表单字段(嵌入表单集合)

时间:2017-12-20 09:23:01

标签: php symfony symfony-forms symfony-3.3

我尝试使用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 个答案:

答案 0 :(得分:0)

  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;
    
         // ...
    
    }
    
  2. 在这个例子中,我们有一个叫做团队的实体。每个团队都有很多用户(这只是与您相关的示例)。我想,你已经创建了User实体。

    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或者您可以使用bundle(但不是官方文档):ninsuo/symfony-collection