Home > Mobile >  $user->addTag() adding a doublon on my tag database on a many to many relation
$user->addTag() adding a doublon on my tag database on a many to many relation

Time:05-05

I develop a site where an user can add a tag on his profile. So to make this feature, I add this script on my controller:

if ($formTag->isSubmitted() && $formTag->isValid()) {

            $dataFormTag = $formTag->getData();

            $userTagsAssocied = $user->getTags();

            $userTagsAssociedArray = $userTagsAssocied->toArray();

            if (in_array($dataFormTag->getName(), $userTagsAssociedArray)) {
                $this->addFlash('danger', 'Vous avez deja le tag ' . $dataFormTag->getName() . ' associé à votre profil');
                return $this->redirectToRoute('app_user_profil');
            }

            $user->addTag($dataFormTag);
            $this->entityManager->persist($user);
            $this->entityManager->flush();
            $this->addFlash('success', 'Tag ' . $dataFormTag->getName() . ' bien lier à votre profil');
            return $this->redirectToRoute('app_user_profil');
        }

That work ! but the problem, is that duplicate the tag in my tag database.

An user who's add the tag FPS on his profil, the tag gonna be duplicate on bdd: I add one of the 5 tag n my profil ( for exemple FPS)

The tag FPS is correctly added on my profil

But now, the Tag FPS is duplicate on my database and I show him to my select input..

here my user entity :

<?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\Column(type: 'string', length: 180, unique: true)]
    private $email;

    #[ORM\Column(type: 'json')]
    private $roles = [];

    #[ORM\Column(type: 'string')]
    private $password;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private $discord;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private $twitter;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private $instagram;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private $tiktok;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private $facebook;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private $twitch;

    #[ORM\Column(type: 'string', length:255)]
    private $img;

    #[ORM\Column(type: 'string', length: 255)]
    private $pseudo;

    #[ORM\Column(type:'text', nullable: true)]
    private $description;

    #[ORM\Column(type: 'datetime')]
    private $created_time;

    #[ORM\Column(type: 'datetime')]
    private $updated_time;

    #[ORM\ManyToMany(targetEntity: Tag::class, inversedBy: 'users', cascade: ['persist'])]
    private $tags;

    #[ORM\ManyToMany(targetEntity: Games::class, inversedBy: 'users', cascade: ['persist'])]
    private $games;

    #[ORM\Column(type: 'boolean')]
    private $isVerified = false;



    public function __construct()
    {
        $this->tags = new ArrayCollection();
        $this->games = new ArrayCollection();
        $this->created_time = new \DateTime();
        $this->updated_time = new \DateTime();
    }

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

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUserIdentifier(): string
    {
        return (string) $this->email;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

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

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function getDiscord(): ?string
    {
        return $this->discord;
    }

    public function setDiscord(?string $discord): self
    {
        $this->discord = $discord;

        return $this;
    }

    public function getTwitter(): ?string
    {
        return $this->twitter;
    }

    public function setTwitter(?string $twitter): self
    {
        $this->twitter = $twitter;

        return $this;
    }

    public function getInstagram(): ?string
    {
        return $this->instagram;
    }

    public function setInstagram(?string $instagram): self
    {
        $this->instagram = $instagram;

        return $this;
    }

    public function getTiktok(): ?string
    {
        return $this->tiktok;
    }

    public function setTiktok(?string $tiktok): self
    {
        $this->tiktok = $tiktok;

        return $this;
    }

    public function getFacebook(): ?string
    {
        return $this->facebook;
    }

    public function setFacebook(?string $facebook): self
    {
        $this->facebook = $facebook;

        return $this;
    }

    public function getTwitch(): ?string
    {
        return $this->twitch;
    }

    public function setTwitch(?string $twitch): self
    {
        $this->twitch = $twitch;

        return $this;
    }

    public function getImg(): ?string
    {
        return $this->img;
    }

    public function setImg(string $img): self
    {
        $this->img = $img;

        return $this;
    }

    public function getPseudo(): ?string
    {
        return $this->pseudo;
    }

    public function setPseudo(string $pseudo): self
    {
        $this->pseudo = $pseudo;

        return $this;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(string $description): self
    {
        $this->description = $description;

        return $this;
    }

    public function getCreatedTime(): ?\DateTimeInterface
    {
        return $this->created_time;
    }

    public function setCreatedTime(\DateTimeInterface $created_time): self
    {
        $this->created_time = $created_time;

        return $this;
    }

    public function getUpdatedTime(): ?\DateTimeInterface
    {
        return $this->updated_time;
    }

    public function setUpdatedTime(\DateTimeInterface $updated_time): self
    {
        $this->updated_time = $updated_time;

        return $this;
    }

    /**
     * @return Collection<int, Tag>
     */
    public function getTags(): Collection
    {
        return $this->tags;
    }

    public function addTag(Tag $tag): self
    {
        if (!$this->tags->contains($tag)) {
            $this->tags[] = $tag;
        }

        return $this;
    }

    public function removeTag(Tag $tag): self
    {
        $this->tags->removeElement($tag);

        return $this;
    }

    /**
     * @return Collection<int, Games>
     */
    public function getGames(): Collection
    {
        return $this->games;
    }

    public function addGame(Games $game): self
    {
        if (!$this->games->contains($game)) {
            $this->games[] = $game;
        }

        return $this;
    }

    public function removeGame(Games $game): self
    {
        $this->games->removeElement($game);

        return $this;
    }

    public function getIsVerified(): ?bool
    {
        return $this->isVerified;
    }

    public function setIsVerified(bool $isVerified): self
    {
        $this->isVerified = $isVerified;

        return $this;
    }

}

And here my Tag entity :

<?php

namespace App\Entity;

use App\Repository\TagRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: TagRepository::class)]
class Tag
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\Column(type: 'string', length: 255)]
    private $name;

    #[ORM\Column(type: 'datetime')]
    private $created_time;

    #[ORM\Column(type: 'datetime')]
    private $updated_time;

    #[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'tags',cascade: ['persist'])]
    private $users;

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

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

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    public function getCreatedTime(): ?\DateTimeInterface
    {
        return $this->created_time;
    }

    public function setCreatedTime(\DateTimeInterface $created_time): self
    {
        $this->created_time = $created_time;

        return $this;
    }

    public function getUpdatedTime(): ?\DateTimeInterface
    {
        return $this->updated_time;
    }

    public function setUpdatedTime(\DateTimeInterface $updated_time): self
    {
        $this->updated_time = $updated_time;

        return $this;
    }

    /**
     * @return Collection<int, User>
     */
    public function getUsers(): Collection
    {
        return $this->users;
    }

    public function addUser(User $user): self
    {
        if (!$this->users->contains($user)) {
            $this->users[] = $user;
            $user->addTag($this);
        }

        return $this;
    }

    public function removeUser(User $user): self
    {
        if ($this->users->removeElement($user)) {
            $user->removeTag($this);
        }

        return $this;
    }
}

CodePudding user response:

You can check if the tag exists before persisting it:

if ($formTag->isSubmitted() && $formTag->isValid()) {

    $dataFormTag = $formTag->getData();
    $userTagsAssocied = $user->getTags();
    $userTagsAssociedArray = $userTagsAssocied->toArray();

    if (in_array($dataFormTag->getName(), $userTagsAssociedArray)) {
        $this->addFlash('danger', 'Vous avez deja le tag ' . $dataFormTag->getName() . ' associé à votre profil');
        return $this->redirectToRoute('app_user_profil');
    }

    $existingTag = $tagRepository->findOneByName($dataFormTag->getName());

    if ($existingTag !== null) {
        $user->addTag($existingTag);
    } else {
        $user->addTag($dataFormTag);
    }
    
    $this->entityManager->persist($user);
    $this->entityManager->flush();
    
    $this->addFlash('success', 'Tag ' . $dataFormTag->getName() . ' bien lier à votre profil');
    return $this->redirectToRoute('app_user_profil');
}

To prevent any duplicates because of case issue you could write your own findByName method in your repository

// TagRepository.php

public function findOneByName($name) {
    return $this->createQueryBuilder('t')
        ->where('upper(t.name) = upper(:name)')
        ->setParameter('name', $name)
        ->getQuery()
        ->getOneOrNullResult();
}

  • Related