Doctrine ORM para PHP: guia completo com exemplos práticos
1. O que é e para que serve?
Doctrine ORM (Object-Relational Mapper) é uma biblioteca poderosa para PHP que implementa o padrão Data Mapper. Diferente do Active Record (usado no Laravel Eloquent), o Doctrine separa completamente a lógica de negócio (entidades) da lógica de acesso ao banco de dados. As entidades são objetos PHP comuns (Plain Old PHP Objects, POPO) que não sabem da existência do banco de dados. Todo o trabalho com o banco é feito através de um repositório central chamado EntityManager.
Para que serve? O Doctrine resolve o problema fundamental de incompatibilidade entre o modelo orientado a objetos e o modelo relacional do banco de dados (Object-Relational Impedance Mismatch). Você trabalha com objetos e coleções, enquanto o Doctrine traduz automaticamente suas ações em consultas SQL. Isso permite escrever um código mais limpo, testável e de fácil manutenção, especialmente em projetos enterprise de grande porte.
Principais vantagens: controle total sobre SQL (através do DQL — Doctrine Query Language), carregamento tardio (Lazy Loading), sistema flexível de eventos (Lifecycle Events), suporte a herança (Mapped Superclass, Single Table Inheritance, Joined Table Inheritance), Query Builder integrado e modos de hidratação (Hydration Modes). O Doctrine é o padrão de facto para aplicações PHP complexas (Symfony, Drupal, Magento).
2. Instalação
A instalação é feita via Composer (equivalente ao pip para PHP). Para uso básico, você precisa de dois pacotes:
composer require doctrine/orm
composer require doctrine/dbal
composer require symfony/cache # Recomendado para cache de metadados
Para trabalhar com anotações (método antigo, mas ainda popular), é necessário um pacote adicional:
composer require doctrine/annotations
Para configuração em YAML ou XML:
composer require symfony/yaml # Para YAML
Após a instalação, certifique-se de que o autoloader do Composer está incluído no seu projeto:
require_once __DIR__ . '/vendor/autoload.php';
3. Início rápido — exemplo mínimo funcional
Vamos criar uma entidade simples User e salvá-la em um banco de dados SQLite.
Passo 1: Configuração do EntityManager (bootstrap.php)
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;
use Doctrine\DBAL\DriverManager;
require_once __DIR__ . '/vendor/autoload.php';
// Configurar caminhos das entidades e modo de desenvolvimento
$paths = [__DIR__ . '/src/Entity'];
$isDevMode = true;
// Criar configuração ORM
$config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);
// Configurar conexão com o banco (SQLite)
$connectionParams = [
'driver' => 'pdo_sqlite',
'path' => __DIR__ . '/data/database.sqlite',
];
$connection = DriverManager::getConnection($connectionParams, $config);
// Criar EntityManager
$entityManager = new EntityManager($connection, $config);
Passo 2: Criar a entidade (src/Entity/User.php)
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'users')]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int|null $id = null;
#[ORM\Column(type: 'string', length: 100)]
private string $name;
#[ORM\Column(type: 'string', length: 255, unique: true)]
private string $email;
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): self