web-dev-qa-db-fra.com

Symfony2 Doctrine2 Formulaire Many To Many, pas des entités de sauvegarde

J'ai des problèmes avec plusieurs à plusieurs relations. J'ai Users et Assets. J'aimerais pouvoir affecter des utilisateurs à un actif sur la page de l'actif.

Le code ci-dessous affiche une liste d'utilisateurs lors de la création/modification d'un actif, mais les modifications apportées aux cases à cocher des utilisateurs ne sont pas enregistrées, tant que le reste des données est conservé.

Si j'ajoute une entrée à users_assets via le client mysql, ces modifications sont affichées dans la liste des ressources.

Utilisateur

class User extends BaseUser
{
    /**
     * @ORM\ManyToMany(targetEntity="Asset", inversedBy="users")
     */
    private $assets;
}

Atout

class Asset
{
    /**
     * @ORM\ManyToMany(targetEntity="User", mappedBy="assets")
     */
    private $users;
}

Type d'actif

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $form = $builder
        ->add('users', null, array(
            'expanded' => true,
            'multiple' => true
        ))
        ->getForm();

    return $form;
}
19
Shawn Northrop

Pour une raison quelconque, j'ai dû changer les correspondances de la doctrine pour que cela fonctionne:

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;

Maintenant, lorsque je sauvegarde l'actif, il enregistre les utilisateurs associés. Je n'avais pas besoin de définir constructeur-> ajouter en tant qu'entité ou collection. Je passe simplement la valeur null et utilise les informations de mappage pour renseigner les informations d'entité:

AssetType:
->add('users', null, array('expanded' => "true", "multiple" => "true"))

Je ne sais pas trop pourquoi j'avais besoin des informations inversedBy et JoinTable sur Asset vs The User, mais cela semble fonctionner maintenant!

Merci pour les suggestions !!!

30
Shawn Northrop

Pas tout à fait sûr pourquoi je devais avoir les informations inversedBy et JoinTable sur l'actif par rapport à l'utilisateur mais cela Semble fonctionner maintenant! 

La raison pour laquelle vos modifications ont été ignorées est que la doctrine ne persiste que si elles sont modifiées par le côté propriétaire d'une relation (comme l'a dit @ Florian). 

C'est le lien vers la documentation de Doctrine où ce comportement est expliqué: http://docs.doctrine-project.org/en/latest/reference/unitofwork-associations.html

17
naitsirch

Assez bizarre, j'ai rencontré le même problème en 2016 et j'avais toujours du mal à trouver la solution. Je vais le partager pour les futurs googleurs:

Le problème est que ce que symfony fait essentiellement lorsque vous enregistrez le formulaire est le suivant: 

$asset->getUsers()->add($user)

Et comme vous êtes à l’inverse de la relation, vos modifications ne seront pas conservées.

Ce dont vous avez vraiment besoin est de faire en sorte que cela appelle ceci:

$asset->addUser($user)

Où addUser () est défini de la manière suivante sur l'entité Asset:

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);
}

Donc, pour que symfony utilise cette méthode $asset->addUser(), vous devez définir 

'by_reference' => false

sur votre champ users pour le formulaire AssetType.

Plus d'informations sur ce paramètre ici http://symfony.com/doc/current/reference/forms/types/form.html#by-reference

N'oubliez pas que vous devez également définir la méthode removeUser() de la même manière (afin qu'elle supprime l'entité de la relation propriétaire).

12
Pavel Dubinin

Au début, vous devriez supprimer le préfixe barre oblique inverse dans les annotations (voir notice ici ).

Et vous devez utiliser le type de champ d'entité:

$builder->add('users', 'entity', array(
    'class' => 'AdaptiveUserBundle:User',
    'expanded' => true,
    'multiple' => true,
    'query_builder' => function(EntityRepository $er) {
        return $er->createQueryBuilder('u')
            ->orderBy('u.username', 'ASC');
    },
));
4
jkucharovic

Vous devez utiliser le type de champ 'collection' dans votre formulaire.

$builder->add('users', 'collection', array(
    'type' => new UserType(),
    'prototype' => true,
    'allow_add' => true,
    'allow_delete' => true
));

Vous devez évidemment créer le formulaire UserType() en premier.

Voici toutes les informations dont vous aurez besoin, y compris des exemples de code:

http://symfony.com/doc/current/cookbook/form/form_collections.html

http://symfony.com/doc/current/reference/forms/types/collection.html

0
grzechoo