Doctrine ORM
Doctrine is the object-relational mapper (ORM) Symfony pairs with by default.
It's worth being clear about this: Doctrine is a separate project, not something Symfony itself
builds or maintains — but the two are so commonly used together, and integrate so smoothly, that
"Symfony + Doctrine" is effectively the standard combination you'll meet in almost every Symfony
application. Doctrine's job is to let you work with plain PHP objects instead of writing raw SQL,
translating method calls like persist() and find() into database queries
behind the scenes.
Entities
An Entity is a plain PHP class annotated with PHP 8 attributes
that describe how it maps to a database table. Attributes use the #[...] syntax and
sit directly above the class or property they describe — Doctrine reads them to know which table
an object belongs to and which column each property corresponds to.
| Attribute | What it does |
|---|---|
#[ORM\Entity] | Marks the class itself as a Doctrine entity |
#[ORM\Table(name: 'articles')] | Names the database table the entity maps to |
#[ORM\Column(type: 'string')] | Marks a property as a mapped column, with its column type |
A Worked Example: The Article Entity
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'articles')]
class Article
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int $id;
#[ORM\Column(type: 'string')]
private string $title;
#[ORM\Column(type: 'text')]
private string $content;
public function getId(): int
{
return $this->id;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getContent(): string
{
return $this->content;
}
public function setContent(string $content): static
{
$this->content = $content;
return $this;
}
}
Each private property has a matching getter (and, other than id, a setter) — this
is the plain-PHP-object shape Doctrine expects, and the same shape the Form component (covered on
the Forms page) knows how to bind to automatically.
Generating Entities and Migrations
You rarely write an entire entity by hand. Symfony's console (see Console Commands) ships a code generator that scaffolds entities and the migration files that create or alter their matching tables:
php bin/console make:entity
php bin/console make:migration
make:entity interactively asks for the class name, its properties, and their types,
then writes (or updates) the entity class for you. make:migration compares your
current entity mappings against the actual database schema and generates a migration file
containing the SQL needed to bring the database in line.
The EntityManager
The EntityManager is the central object Doctrine uses to persist and query entities.
You hand it plain PHP objects, and it takes care of turning that into the right SQL.
<?php
$article = new Article();
$article->setTitle('Getting Started with Doctrine');
$article->setContent('Doctrine maps PHP objects to database rows.');
// Saving a new entity
$entityManager->persist($article);
$entityManager->flush();
// Fetching an entity by its id
$article = $repository->find($id);
persist() tells Doctrine "I want this object saved eventually" — it doesn't hit the
database yet. flush() is what actually executes the queued SQL (an INSERT
in this case). Reading works the other way: a repository (one per entity)
gives you finder methods like find($id) to fetch an existing row back as a fully
hydrated Article object.
EntityManager needs a database to actually connect to. Head to Database Configuration to set the connection string and run your first migration.