Coded Monkey Developer Reference

Configuring entities with Doctrine can be a complex task while the documentation around the subject is difficult to find because it's spread out across multiple pages. This page is an effort to provide a comprehensive list of examples to configure Doctrine entities through annotations. See the documentation on Basic Mapping for a basic overview of how Doctrine handles entity mapping. See the official Annotations Reference for in-depth explanations of the annotations that are shown on this page.

Examples on this page are compatible with PHP 7.1 or higher. Most examples on this page are focused on using the Symfony framework but can be used in any project (unless stated otherwise). Since getters and setters are not required for a Doctrine entity to work, this page contains separate examples that show how those are generally structured. It's recommended to use an IDE like PhpStorm or Zend Studio to automatically generate getters and setters or simply use Symfony's Maker Bundle to build entities through CLI commands.

Skeleton

The following example contains the least configuration and code required for a functional entity:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class Product
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private $id;

    // other fields..
}
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class Product
{
    /**
     * @var integer|null
     *
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private $id;

    // other fields..

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

    // other methods..
}

Entity configuration

An entity is defined by adding the @ORM\Entity annotation to a class:

/**
 * @ORM\Entity()
 */
class Product
{
    // fields..
}
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class Product
{
    // fields..
}

To specify a table name, add the @ORM\Table annotation to the entity:

/**
 * @ORM\Entity()
 * @ORM\Table(name="app_product")
 */
class Product
{
    // fields..
}
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="app_product")
 */
class Product
{
    // fields..
}

To specify a custom repository class for the entity, expand the entity's @ORM\Entity annotation:

/**
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Product
{
    // fields..
}
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Product
{
    // fields..
}

Field mapping

A field is defined by adding the @ORM\Column annotation to the property of an entity. If no field type is specified, the field defaults to a string. The following example contains the least configuration required to add a field:

    /**
     * @ORM\Column()
     */
    private $name;
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class Product
{
    /**
     * @var string|null
     *
     * @ORM\Column()
     */
    private $name;

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

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

        return $this;
    }
}

The following example shows a field with some commonly used configuration options:

    /**
     * @ORM\Column(type="string", name="product_name", unique=false, nullable=false, length=255, options={"default":"Foo"})
     */
    private $name;
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Product
{
    /**
     * @var string|null
     *
     * @ORM\Column(type="string", name="product_name", unique=false, nullable=false, length=255, options={"default":"Foo"})
     */
    private $name;

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

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

        return $this;
    }
}

Note that the length attribute is only available on fields with the string type. A full list of field types supported by Doctrine can be found in the Doctrine documentation.

For more information about field mapping, see the Property mapping section of the documentation.

Identity

Every entity is required to have an identifier (primary key) which can be configured by adding the @ORM\Id annotation to a field. In the skeleton we configured this value to be an integer, although this is not required, it is common practice to have an auto-generated integer called id as the primary key for database tables. Add the @ORM\GeneratedValue annotation to use the default automatic generator strategy.

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private $id;
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Product
{
    /**
     * @var integer|null
     *
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private $id;

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

To learn more about identifiers and automatic generator strategies, read the Identifiers section of the documentation.

Association mapping

Associations are the relationships between two entities in a database. Read the documentation on Association Mapping for an in-depth explanation on the topic.

Many to One

Use a many-to-one association when many instances of the current entity can be associated with one instance of the targeted entity with the @ORM\ManyToOne annotation. In this example each Product can . there are multiple Product entities for each Category entity:

// src/App/Entity/Product.php

    /**
     * @ORM\ManyToOne(targetEntity="Category")
     */
    private $category;

To configure the association column created in the database table, add the @ORM\JoinColumn annotation to the field:

    /**
     * @ORM\ManyToOne(targetEntity="Category")
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */

One to Many

A many-to-one association can be inversed by adding a one-to-many association on the targeted entity with the @ORM\OneToMany annotation and by using the inversedBy and mappedBy attributes. This example shows how to inverse the examples of the previous section:

// src/App/Entity/Product.php

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
     */
    private $category;

// src/App/Entity/Category.php

    /**
     * @ORM\OneToMany(targetEntity="Product", mappedBy="category")
     */
    private $products;

    public function __construct() {
        $this->products = new \Doctrine\Common\Collections\ArrayCollection();
    }

Note that it's not possible to use a one-to-many association without using a many-to-one association, although it is possible to achieve this result by using a many-to-many association with a unique constraint as explained in the Many to Many section of this page.

One to One

Use a one-to-one association when one instance of the current entity can be associated with one instance of the targeted entity with the @ORM\OneToOne annotation. In this example the Product entity references itself through a baseProduct field:

// src/App/Entity/Product.php

    /**
     * @ORM\OneToOne(targetEntity="Product")
     */
    private $baseProduct;

To configure the association column created in the database table, add the @ORM\JoinColumn annotation to the field:

    /**
     * @ORM\ManyToOne(targetEntity="Product")
     * @ORM\JoinColumn(name="base_product_id", referencedColumnName="id")
     */

Similar to the other association types, a one-to-one association can be inversed by using the inversedBy and mappedBy attributes. The following example shows a scenario where one Customer entity can be only be associated with one Cart entity at a time:

// src/App/Entity/Customer.php

    /**
     * @ORM\OneToOne(targetEntity="Cart", mappedBy="customer")
     */
    private $cart;

// src/App/Entity/Cart.php

    /**
     * @ORM\OneToOne(targetEntity="Customer", inversedBy="cart")
     */
    private $customer;

Note that in some cases, Doctrine might not even create an foreign key constraint when using a one-to-one association. To force the use of a foreign key for the association, make sure to use the @ORM\JoinColumn annotation.

Many to Many

Use the ManyToMany annotation to create a many-to-many association when many entities of the current entity can be associated with many entities of the targeted entity. In this example each Product entity can be associated with multiple Category entities:

// src/App/Entity/Product.php

    /**
     * @ORM\ManyToMany(targetEntity="Category")
     */
    private $categories;

    public function __construct()
    {
        $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
    }

To configure the association table created by Doctrine, add the @ORM\JoinTable annotation to the field:

    /**
     * @ORM\ManyToMany(targetEntity="Category")
     * @ORM\JoinTable(name="product_category",
     *   joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")},
     *   inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")}
     * )
     */

Similar to the other association types, a many-to-many association can be inversed by using the inversedBy and mappedBy attributes. This example shows how to inverse the example of the many-to-many association between the Product and Category entities:

// src/App/Entity/Product.php

    /**
     * @ORM\ManyToMany(targetEntity="Category", inversedBy="products")
     */
    private $categories;

    public function __construct()
    {
        $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
    }

// src/App/Entity/Category.php

    /**
     * @ORM\ManyToMany(targetEntity="Product", mappedBy="categories")
     */
    private $products;

    public function __construct()
    {
        $this->products = new \Doctrine\Common\Collections\ArrayCollection();
    }

Note that it's possible to use the @ORM\JoinTable annotation to simulate a many-to-one or one-to-many association by using the unique attribute of the @ORM\JoinColumn annotation to prevent that entity from being associated with more than of the targeted entity:

    /**
     * @ORM\ManyToMany(targetEntity="Category")
     * @ORM\JoinTable(name="product_category",
     *   joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")},
     *   inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id", unique=true)}
     * )
     */

Inheritance Mapping

Inheritance mapping can be used in cases that require multiple classes for a single entity. Read the documentation on Inheritance Mapping for an in-depth explanation on the topic.

Mapped Superclasses

Mapped superclasses can be used to define Doctrine fields and metadata on a class without implicitly creating an entity. Mapped superclasses can be extended by other entities to inherit the mapping information. Create a mapped superclass by using the @ORM\MappedSuperclass annotation on a class:

/**
 * @ORM\MappedSuperclass
 */
abstract class Contact
{
    /**
     * @ORM\Column
     */
    protected $address;

    /**
     * @ORM\Column
     */
    protected $emailAddress;

    /**
     * @ORM\Column
     */
    protected $phoneNumber;
}

/**
 * @ORM\Entity
 */
class User extends Contact
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private $id;

    // other fields..
}

/**
 * @ORM\Entity
 */
class Supplier extends Contact
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private $id;

    // other fields..
}

Single Table Inheritance

Single table inheritance can be used to map multiple entities to a single database table by creating a discriminator column. To configure single table inheritance, add the @ORM\InheritanceType, @ORM\DiscriminatorColumn and @ORM\DiscriminatorMap annotations to an entity:

/**
 * @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discriminator")
 * @ORM\DiscriminatorMap({"user" = "User", "employee" = "Employee"})
 */
class User
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    protected $id;

    // other fields..
}

/**
 * @ORM\Entity
 */
class Employee extends User
{
    // ..
}

Class Table Inheritance

Class table inheritance is an inheritance mapping strategy where each entity is mapped to a different table and are linked through a foreign key constraint. Similarly to single table inheritance, add the @ORM\InheritanceType, @ORM\DiscriminatorColumn and @ORM\DiscriminatorMap annotations to an entity to configure class table inheritance:

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discriminator")
 * @ORM\DiscriminatorMap({"user" = "User", "employee" = "Employee"})
 */

Mapping overrides

It's possible to override the associations and fields of an inheritance mapping by using the @ORM\AssociationOverrides and @ORM\AttributeOverrides annotations.

Unfortunately I was unable to provide a reasonable example for mapping overrides. See the Mapping Overrides section of the Doctrine documentation. If you have a good example you'd like to share, send me a Gist using Twitter. Thanks!

This page was last updated on 22 Aug 2019, at 14:56.
Enter a query to start searching