Symfony form to manage OneToManyToOne relation (ManyToMany with extra fields)

40 views Asked by At

Maybe some of you can help me ? I am struggling with a form I am building. In my app, users can create groups called "family" and invite other users to join that family. I want to create a form so that the admin of a family can manages the users who are members of its family.

I could have created a ManyToMany relationship between my entities User and Family, but I wanted to store extra information about that relation, like user's role, the date he/she entered the family...

So I have a Family and a User entities that have both a OneToMany relationship with the FamilyMember entity. Here are their main attributes :

Entity\User
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180, unique: true)]
    private ?string $email = null;

    #[ORM\Column(length: 255)]
    private ?string $lastname = null;

    #[ORM\Column(length: 255)]
    private ?string $firstname = null;

    #[ORM\Column(length: 255)]
    private ?string $avatar = null;

    #[ORM\OneToMany(mappedBy: 'user', targetEntity: FamilyMember::class, orphanRemoval: true)]
    private Collection $familyMember;

    public function __construct()
        {
            $this->familyMember = new ArrayCollection();
        }
Entity\Family
#[ORM\Entity(repositoryClass: FamilyRepository::class)]
#[ORM\HasLifecycleCallbacks]
class Family
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $name = null;

    #[ORM\OneToMany(mappedBy: 'family', targetEntity: FamilyMember::class)]
        private Collection $familyMembers;
    
    public function __construct()
    {
        $this->familyMembers = new ArrayCollection();
    }
Entity\FamilyMember
#[ORM\Entity(repositoryClass: FamilyMemberRepository::class)]
class FamilyMember
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(inversedBy: 'familyMember', fetch: "EAGER")]
    #[ORM\JoinColumn(nullable: false)]
    private ?User $user = null;

    #[ORM\ManyToOne(inversedBy: 'familyMemberBis')]
    #[ORM\JoinColumn(nullable: false)]
    private ?Family $family = null;

    #[ORM\Column]
    private array $role = [];
Controller\FamilyController
  #[Route('/compte/familles/{familyId}/gerer-membres', name: 'family_manage_members', requirements: ['familyId' => '\d+'])]
    public function manageFamilyMembers(int $familyId, Request $request): Response
    {
        $family = $this->familyRepository->find($familyId);
        // This is where I am supposed to call the form

Can someone help me please to create a form (using form types) where I have :

  • the list of all users who are part of the familly
  • for each user, the ability to make him a family admin
  • for each user, an option to exclude him from the family I do not want to be able to modify a user or a family in that form.

I tried different versions of FamilyType and FamilyMemberType, with embedded collections, but it was never fully functional.

1

There are 1 answers

0
HelenGreatly On

This is the last version I tried :

Controler\FamilyController
 #[Route('/compte/familles/{familyId}/gerer-membres', name: 'family_manage_members', requirements: ['familyId' => '\d+'])]
 public function manageFamilyMembers(int $familyId, Request $request): Response
    {
        $family = $this->familyRepository->find($familyId);
        $familyMembers = $family->getFamilyMembers();
        $forms = [];
        foreach ($familyMembers as $familyMember) {
          $form = $this->createForm(FamilyMemberType::class, $familyMember);
          $form->handleRequest($request);
          $forms[] = $form->createView();
        }
        return $this->renderForm('user/family-manage-members-form.html.twig', [
                'familyMemberForms' => $forms,
            ]);
}
class FamilyMemberType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('role', ChoiceType::class, [
                'label' => 'RĂ´le',
                'choices' => [
                    'Administrateur' => 'FAMILY_ADMIN',
                ],
                'multiple' => true,
                'expanded' => true
            ])
            ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => FamilyMember::class,
        ]);
    }
}
user/family-manage-members-form.html.twig
{% for form in familyMemberForms %}
    {{ form.vars.value.user.fullName}}
    {{ form_start(form) }}
    {{ form_widget(form) }}
    {{ form_end(form) }}
{% endfor %}
    <input type="submit" value="Enregistrer" class="btn btn-primary">

The "looking" of the form rendering was kind of what I wanted : Information about the user (its fullname) + the ability to make him an admin. The issue what that I had either one submit button per user, or one submit button at the end that was out of any HTML . The problem being that there are several forms. I was not able to add a button to delete a user from a family.

Thanks for any way you can help me !