I'm trying to create a controller method to edit an existing entity UserGroup
, but to modify only a ManyToMany
relation field to entity User
, this is the only field in the FormType.
The problem is, nothing is getting saved, although POST data is being sent and inspecting the entity after handleRequest()
shows that relation field has been correctly captured.
Note: Using Symfony generated CRUD controller doesn't save this relation field either, it does save other fields but not the relation field so maybe there's something wrong in relation definition.
This is UserGroup
entity:
#[ORM\Entity(repositoryClass: UserGroupRepository::class)]
class UserGroup extends ItemCollection implements IMessageInternalRecipient
{
const USER_GROUP_MARKETING = 'marketing';
#[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'groups', cascade: ['persist', 'remove'])]
private Collection $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
/*
insert into user_group(view_order, shortname, name) values(1, 'marketing', 'Equipo de marketing');
*/
/**
* @return Collection<int, User>
*/
public function getUsers(): Collection
{
return $this->users;
}
public function addUser(User $user): static
{
if (!$this->users->contains($user)) {
$this->users->add($user);
$user->addGroup($this);
}
return $this;
}
public function removeUser(User $user): static
{
if ($this->users->removeElement($user)) {
$user->removeGroup($this);
}
return $this;
}
}
This is ItemCollection
(which previous entity extends from):
#[ORM\MappedSuperclass]
class ItemCollection
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
protected $id;
#[ORM\Column(type: 'string', length: 100)]
protected $shortname;
//... and other fields
}
This is relation in User
entity:
#[ORM\ManyToMany(targetEntity: UserGroup::class, inversedBy: 'users')]
private Collection $groups;
UserGroupType
:
class UserGroupType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('users', EntityType::class, [
'label' => 'Marketing users',
'class' => User::class,
'choice_label' => 'email',
'multiple' => true,
'expanded' => true
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => UserGroup::class,
]);
}
}
And this is controller method. Notes: I don't pass a $userGroup
instance but a shortname, and perform a find()
on that shortname:
#[Route('/group_users/{shortname}', name: 'app_user_group_users', methods: ['GET', 'POST'])]
public function groupUsers(Request $request,
EntityManagerInterface $entityManager,
UserGroupRepository $userGroupRepository,
LoggerInterface $logger,
string $shortname): Response
{
$userGroup = $userGroupRepository->findOneBy(['shortname' => $shortname]);
if ($userGroup == null)
return $this->redirectToRoute('app_user_index', [], Response::HTTP_SEE_OTHER);
$form = $this->createForm(UserGroupType::class, $userGroup,
['action' => $this->generateUrl('app_user_group_users', ['shortname' => $shortname])]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// $entityManager->persist($userGroup); //This was tried but didn't work either
$entityManager->flush();
return $this->redirectToRoute('app_user_index', [], Response::HTTP_SEE_OTHER);
}
return $this->render('user/group_users.html.twig', [
'user_group' => $userGroup,
'form' => $form,
]);
}
You should add the parameter 'by_reference' => false
in the UserGroupType
for the users
field
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('users', EntityType::class, [
'label' => 'Marketing users',
'class' => User::class,
'choice_label' => 'email',
'multiple' => true,
'expanded' => true,
'by_reference' => false,
])
;
}