-1

I have a form and i want submit it depends on the click of a radio button which is a choiceType : I have three entities(User which is the parent of Particuler and Professionnal) :

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\InheritanceType("JOINED")]
#[ORM\DiscriminatorColumn(name:"compte", type: "string")]
#[ORM\DiscriminatorMap(["professionnel"=>Professionel::class, "particulier"=> Particulier::class])]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\Column(type: 'string', length: 50)]
    private $typeCompte;

    #[ORM\Column(type: 'string', length: 180, unique: true)]
    #[Assert\NotBlank()]
    #[Assert\Length(min:2, max:80)]
    #[Assert\Email(message:"Choisir un autre email")]
    private $email;
    
    #[ORM\Column(type: 'boolean', nullable: true)]
    private $approve;
    // getters and setters
}
#[ORM\Entity(repositoryClass: ProfessionelRepository::class)]
class Professionel extends User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private $logo;
   // getters and setters
}
class Particulier extends User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    
    #[ORM\Column(type: 'string', length: 50)]
    #[Assert\NotBlank()]
    #[Assert\Length(min:2, max:50)]
    private $prenom;
   // getters and setters 
}

the corresponding formtype :

class RegistrationFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('typeCompte', ChoiceType::class, [
                'label' => 'Type de compte*',
                'choices'=>[
                    'Particulier' =>'Particulier',
                    'Professionel'=>'Professionel'
                ],
                'data'=>'Particulier',
                'expanded'=> true,
                'multiple'=> false,
                'attr'=>[
                    'class'=>'form-check-input',
                    'name' => 'type_compte'
                ]
              
            ])
            ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
                $data = $event->getData();
                $form = $event->getForm();

                // Set the default value for the "typeCompte" field
                $form->get('typeCompte')->setData('particulier');
            })
            ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
                $data = $event->getData();
                $form = $event->getForm();
                //dd($data);
                // Check the value of the "typeCompte" field
                $user = $event->getForm()->getData();
                dd($user);
                if ($data['typeCompte'] === 'Particulier') {
                    // Add the corresponding fields
                    $form->add('civility', ChoiceType::class, [
                            'label' => 'Civilité',
                            'choices' => [
                                'Madame' => 'Madame',
                                'Madamoiselle' => 'Madamoiselle',
                                'Monsieur' => 'Monsieur'
                            ],
                            'expanded' => true,
                            'multiple' => false,
                            'attr' => [
                                'class' => 'form-check-input',
                            ]

                        ])
                        ->add('prenom', TextType::class, [
                            'label' => 'Prénom*',
                            'attr' => [
                                'placeholder' => 'Votre prénom',
                                'class' => 'form-control'
                            ]
                            ])
                        ->add('nom', TextType::class, [
                            'label' => 'Nom*',
                            'attr' => [
                                'placeholder' => 'Votre nom',
                                'class' => 'form-control'
                            ]
                        ])
                    ;
                } elseif ($data['typeCompte'] === 'professionel') {
                    // Add the corresponding fields
                    $form->add('nomProfessionel', TextType::class, [
                        'label' => 'Concession*',
                        'attr' => [
                            'placeholder' => 'Nom concession',
                            'class' => 'form-control',
                            'id' => 'entreprise',
                        ])
                     
                        ->add('logo', FileType::class, [
                            'label' => 'Logo',
                            'attr' => [
                                'class' => 'form-control',
                                'id' => 'entreprise',
                            ]
                        ])
                    ;
                }
            })
            ->add('email', EmailType::class, [
                'label' => 'Email*',
                'attr' => [
                    'placeholder' => 'Votre email',
                    'class' => 'form-control'
                ]
         
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => User::class,
        ]);
    }
}

the corresponding controller :

#[Route('/Inscription', name: 'app_register')]
    public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher): Response
    {
      $form = $this->createForm(RegistrationFormType::class);
        // dd($form->get('typeCompte')->getData());
        // dd($request);
        $form->handleRequest($request);
       // dd($form->handleRequest($request));
        // dd($form);
        // dd($form->isSubmitted() && $form->isValid());
        if ($form->isSubmitted() && $form->isValid()) {
            dd($form->get('typeCompte')->getData());
            if ($form->get('typeCompte')->getData() === 'particulier'){
                $user = new Particulier();

            }
            if ($form->get('typeCompte')->getData() === 'professionel') {
                $user = new Professionel();
            }
            $form->getData($user);
            // encode the plain password
            $user->setPassword(
            $userPasswordHasher->hashPassword(
                    $user,
                    $form->get('password')->getData()
                )
            );
           

            $this->em->persist($user);
            $this->em->flush();
       return $this->renderForm('registration/register.html.twig', [
            'registrationForm' => $form,
        ]);
}

I have tried to build the form by adding eventlisteners as shown in the formType but i accross a null error when i trying to use dd($data). What i expect is to submit the form whether the user is Particulier or Professionnal by clicking on the typeCompte field.

kasali
  • 11
  • 3
  • 1
    You should probably use, User Roles. A lot easier to manage than seperate user tables etc.. I'm not to sure what you're trying to do. – Bossman Jan 04 '23 at 15:55

2 Answers2

0

My answer could look like judgemental but i want to highlight the tech vision of the proper answer instead of the direct solution to a problem that occurred because of a deeper problem.

Your trying to anticipate a multi-function approach without a clear goal about what you're trying to do in the end.

Your issue find it's origin where you try to submit potential different entities with one form type. Which is a bad practice and will lead you to other problem in the futur. In your case, there is also a main problem, one and only one user can be associated with the same company (a Professionel in your case) since the logo is associated with the user

Here is my vision

A user can not be something else than a person (email, firstname, lastname etc...).
So a user can not be a company (a Professionel in your case) or a particular (same as user).
But a user can be associated with a company

With this vision you could completely abandon using inheritance. You will remove a lot of you condition based on the choice of the user. It will simplify a lot your codebase.

Class User :

class User implements UserInterface
{
    
    //...
    #[ORM\ManyToMany(targetEntity: Company::class, mappedBy: 'associatedUsers')]
    private Collection $companies;

    #[ORM\Column(type: 'json')]
    private array $roles = [];
    
}

Class Company :

class Company
{

    #[ORM\Column()]
    private string $name;


    #[ORM\Column()]
    private string $logo;

    #[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'companies')]
    private Collection $associatedUsers;
}

So you can create one form type and no more. This form will submit a user no matter what. The exception is if the user select "professional" in the form, you can display additional field to directly add a company from the user subscription form. Check https://symfony.com/doc/current/form/embedded.html

Basically it is a CompanyType :

class CompanyType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name', StringType::class)
            ->add('logo', FileType::class)
    }
}

And then inside user type you can add this line :

$builder->add('company', CompanyType::class);

Also for :

Look at mapped false to generate the field but to ignore when persisting entity since you do not really need it inside the database since the association with company gives you the information.

->add('typeCompte', ChoiceType::class, [
                'label' => 'Type de compte*',
                'choices'=>[
                    'Particulier' =>'Particulier',
                    'Professionel'=>'Professionel'
                ],
                'data'=>'Particulier',
                'expanded'=> true,
                'multiple'=> false,
                'mapped' => false, 
                'attr'=>[
                    'class'=>'form-check-input',
                    'name' => 'type_compte'
                ]
              
            ])

Now you have a userType that handle adding a company. And then if the user fill the company fiels, set his role to ROLE_COMPANY as his user role, if not ROLE_USER or any roles according to your need.

Well it is a generic approach that will help you to improve your app and avoid complex homemade use of symfony and his form system.

Feel free to ask anything and i will update my answer. :)

ThomasL
  • 749
  • 4
  • 12
  • The problem here is not about Roles. it's about how to submit a form depending on whether the User is a simple(Particular) or a Professional user. I want if the User clicks on the radio buttons only the fields corresponding to a user appear. I have done that with a js script but I'm stuck in the form type when i add the eventlistener. – kasali Jan 04 '23 at 20:43
  • I guess using inheritance is suitable. We do have not a user which has 1..* companies. – kasali Jan 04 '23 at 20:47
  • @kasali, my comment also suggested Roles. What you're trying to achieve would then be easy. In your controller you could pass the *Role* of the logged in user to your form builder as an option, then in your form builder you can add/remove any field according to their Role. Example: `if ($options['userRole'] === 'role_particulier') { $builder->add(...) }` – Bossman Jan 04 '23 at 22:03
  • inheritance do have a lot of counterpart so it has to be used carefully. And maybe you do not need a user with n company but there is a high chance that you will need company to be able to have n user. So going from many to many to many to one at least will be required. And inheritance, in my view are not here to accomplish this kind of thing. A user can not be a company in term of pure logic. Trust me, you will prevent yourself of having futur issue if you dont fix that. @kasali – ThomasL Jan 05 '23 at 11:17
  • The problem is that we have a relationship "is" and not "has" so I guess inheritance is suitable. – kasali Jan 05 '23 at 13:59
0

i think you have wrong understanding of the eventlistener in symfony. The PRE_SUBMIT cannot replace / add fields, only can edit the data contained in the model that is going to be submitted.

If i understand you want to have a form with choice type field. Based on the user selection to load fields corresponding to the choice made by the user.

  1. One approach is to make 2 endpoints with 2 different forms, based on the choice type to redirect to Proffesional / Particulier and then to submit the form.

  2. Second is to make a large form combining the two forms with not mapped fields. Then using ajax to hide/show unwanted fields. But you have to handle the submit of the data.

benkov
  • 184
  • 9