子表单值在表单提交后在接收端显示为空

时间:2019-02-11 03:13:21

标签: forms symfony subform

我建立了一个可以很好提交的表单,但是当我在控制器中查看子表单值时,它们在接收端最终都为null。

这是我基于UserProfileType类的User表格。因此,具体地说,我们正在查看的子表单是subscriptionTier1subscriptionTier1subscriptionTier1

class UserProfileType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('firstName', TextType::class)
            ->add('lastName', TextType::class)
            ->add('email', EmailType::class)

            // etc... I'll keep out the unimportant fields

            // here are the subforms whose values show up as null on the back end
            ->add('subscriptionTier1', UserSubscriptionTierType::class, [
                'required' => false,
                'mapped' => false
                ])
            ->add('subscriptionTier2', UserSubscriptionTierType::class, [
                    'required' => false,
                    'mapped' => false
                ])
            ->add('subscriptionTier3', UserSubscriptionTierType::class, [
                    'required' => false,
                    'mapped' => false
                ])
            ->add('save', SubmitType::class, [
                'attr' => ['class' => 'save'],
            ])
        ;

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
            'data_class' => User::class,
            'mode' => null
        )
    );
}

}

这是我的UserSubscriptionTierType表单类型类的样子:

class UserSubscriptionTierType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class, [
                'attr' => [
                    'maxlength' => 25
                ]
            ])
            ->add('price', ChoiceType::class, [
                'choices' => [
                    '$10 per month' => 10,
                    '$20 per month' => 20,
                    '$30 per month' => 30
                ]
            ])
            ->add('description', TextareaType::class)
            ->add('messaging', CheckboxType::class, [
                'required' => false
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => UserSubscriptionTier::class,
        ));
    }
}

如下图所示,子表单subscriptionTier1的名称,价格和描述值都在前端设置:

enter image description here

以下是subscriptionTier1子表单的细枝代码:

    <div class="row justify-content-center w-100 ml-0 mr-0 mt-3 tier tier-1" >
        <div class="col-lg-6 mt-1">
            <div class="form-group form-control-lg w-100">
                <label for="firstname" class="mb-2">Tier 1 Name</label>
                {{ form_widget(form.subscriptionTier1.name, { 'attr': {'class': 'form-control'}}) }}
            </div>
        </div>
        <div class="col-lg-6 mt-1">
            <div class="form-group form-control-lg w-100">
                <label for="tier1price" class="mb-2">Tier 1 Price</label>
                {{ form_widget(form.subscriptionTier1.price, { 'attr': {'class': 'form-control'}}) }}
            </div>
        </div>
        <div class="col-lg-12 mt-3">
            <div class="form-group form-control-lg w-100">
                <label for="bio" class="mb-2">Tier 1 Description
                    <sup class="text-danger">*</sup>
                </label>
                {{ form_widget(form.subscriptionTier1.description, { 'attr': {'class': 'form-control border-box', 'rows':'8'}}) }}
            </div>
        </div>
        <div class="col-lg-12">
            <div class="form-group form-control-lg w-100">
                <div class="form-check">
                    <label class="form-check-label">
                        {{ form_widget(form.subscriptionTier1.messaging, { 'attr': {'class': 'form-control form-check-input'}}) }}
                        <span class="form-check-sign"></span>
                        Enable Messaging
                    </label>
                </div>
            </div>
        </div>
    </div>

这是接收方(控制器)上的代码:

public function saveProfileAction(Request $request)
{
    $user = $this->getUser();

    $form = $this->createForm(UserProfileType::class, $user);
    $form->handleRequest($request);

dump($form->get('subscriptionTier1')->getData()); 

因此在调试中,如果我仅转储第一个表单subscriptionTier1,则可以看到所有值都是null

ProfileController.php on line 269:
Form {#2235 ▼
  -config: FormBuilder {#2236 ▶}
  -parent: Form {#2112 ▶}
  -children: OrderedHashMap {#2237 ▶}
  -errors: []
  -submitted: true
  -clickedButton: null
  -modelData: UserSubscriptionTier {#2280 ▼
    -id: null
    -posts: ArrayCollection {#2323 ▶}
    -subscriptions: null
    -name: null         // Don't understand why this is null 
    -price: null        // Don't understand why this is null 
    -description: null  // Don't understand why this is null 
    -tierNumber: null
    -versionNumber: null
    -messaging: false
    -user: null
    +"subsciptions": ArrayCollection {#2089 ▶}
  }
  -normData: UserSubscriptionTier {#2280 ▶}
  -viewData: UserSubscriptionTier {#2280 ▶}
  -extraData: []
  -transformationFailure: null
  -defaultDataSet: true
  -lockSetData: false
}

有人会知道为什么这些值没有传递到后端(或无效)吗?

2 个答案:

答案 0 :(得分:1)

由于data_class表单类型的UserProfileType选项设置为User类,因此模型数据将是User类的实例,并且由于{{1} }类没有User等字段,这些字段不会出现在模型数据中。

相反,您可以在控制器中以如下形式访问未映射的字段:

subscriptionTier1

文档here

编辑:仅在处理完表单之后,并且仅在提交表单后,您才可以访问subscriptionTier1等的值,否则它将为null:

$subscriptionTier1 = $form->get('subscriptionTier1')->getData();

答案 1 :(得分:0)

我不知道这只是一种解决方法,还是实际上是实现此目的的最佳做法,但这是我的工作方式:

我在以下子窗体标签中有: {{ form_start(form.subscriptionTier1) }} etc... {{ form_end(form.subscriptionTier1) }}

这将嵌套表单标签。显然,您不允许嵌套这样的表单。

因此,取出所有{{ form_start(form.subscriptionTier1) }}{{ form_end(form.subscriptionTier1) }}subscriptionTier1的{​​{1}},subscriptionTier1,然后检查请求对象中的表单值是否有效