Skip to main content
Lennu.net

Doctrine Many To Many with Extra Fields

Extra fields for Many to Many relationship is usually well supported. However in Doctrine this is actually something that you can’t do with just normal ManyToMany entity.

In Doctrine you have to define three Entities where you kind of manually create the Many To Many relationship. This is done like this.

Lets say we have Products and Categories. Products can have many Categories and Categories can have many Products. So we need a many to many relationship.

Now for the sake of example we also need quantity of how many products are in a category. It would be convenient to store the information into the middle table of our many to many relationship.

Lets first define the Product class

namespace Entity;
 
use Doctrine\ORM\Mapping as ORM;
 
/**
 * @ORM\Entity()
 * @ORM\Table(name="product")
 */
class Product
{
    /**
     * @ORM\Id()
     * @ORM\Column(type="integer")
     */
    private $id;
 
    /**
     * ORM\Column(name="name", type="string", length=50, nullable=false)
     */
    private $name;
 
    /**
     * @ORM\OneToMany(targetEntity="Entity\CategoryProduct", mappedBy="product")
     */
    private $categoryProducts;
}

So you see that we are using OneToMany relationship in here and it is targeting Entity CategoryProducts which eventually will be our middle table.

Now lets define Category class:

namespace Entity;
 
use Doctrine\ORM\Mapping as ORM;
 
/**
 * @ORM\Entity()
 * @ORM\Table(name="store")
 */
class Store
{
    /**
     * @ORM\Id()
     * @ORM\Column(type="integer")
     */
    private $id;
 
    /**
     * ORM\Column(name="name", type="string", length=50, nullable=false)
     */
    private $name;
 
    /**
     * @ORM\OneToMany(targetEntity="Entity\CategoryProduct", mappedBy="category")
     */
    private $categoryProducts;
}

Now we have defined both of our main entities. Now it’s time for the middle table.

namespace Entity;
 
use Doctrine\ORM\Mapping as ORM;
 
/**
 * @ORM\Entity()
 * @ORM\Table(name="category_product")
 */
class CategoryProduct
{
    /**
     * ORM\Column(type="integer")
     */
    private $quantity;
 
    /**
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="Entity\Product", inversedBy="categoryProducts") 
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id", nullable=false) 
     */
    private $product;
 
    /**
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="Entity\Category", inversedBy="categoryProducts") 
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false) 
     */
    private $category;
}

Here in the middle table we just define ManyToOne side relationships to their corresponding OneToMany relations on the main entities. We can also add here as many extra fields as we like. Currently this entity contains the Quantity which will store the information of how many products are in this category.