0
votes

Form before handleRequest: no global errors.

Form {#1852 ▼
  -config: FormBuilder {#1851 ▶}
  -parent: null
  -children: OrderedHashMap {#1836 ▶}
  -errors: []
  -submitted: false
  -clickedButton: null
  -modelData: User {#2096 ▶}
  -normData: User {#2096 ▶}
  -viewData: User {#2096 ▶}
  -extraData: []
  -synchronized: true
  -defaultDataSet: true
  -lockSetData: false
}

Request: 'firstname' field is passed.

Request {#3 ▼
  +attributes: ParameterBag {#6 ▶}
  +request: ParameterBag {#4 ▼
    #parameters: array:1 [▼
      "registration" => array:6 [▼
        "firstname" => "foo"
        "lastname" => "bar"
        "email" => "[email protected]"
        "accountType" => "bbbbbb"
        "school_info" => array:4 [▶]
        "_token" => "1a55e2d7474183267374a0007e15b92e6114158d"
      ]
   ]
  }
...
}

Form after handleRequest: global error with error message from 'firstname' field, but no error in the field itself.

Form {#1852 ▼
-config: FormBuilder {#1851 ▶}
  -parent: null
  -children: OrderedHashMap {#1836 ▼
    -elements: array:5 [▼
      "firstname" => Form {#1835 ▼
        -config: FormBuilder {#1854 ▶}
        -parent: Form {#1852}
        -children: OrderedHashMap {#1853 ▶}
        -errors: []
        -submitted: true
        -clickedButton: null
        -modelData: "poipoi"
        -normData: "poipoi"
        -viewData: "poipoi"
        -extraData: []
        -synchronized: true
        -defaultDataSet: true
        -lockSetData: false
      }
      "email" => Form {#1858 ▶}
      "lastname" => Form {#1861 ▶}
      "accountType" => Form {#1864 ▶}
      "school_info" => Form {#1867 ▶}
    ]
    -orderedKeys: array:5 [▶]
    -managedCursors: []
  }
  -errors: array:3 [▼
    0 => FormError {#728 ▼
      -message: "missing email"
      #messageTemplate: "missing email"
      #messageParameters: array:1 [▶]
      #messagePluralization: null
    }
    1 => FormError {#733 ▼
      -message: "missing firstname"
      #messageTemplate: "missing firstname"
      #messageParameters: array:1 [▶]
      #messagePluralization: null
    }
    2 => FormError {#738 ▼
      -message: "missing lastname"
      #messageTemplate: "missing lastname"
      #messageParameters: array:1 [▶]
      #messagePluralization: null
    }
  ]
  -submitted: true
  -clickedButton: null
  -modelData: User {#2096 ▶}
  -normData: User {#2096 ▶}
  -viewData: User {#2096 ▶}
  -extraData: []
  -synchronized: true
  -defaultDataSet: true
  -lockSetData: false
}

Same issue for 'firstname', 'lastname' and 'email'. Notice how the errors are global to the form, and there is no error in the fields themselves. Also, error bubbling does not affect the issue.

Form Type:

<?php

namespace Acme\SiteBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Acme\SiteBundle\Entity\User;

/**
 *
 */
class RegistrationType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('firstname', null, array('label' => 'firstname'))
            ->add('lastname', null, array('label' => 'lastname'))
            ->add('email', 'email', array('label' => 'form.email'))
            ->add('accountType', 'choice'));

        $builder->add('school_info', 'school_info', array(
                'label' => 'School',
                'cascade_validation' => false,
                'mapped' => false,
                'required' => false,
        ));        
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\\SiteBundle\\Entity\\User',
            'intention' => 'registration',
            'validation_groups' => function (FormInterface $form) {
                $data = $form->getData();
                if ($this->isPro($data)) {
                    return array('HKCustomRegistration', 'account_type_pro');
                } else {
                    return array('HKCustomRegistration', 'account_type');
                }
            },
            'cascade_validation' => true,
        ));
    }

    public function getName()
    {
        return 'registration';
    }

}

Embedded Form (school_info) Form Type.

Key point : The issue only happens when the school_info form is added as a field in the registration form and shool input is filled in (if not filled in, bug does not happen).

<?php

namespace Acme\SiteBundle\Form\Type;

use Acme\SiteBundle\Service\SiteProvider;
use Acme\SiteBundle\Entity\School;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;

class SchoolInfoType extends AbstractType
{
    private $site;

    public function __construct(SiteProvider $siteProvider)
    {
        $this->site = $siteProvider->getCurrentSiteDB();

    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $site = $this->site;
        $builder
            ->add('school', 'entity', array(
                'empty_value' => '------------',
                'class' => 'AcmeSiteBundle:School',
                'query_builder' => function (EntityRepository $er) use ($site) {
                    return $er->createQueryBuilder('sc')
                              ->where('sc.site = :site')
                              ->setParameter('site', $site)
                              ->addOrderBy('sc.name', 'ASC');
                },
                'mapped' => true, // mapped but not persisted
                'label' => 'school',
            ));

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\SiteBundle\Entity\User',
            'site' => null,
        ));
    }

    public function getName()
    {
        return 'school_info';
    }

Validation constraints in the Entity:

/**
 * @var string
 *
 * @ORM\Column(name="firstname", type="string", length=100, nullable=true)
 * @Assert\NotBlank(groups={"HKCustomRegistration", "HKCustomProfile", "Default", "sylius"}, message="missing firstname")
 */
private $firstname;
1
Codes of your Form Type, Form Builder would be helpful for start. - Starx
I've added the form types. - Baishu
Not sure how much relevant the school_info form type is, but I think the registration type itself is quite standalone. Have you tried to render only the registration type form and see if the problem exists on that case? - Starx
The issue only happens when the school_info form is added as a field in the registration form. Furthermore, it only happens when at some point before submitting the regsitration form, an ajax call to populate the school_info form has been made. Let me add the ajax call. - Baishu
The code itself does not show any problem to me yet, but validation constraints can also be placed in Entities as well. The thing to try would be to pinpoint which form/subform is causing that. Now that we know that the problem happens with school_info is added, add and remove its subform to narrow down the problem. - Starx

1 Answers

0
votes

OK, so it was a validation group error !

The schoolInfoType validated the User entity against the default validation group, which requires 'firstname', 'lastname' and 'email'. It was a bit misleading because those fields were filled in the parent form. (not sure if 'mapped' => false plays a role here).

Anyway, my solution was to add a validation group with no associated constraints to SchoolInfoType:

<?php
class SchoolInfoType extends AbstractType
{
    //...
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\SiteBundle\Entity\User',
            'validation_groups' => array('school'),
            'site' => null,
        ));
    }
}
?>