Search code examples
phpsymfonyormdoctrine-ormmany-to-many

doctrine2: deleting an entity with a ManytoMany relationship


I was wondering If you guys could help me with this. I've been looking for answers everywhere, and nothing worked. I have an Entity, User, that has Roles, with a Many to Many relationship. I'm managing it with Doctrine ORM, but the problem is that when I try to delete an user, nothing happens. What am I doing wrong? Here is the code:

USER:

/**
 * User.
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
 */
class User implements AdvancedUserInterface, \Serializable
{
/**
 * @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)
 * @Assert\NotBlank()
 */
private $username;

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

/**
 * @var bool
 *
 * @ORM\Column(name="enabled", type="boolean")
 * @Assert\Type(type="bool")
 */
private $isEnabled;

/**
 * @var \Doctrine\Common\Collections\ArrayCollection
 * 
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Role", inversedBy="users", cascade={"persist"})
 * @ORM\JoinTable(name="user_role",
 *          joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="cascade")},
 *          inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id", onDelete="cascade")}
 * )
 */
private $roles;

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\MediaCenter", mappedBy="user", cascade={"persist"})
 */
private $mediaCenters;

/**
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Client", cascade={"persist"})
 */
private $clients;

/**
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Account", cascade={"persist"})
 */
private $accounts;

public function __construct()
{
    $this->isEnabled = true;
    $this->roles = new ArrayCollection();
    $this->mediaCenters = new ArrayCollection();
    $this->clients = new ArrayCollection();
    $this->accounts = new ArrayCollection();
}

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

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

    return $this;
}

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

/**
 * Set email.
 *
 * @param string $email
 *
 * @return User
 */
public function setEmail($email)
{
    $this->email = $email;

    return $this;
}

/**
 * Get email.
 *
 * @return string
 */
public function getEmail()
{
    return $this->email;
}

/**
 * Set isEnabled.
 *
 * @param bool $isEnabled
 *
 * @return User
 */
public function setIsEnabled($isEnabled)
{
    $this->isEnabled = $isEnabled;

    return $this;
}

/**
 * Get isEnabled.
 *
 * @return bool
 */
public function getIsEnabled()
{
    return $this->isEnabled;
}

public function __toString()
{
    return ''.$this->getUsername();
}

public function getRoles()
{
    return $this->roles->toArray();
}
/**
 * Add roles.
 *
 * @param AppBundle\Entity\Role $roles
 *
 * @return User
 */
public function addRole(AppBundle\Entity\Role $roles)
{
    $roles->addUser($this);

    $this->roles->add($role);
    return $this;
}

/**
 * Remove roles.
 *
 * @param AppBundle\Entity\Role $roles
 */
public function removeRole(AppBundle\Entity\Role $roles)
{
    $this->roles->removeElement($roles);
}

public function getMediaCenters()
{
    return $this->mediaCenters->toArray();
}

/**
 * Add mediaCenters.
 *
 * @param AppBundle\Entity\MediaCenter $mediaCenters
 *
 * @return User
 */
public function addMediaCenter(AppBundle\Entity\MediaCenter $mediaCenters)
{
    $this->mediaCenters[] = $mediaCenters;

    return $this;
}

/**
 * Remove mediaCenters.
 *
 * @param AppBundle\Entity\MediaCenter $mediaCenters
 */
public function removeMediaCenter(AppBundle\Entity\MediaCenter $mediaCenters)
{
    $this->mediaCenters->removeElement($mediaCenters);
}

public function getClients()
{
    return $this->clients->toArray();
}

/**
 * Add clients.
 *
 * @param AppBundle\Entity\Client $client
 *
 * @return User
 */
public function addClient(AppBundle\Entity\Client $clients)
{
    $this->clients[] = $clients;

    return $this;
}

/**
 * Remove clients.
 *
 * @param AppBundle\Entity\Client $clients
 */
public function removeClient(AppBundle\Entity\Client $clients)
{
    $this->clients->removeElement($clients);
}

public function getAccounts()
{
    return $this->accounts->toArray();
}

/**
 * Add accounts.
 *
 * @param AppBundle\Entity\Account $accounts
 *
 * @return User
 */
public function addAccount(AppBundle\Entity\Account $accounts)
{
    $this->accounts[] = $accounts;

    return $this;
}

/**
 * Remove accounts.
 *
 * @param AppBundle\Entity\Account $accounts
 */
public function removeAccount(AppBundle\Entity\Account $accounts)
{
    $this->accounts->removeElement($accounts);
}

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

/**
 * @see \Serializable::serialize()
 */
 public function serialize()
 {
     return serialize(array(
         $this->id,
     ));
 }   
/**
 * @see \Serializable::unserialize()
 */
 public function unserialize($serialized)
 {
    list(
        $this->id) = unserialize($serialized);
 }
}

Role:

/**
 * @ORM\Table()
 * @ORM\Entity()
 */
class Role implements RoleInterface
{
/**
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id()
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

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

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

/**
 * @ORM\ManyToMany(targetEntity="User", mappedBy="roles", cascade={"persist"})
 */
private $users;

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

/**
 * @see RoleInterface
 */
public function getRole()
{
    return $this->role;
}

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

/**
 * Set name.
 *
 * @param string $name
 *
 * @return Role
 */
public function setName($name)
{
    $this->name = $name;

    return $this;
}

/**
 * Get name.
 *
 * @return string
 */
public function getName()
{
    return $this->name;
}

/**
 * Set role.
 *
 * @param string $role
 *
 * @return Role
 */
public function setRole($role)
{
    $this->role = $role;

    return $this;
}

/**
 * Add users.
 *
 * @param AppBundle\Entity\User $users
 *
 * @return Role
 */
public function addUser(AppBundle\Entity\User $users)
{
    //$this->users[] = $users;

   // $users->addRole($this);

    if (!$this->users->contains($users)) {
        $this->users->add($users);
    }

    return $this;
}

/**
 * Remove users.
 *
 * @param AppBundle\Entity\User $users
 */
public function removeUser(AppBundle\Entity\User $users)
{
    $this->users->removeElement($users);
    //$users->removeRole($this);
}

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

public function setUsers($users)
{
    $this->users = new ArrayCollection();

    foreach ($users as $a) {
        $this->adduser($a);
    }

    return $this;
}

public function __toString()
{
    return ''.$this->getName();
}
}

And here is how I try to remove a User:

public function DeleteUserAction()
{
    $request = $this->getRequest();

    $session = $this->get('session');
    $em = $this->getDoctrine()->getManager();

    $user = new User();

    $form = $this->createForm(new UserDeleteType(), $user);

    $form->handleRequest($request);

    if ($form->isValid()) 
    {
        $user = $form->getData();
        $exists = $em->getRepository('AppBundle:User')->findOneByEmail($user->getEmail());
        $loggedUser = $this->getUser();

        if(($exists && $exists==$loggedUser)) {
            return $this->redirect($this->generateUrl('menu_admin'));
        }
        if(!$exists){
            return $this->redirect($this->generateUrl('user_delete'));
        }
        foreach ($user->getRoles() as $role){
            $role->getUsers->removeElement($user);
            $em->persist($role);
        }

        $em->remove($user);
        $em->flush();
}

The structure of the tables in the database:

| User  | CREATE TABLE `User` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_2DA17977F85E0677` (`username`),
  UNIQUE KEY `UNIQ_2DA17977E7927C74` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

| Role  | CREATE TABLE `Role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) COLLATE utf8_unicode_ci NOT NULL,
  `role` varchar(45) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_F75B255457698A6A` (`role`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |


| user_role | CREATE TABLE `user_role` (
  `user_id` int(11) NOT NULL,
  `role_id` int(11) NOT NULL,
  PRIMARY KEY (`user_id`,`role_id`),
  KEY `IDX_2DE8C6A3A76ED395` (`user_id`),
  KEY `IDX_2DE8C6A3D60322AC` (`role_id`),
  CONSTRAINT `FK_2DE8C6A3A76ED395` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FK_2DE8C6A3D60322AC` FOREIGN KEY (`role_id`) REFERENCES `Role` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

Thanks in advance!


Solution

  • First of all you are trying to remove $user object which is just created but not persisted anywhere, instead of $exists object which is managed and was found by Entity Manager.

    Secondly you shouldn't persist $role each time you remove a user from it, so as $role is already managed entity, it is already known to EntityManager.

        foreach ($exists->getRoles() as $role){
            $role->getUsers->removeElement($exists);
        }
    
        $em->remove($exists);
        $em->flush();