Doctrine ORM pour PHP : guide complet avec exemples
1. Qu'est-ce que Doctrine ORM et pourquoi l'utiliser ?
Doctrine ORM (Object-Relational Mapper) est une bibliothèque PHP puissante qui implémente le modèle Data Mapper. Contrairement à Active Record (utilisé dans Laravel Eloquent), Doctrine sépare complètement la logique métier (entités) de la logique d'accès aux données. Les entités sont de simples objets PHP (Plain Old PHP Objects, POPO) qui ignorent l'existence de la base de données. Toute interaction avec la base de données passe par un référentiel central : l'EntityManager.
Pourquoi l'utiliser ? Doctrine résout le problème fondamental du décalage entre le modèle objet et le modèle relationnel (Object-Relational Impedance Mismatch). Vous travaillez avec des objets et des collections, tandis que Doctrine traduit automatiquement vos actions en requêtes SQL. Cela permet d'écrire un code plus propre, plus testable et plus maintenable, en particulier dans les projets d'entreprise de grande envergure.
Avantages clés : contrôle total sur le SQL (via DQL — Doctrine Query Language), chargement paresseux (Lazy Loading), système d'événements flexible (Lifecycle Events), support de l'héritage (Mapped Superclass, Single Table Inheritance, Joined Table Inheritance), Query Builder intégré et modes d'hydratation (Hydration Modes). Doctrine est la norme de facto pour les applications PHP complexes (Symfony, Drupal, Magento).
2. Installation
L'installation se fait via Composer (l'équivalent de pip pour PHP). Pour une utilisation de base, deux paquets suffisent :
composer require doctrine/orm
composer require doctrine/dbal
composer require symfony/cache # Recommandé pour la mise en cache des métadonnées
Pour utiliser les annotations (méthode ancienne mais populaire), un paquet supplémentaire est nécessaire :
composer require doctrine/annotations
Pour la configuration en YAML ou XML :
composer require symfony/yaml # Pour YAML
Après l'installation, assurez-vous que l'autoloader Composer est inclus dans votre projet :
require_once __DIR__ . '/vendor/autoload.php';
3. Démarrage rapide — exemple minimal fonctionnel
Créons une entité simple User et sauvegardons-la dans une base de données SQLite.
Étape 1 : Configuration de l'EntityManager (bootstrap.php)
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;
use Doctrine\DBAL\DriverManager;
require_once __DIR__ . '/vendor/autoload.php';
// Configuration des chemins vers les entités et du mode développement
$paths = [__DIR__ . '/src/Entity'];
$isDevMode = true;
// Création de la configuration ORM
$config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);
// Configuration de la connexion à la base de données (SQLite)
$connectionParams = [
'driver' => 'pdo_sqlite',
'path' => __DIR__ . '/data/database.sqlite',
];
$connection = DriverManager::getConnection($connectionParams, $config);
// Création de l'EntityManager
$entityManager = new EntityManager($connection, $config);
Étape 2 : Création de l'entité (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