Doctrine Symfony ManyToMany example

Doctrine Symfony ManyToMany example

Table of Contents

Introduction

In this post, I will show you how to use the ManyToMany relationship in Symfony with Doctrine. I will use my own code from 1payment.tools SaaS project.

Suppose we have two entities: Tool and Category. Each tool can be in multiple categories, and each category can have multiple tools.

Classes


TIP

You should use the bin/console make:entity command to generate the classes.


Tool class:

src/Entity/Tool.php
<?php

namespace App\Entity;

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

#[ORM\Entity(repositoryClass: ToolRepository::class)]
class Tool
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 155)]
    private ?string $name = null;

    /**
     * @var Collection<int, Category>
     */
    #[ORM\ManyToMany(targetEntity: Category::class, inversedBy: 'tools', fetch: 'EAGER')]
    private Collection $category;

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

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

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

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

        return $this;
    }

    /**
     * @return Collection<int, Category>
     */
    public function getCategory(): Collection
    {
        return $this->category;
    }

    public function addCategory(Category $category): static
    {
        if (!$this->category->contains($category)) {
            $this->category->add($category);
        }

        return $this;
    }

    public function removeCategory(Category $category): static
    {
        $this->category->removeElement($category);

        return $this;
    }
}

Category class:

src/Entity/Category.php
<?php

namespace App\Entity;

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

#[ORM\Entity(repositoryClass: CategoryRepository::class)]
class Category
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 155)]
    private ?string $name = null;

    #[ORM\Column(length: 255)]
    private ?string $slug = null;

    /**
     * @var Collection<int, Tool>
     */
    #[ORM\ManyToMany(targetEntity: Tool::class, mappedBy: 'category')]
    private Collection $tools;

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

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

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

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

        return $this;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): static
    {
        $this->slug = $slug;

        return $this;
    }

    /**
     * @return Collection<int, Tool>
     */
    public function getTools(): Collection
    {
        return $this->tools;
    }

    public function addTool(Tool $tool): static
    {
        if (!$this->tools->contains($tool)) {
            $this->tools->add($tool);
            $tool->addCategory($this);
        }

        return $this;
    }

    public function removeTool(Tool $tool): static
    {
        if ($this->tools->removeElement($tool)) {
            $tool->removeCategory($this);
        }

        return $this;
    }
}


Doctrine QueryBuilder example:

Get all tools what have any categories:


    $this->em->getRepository(Tool::class)->createQueryBuilder('t')
            ->join('t.category', 'c')
            ->getQuery()
            ->getResult();

Get all tools not depends on category presents

        $this->em->getRepository(Tool::class)->createQueryBuilder('t')
            ->leftJoin('t.category', 'c')
            ->getQuery()
            ->getResult();

Get all Tools with zero categories:

    $this->em->getRepository(Tool::class)->createQueryBuilder('t')
            ->leftJoin('t.category', 'c')
            ->where('c.id IS NULL')
            ->getQuery()
            ->getResult();

Get all Tools with specific category:

       $this->em->getRepository(Tool::class)->createQueryBuilder('t')
            ->join('t.category', 'c')
            ->where('c.name LIKE  :name')
            ->setParameter('name', '%Portfolio%')
            ->getQuery()
            ->getResult();