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