Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subform values are showing up as null on the receiving end after form submit

I have built out a form which submits fine, however subform values all end up as null on the receiving end when I look at them in the controller.

Here is my UserProfileType form, based on the Userclass. So specifically, the subforms we are looking at are subscriptionTier1, subscriptionTier1, and subscriptionTier1:

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
        )
    );
}

}

Here is what my UserSubscriptionTierType form type class looks like:

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,
        ));
    }
}

As you can see in the picture below, the subform subscriptionTier1's name, price, and description values are all set on the front-end:

enter image description here

Here is what the twig code looks like for the subscriptionTier1 subform:

    <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>

Here is the code on the receiving end, the controller:

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

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

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

So in debugging, if I dump just the first form subscriptionTier1, you can see that the values are all 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
}

Would anyone know why the values are not passing to the back-end (or getting nulled out)?

like image 610
Brent Heigold Avatar asked Feb 11 '19 03:02

Brent Heigold


1 Answers

Since the data_class option of UserProfileType form type is set to User class, the model data will be an instance of User class and since the User class doesn't have fields like subscriptionTier1 etc, these will not appear in your model data.

Instead, you could access unmapped fields in a form in a controller like this:

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

Documentation here

EDIT: You can only access the value of subscriptionTier1 etc, only after the form has been handled and only if the form has been submitted, otherwise it will be null:

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

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

    if ($form->isSubmitted() && $form->isValid()) {
        $subscriptionTier1 = $form->get('subscriptionTier1')->getData();
        dump($subscriptionTier1);
    }
like image 161
iiirxs Avatar answered Oct 19 '22 04:10

iiirxs