I am having some trouble with a many to many relationship. I have Users
and Assets
. I would like to be able to assign users to an asset on the asset page.
The code below displays a list of users when creating/editing an asset, however changes made to the user checkboxes do not save, while the rest of the data is persisted.
If I add an entry to users_assets through the mysql client, these changes are shown in the asset list.
User
class User extends BaseUser
{
/**
* @ORM\ManyToMany(targetEntity="Asset", inversedBy="users")
*/
private $assets;
}
Asset
class Asset
{
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="assets")
*/
private $users;
}
AssetType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$form = $builder
->add('users', null, array(
'expanded' => true,
'multiple' => true
))
->getForm();
return $form;
}
For some reason I had to switch the doctrine mappings to get this to work:
Asset:
/**
* @ORM\ManyToMany(targetEntity="Adaptive\UserBundle\Entity\User", inversedBy="assets")
* @ORM\JoinTable(name="user_assets")
*/
private $users;
User:
/**
* @ORM\ManyToMany(targetEntity="Splash\SiteBundle\Entity\Asset", mappedBy="users")
*/
private $assets;
Now when I save the asset it saves the users associated. I did not need to define builder->add as an entity or collection. I simply pass it null and it uses the mapping info to fill in the entity info:
AssetType:
->add('users', null, array('expanded' => "true", "multiple" => "true"))
Not exactly sure why I needed to have the inversedBy and JoinTable info on the Asset vs The User but it seems to be working now!
Thanks For The Suggestions!!!
Weird enough I faced the same problem in 2016 and still had hard time finding the solution. I will share it for future googlers:
The problem is that what symfony essentially does when you save the form is this:
$asset->getUsers()->add($user)
And because you're on the inverse side of the relation it won't persist your changes.
What you really need is to make so that it calls this:
$asset->addUser($user)
Where addUser() is defined the following way on the Asset entity:
public function addUser(User $user)
{
//add to the inverse side
$this->users->add($user);
//add on the owning side (only this is persisted)
$user->addAsset($this); //$user->assets->add($asset);
}
So in order to make symfony use that $asset->addUser()
method, you should set
'by_reference' => false
on your users
field for AssetType
form.
More about this setting here http://symfony.com/doc/current/reference/forms/types/form.html#by-reference
Remember you also need to define removeUser()
method in the same way (so that it removes entity from the owning relation)
Not exactly sure why I needed to have the inversedBy and JoinTable info on the Asset vs The User but it seems to be working now!
The reason why your changes has been ignored is that doctrine persists only changes by the owning side of a relation (like @Florian said).
This is the link to Doctrine's documentation where this behaviour is explained: http://docs.doctrine-project.org/en/latest/reference/unitofwork-associations.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With