Problem in Symfony 3 with ManyToMany Bidirectional relationship

2

I'm using Symfony 3 with Doctrine. In my application I have 2 entities: User and Role, and I need to make a bidirectional relationship between both entities from many to many that allows me to relate roles with users both from the User form and from the Role form.

I consulted the Doctrine documentation and put the corresponding annotations. When generating the CRUD, the User form works correctly; however, the ROL form inserts all the data correctly except the field of the relationship with User.

Here is a picture of the table:

And the code of each entity:

   class Usuario implements AdvancedUserInterface
   {
   /**
   * @var int
   *
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
   private $id;

   /**
   * @var string
   *
   * @ORM\Column(name="username", type="string", length=255, unique=true)
   */
private $username;

/**
 * @var string
 *
 * @ORM\Column(name="password", type="string", length=255)
 */
private $password;

/**
 * @var string
 *
 * @ORM\Column(name="estado", type="boolean")
 */
private $estado;

/**
 * @var string
 *
 * @ORM\Column(name="salt", type="string", length=255)
 */
private $salt;

/**
 * @ORM\ManyToMany(targetEntity="Rol", inversedBy="usuarios")
 * @ORM\JoinTable(name="usuario_rol")
 */
private $rolesUsuario;

/**
 * @ORM\OneToOne(targetEntity="Persona")
 * @ORM\JoinColumn(name="persona_id", referencedColumnName="id")
 */
private $persona;

public function getAttributes()
{
    return get_class_vars(__CLASS__);
}

/**
 * Get id
 *
 * @return int
 */
public function getId()
{
    return $this->id;
}

/**
 * Set username
 *
 * @param string $username
 *
 * @return Usuario
 */
public function setUsername($username)
{
    $this->username = $username;

    return $this;
}

/**
 * Get username
 *
 * @return string
 */
public function getUsername()
{
    return $this->username;
}

/**
 * Set password
 *
 * @param string $password
 *
 * @return Usuario
 */
public function setPassword($password)
{
    $this->password = $password;

    return $this;
}

/**
 * Get password
 *
 * @return string
 */
public function getPassword()
{
    return $this->password;
}

/**
 * Set estado
 *
 * @param string $estado
 *
 * @return Usuario
 */
public function setEstado($estado)
{
    $this->estado = $estado;

    return $this;
}

/**
 * Get estado
 *
 * @return string
 */
public function getEstado()
{
    return $this->estado;
}

/**
 * Checks whether the user's account has expired.
 *
 * Internally, if this method returns false, the authentication system
 * will throw an AccountExpiredException and prevent login.
 *
 * @return bool true if the user's account is non expired, false otherwise
 *
 * @see AccountExpiredException
 */
public function isAccountNonExpired()
{
    return true;
}

/**
 * Checks whether the user is locked.
 *
 * Internally, if this method returns false, the authentication system
 * will throw a LockedException and prevent login.
 *
 * @return bool true if the user is not locked, false otherwise
 *
 * @see LockedException
 */
public function isAccountNonLocked()
{
    return true;
}

/**
 * Checks whether the user's credentials (password) has expired.
 *
 * Internally, if this method returns false, the authentication system
 * will throw a CredentialsExpiredException and prevent login.
 *
 * @return bool true if the user's credentials are non expired, false otherwise
 *
 * @see CredentialsExpiredException
 */
public function isCredentialsNonExpired()
{
    return true;
}

/**
 * Checks whether the user is enabled.
 *
 * Internally, if this method returns false, the authentication system
 * will throw a DisabledException and prevent login.
 *
 * @return bool true if the user is enabled, false otherwise
 *
 * @see DisabledException
 */
public function isEnabled()
{
    if($this->estado == true){
        return true;
    }else{
        return false;
    }
}

/**
 * Returns the roles granted to the user.
 *
 * <code>
 * public function getRoles()
 * {
 *     return array('ROLE_USER');
 * }
 * </code>
 *
 * Alternatively, the roles might be stored on a ''roles'' property,
 * and populated in any number of different ways when the user object
 * is created.
 *
 * @return (Role|string)[] The user roles
 */

public function getRolesUsuario()
{
    return $this->rolesUsuario;
}


public function getRoles()
{
    $r = array();
    foreach ($this->rolesUsuario as $roles){
        $r[] = $roles->getNombre();
    }
    return $r;
}

/**
 * Returns the salt that was originally used to encode the password.
 *
 * This can return null if the password was not encoded using a salt.
 *
 * @return string|null The salt
 */
public function getSalt()
{
    return $this->salt;
}

/**
 * Removes sensitive data from the user.
 *
 * This is important if, at any given point, sensitive information like
 * the plain-text password is stored on this object.
 */
public function eraseCredentials()
{
    return false;
}
/**
 * Constructor
 */
public function __construct()
{
    $this->rolesUsuario = new \Doctrine\Common\Collections\ArrayCollection();
}

/**
 * Set salt
 *
 * @param string $salt
 *
 * @return Usuario
 */
public function setSalt($salt)
{
    $this->salt = $salt;

    return $this;
}

/**
 * Add role
 *
 * @param \CECMED\SeguridadBundle\Entity\Rol $role
 *
 * @return Usuario
 */
public function addRole(\CECMED\SeguridadBundle\Entity\Rol $role)
{
    $this->rolesUsuario[] = $role;

    return $this;
}

/**
 * Remove role
 *
 * @param \CECMED\SeguridadBundle\Entity\Rol $role
 */
public function removeRole(\CECMED\SeguridadBundle\Entity\Rol $role)
{
    $this->rolesUsuario->removeElement($role);
}

/**
 * Set persona
 *
 * @param \CECMED\SeguridadBundle\Entity\persona $persona
 *
 * @return Usuario
 */
public function setPersona(\CECMED\SeguridadBundle\Entity\persona $persona = null)
{
    $this->persona = $persona;

    return $this;
}

/**
 * Get persona
 *
 * @return \CECMED\SeguridadBundle\Entity\persona
 */
public function getPersona()
{
    return $this->persona;
}

/**
 * @return string
 */
public function __toString()
{
    return $this->getUsername();
}

/**
 * Add rolesUsuario
 *
 * @param \CECMED\SeguridadBundle\Entity\Rol $rolesUsuario
 *
 * @return Usuario
 */
public function addRolesUsuario(\CECMED\SeguridadBundle\Entity\Rol $rolesUsuario)
{
    $this->rolesUsuario[] = $rolesUsuario;

    return $this;
}

/**
 * Remove rolesUsuario
 *
 * @param \CECMED\SeguridadBundle\Entity\Rol $rolesUsuario
 */
public function removeRolesUsuario(\CECMED\SeguridadBundle\Entity\Rol $rolesUsuario)
{
    $this->rolesUsuario->removeElement($rolesUsuario);
}
}

This is Role Class:

class Rol
{
/**
 * @var int
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="nombre", type="string", length=255, unique=true)
 */
private $nombre;

/**
 * @var string
 *
 * @ORM\Column(name="descripcion", type="string", length=255)
 */
private $descripcion;

/**
 * @ORM\ManyToMany(targetEntity="Funcionalidad", inversedBy="rolesUsuario")
 * @ORM\JoinTable(name="rol_funcionalidad")
 */
private $funcionalidades;

/**
 * @ORM\ManyToMany(targetEntity="Usuario", mappedBy="rolesUsuario")
 */
private $usuarios;


public function getAttributes()
{
    return get_class_vars(__CLASS__);
}

/**
 * Get id
 *
 * @return int
 */
public function getId()
{
    return $this->id;
}

/**
 * Set nombre
 *
 * @param string $nombre
 *
 * @return Rol
 */
public function setNombre($nombre)
{
    $this->nombre = $nombre;

    return $this;
}

/**
 * Get nombre
 *
 * @return string
 */
public function getNombre()
{
    return $this->nombre;
}

/**
 * Set descripcion
 *
 * @param string $descripcion
 *
 * @return Rol
 */
public function setDescripcion($descripcion)
{
    $this->descripcion = $descripcion;

    return $this;
}

/**
 * Get descripcion
 *
 * @return string
 */
public function getDescripcion()
{
    return $this->descripcion;
}

/**
 * @return string
 */
public function __toString()
{
    return $this->getNombre();
}
/**
 * Constructor
 */
public function __construct()
{
    $this->funcionalidades = new \Doctrine\Common\Collections\ArrayCollection();
    $this->usuarios = new \Doctrine\Common\Collections\ArrayCollection();
}

/**
 * Add funcionalidade
 *
 * @param \CECMED\SeguridadBundle\Entity\Rol $funcionalidade
 *
 * @return Rol
 */
public function addFuncionalidade(\CECMED\SeguridadBundle\Entity\Rol $funcionalidade)
{
    $this->funcionalidades[] = $funcionalidade;

    return $this;
}

/**
 * Remove funcionalidade
 *
 * @param \CECMED\SeguridadBundle\Entity\Rol $funcionalidade
 */
public function removeFuncionalidade(\CECMED\SeguridadBundle\Entity\Rol $funcionalidade)
{
    $this->funcionalidades->removeElement($funcionalidade);
}

/**
 * Get funcionalidades
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getFuncionalidades()
{
    return $this->funcionalidades;
}

/**
 * Add usuario
 *
 * @param \CECMED\SeguridadBundle\Entity\Usuario $usuario
 *
 * @return Rol
 */
public function addUsuario(\CECMED\SeguridadBundle\Entity\Usuario $usuario)
{
    $usuario->addRolesUsuario($this);
    $this->usuarios[] = '$usuario';

    return $this;
}

/**
 * Remove usuario
 *
 * @param \CECMED\SeguridadBundle\Entity\Usuario $usuario
 */
public function removeUsuario(\CECMED\SeguridadBundle\Entity\Usuario $usuario)
{
    $this->usuarios->removeElement($usuario);
}

/**
 * Get usuarios
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getUsuarios()
{
    return $this->usuarios;
}
}
    
asked by Jesús Soto Mitjans 09.06.2017 в 17:36
source

2 answers

2

in your role class you are doing this:

public function addUsuario(\CECMED\SeguridadBundle\Entity\Usuario $usuario)
{
    $usuario->addRolesUsuario($this);
    $this->usuarios[] = '$usuario';

    return $this;
}

this assigns the string $ user in the user array, but not the object $ user.

I think it would work for you if you change it to:

public function addUsuario(\CECMED\SeguridadBundle\Entity\Usuario $usuario)
{
    $usuario->addRolesUsuario($this);
    $this->usuarios[] = $usuario;

    return $this;
}
    
answered by 10.06.2017 в 00:45
0

Normally for many to many relationships I use the following structure:

<?php
/** @Entity */
class User
{
    // ...

    /**
     * @ORM\ManyToMany(targetEntity="Group", inversedBy="users")
     * @ORM\JoinTable(name="users_groups",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
     *      )
     */
    private $groups;

    public function __construct() {
        $this->groups = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // ...
}

/** @Entity */
class Group
{
    // ...
    /**
     * @ORM\ManyToMany(targetEntity="User", mappedBy="groups")
     */
    private $users;

    public function __construct() {
        $this->users = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // ...
}
    
answered by 05.10.2017 в 12:23