Search code examples
phpsymfonysymfony-3.3

Which is the best way to 'check if exists` in many to many relationship table in Symfony3?


I have simple implementation of User -> Favourites User Articles:

Controller:

/**
 * @Route("/articles/{category}/{id}/addtofavorites", name="addToFavourites")
 */
public function addToFavourites($category, $id)
{
    $em = $this->getDoctrine()->getManager();
    $article = $em->getRepository("AppBundle:Article")->find($id);
    $user = $this->getUser();
    $user = $em->getRepository("AppBundle:User")->find($user->getId());
    $user->addFavouriteArticle($article);
    $em->persist($user);
    $em->flush();

    $test = 'true';

    return new JsonResponse($test);
}

User Entity:

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;

/**
 * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
 * @ORM\Table(name="user")
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    private $firstName;

    /**
     * @var favouriteArticles[]
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Article", cascade={"all"})
     * @ORM\JoinTable(name="user_favourite_articles",
     *     joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *     inverseJoinColumns={@ORM\JoinColumn(name="article_id", referencedColumnName="id")})
     */
    private $favouriteArticles;

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

    /**
     * @return favouriteArticles[]
     */
    public function getFavouriteArticles(): array
    {
        return $this->favouriteArticles->toArray();
    }

    /**
     * @param favouriteArticles[] $favouriteArticles
     */
    public function setFavouriteArticles(array $favouriteArticles): void
    {
        $this->favouriteArticles = $favouriteArticles;
    }

    /**
     * Add user
     *
     * @param \AppBundle\Entity\Article $article
     *
     * @return User
     */
    public function addFavouriteArticle(Article $article)
    {
        $this->favouriteArticles[] = $article;

        return $this;
    }

So I should change controller method to check if Article already exists in DB and Favourite button is clicked again it should remove it from DB (at the moment it just add article every time). How to do it? If it was normal table I would add in User Repository, like this:

return (boolean)$this->createQueryBuilder('u')
            ->andWhere('u.article = :article')
            ->setParameter('article', $rticle)
            ->getQuery()
            ->getOneOrNullResult();

But in this case with ManyToMany relation I don't know how and where to do it.


Solution

  • public function addFavouriteArticle(Article $article)
    {
        if ($this->favouriteArticles->contains($article)) {
            return;
        }
    
        $article->setUser($this);
        $this->favouriteArticles[] = $article;
    }
    
    public function removeFavouriteArticle(Article $article)
    {
        $this->favouriteArticles->removeElement($article);
    }
    

    This way user would never add same article to his favourites (because it aleady exists).