Doctrine ORM for PHP: Complete Guide with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Doctrine ORM for PHP: Complete Guide with Examples

\n\n

1. What is it and why is it needed?

\n

Doctrine ORM (Object-Relational Mapper) is a powerful library for PHP that implements the Data Mapper pattern. Unlike Active Record (used in Laravel Eloquent), Doctrine completely separates business logic (entities) from database logic. Entities are plain PHP objects (Plain Old PHP Objects, POPO) that are unaware of the database's existence. All database work is done through a central repository — the EntityManager.

\n\n

Why is it needed? Doctrine solves the fundamental problem of mismatch between the object-oriented data model and the relational database model (Object-Relational Impedance Mismatch). You work with objects and collections, and Doctrine automatically translates your actions into SQL queries. This allows you to write cleaner, more testable, and maintainable code, especially in large enterprise projects.

\n\n

Key advantages: full control over SQL (via DQL — Doctrine Query Language), lazy loading, flexible event system (Lifecycle Events), inheritance support (Mapped Superclass, Single Table Inheritance, Joined Table Inheritance), built-in Query Builder, and hydrators (Hydration Modes). Doctrine is the de facto standard for complex PHP applications (Symfony, Drupal, Magento).

\n\n

2. Installation

\n

Installation is done via Composer (the PHP equivalent of pip). For basic usage, two packages are sufficient:

\n
composer require doctrine/orm\ncomposer require doctrine/dbal\ncomposer require symfony/cache  # Recommended for metadata caching
\n\n

For working with annotations (deprecated but popular method), an additional package is required:

\n
composer require doctrine/annotations
\n\n

For working with YAML or XML configuration:

\n
composer require symfony/yaml  # For YAML
\n\n

After installation, ensure the Composer autoloader is included in your project:

\n
require_once __DIR__ . '/vendor/autoload.php';
\n\n

3. Quick Start — Minimal Working Example

\n

Let's create a simple User entity and save it to an SQLite database.

\n\n

Step 1: EntityManager Configuration (bootstrap.php)

\n
use Doctrine\\ORM\\EntityManager;\nuse Doctrine\\ORM\\ORMSetup;\nuse Doctrine\\DBAL\\DriverManager;\n\nrequire_once __DIR__ . '/vendor/autoload.php';\n\n// Configure paths to entities and development mode\n$paths = [__DIR__ . '/src/Entity'];\n$isDevMode = true;\n\n// Create ORM configuration\n$config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);\n\n// Configure database connection (SQLite)\n$connectionParams = [\n    'driver' => 'pdo_sqlite',\n    'path' => __DIR__ . '/data/database.sqlite',\n];\n\n$connection = DriverManager::getConnection($connectionParams, $config);\n\n// Create EntityManager\n$entityManager = new EntityManager($connection, $config);
\n\n

Step 2: Create Entity (src/Entity/User.php)

\n
namespace App\\Entity;\n\nuse Doctrine\\ORM\\Mapping as ORM;\n\n#[ORM\\Entity]\n#[ORM\\Table(name: 'users')]\nclass User\n{\n    #[ORM\\Id]\n    #[ORM\\GeneratedValue]\n    #[ORM\\Column(type: 'integer')]\n    private int|null $id = null;\n\n    #[ORM\\Column(type: 'string', length: 100)]\n    private string $name;\n\n    #[ORM\\Column(type: 'string', length: 255, unique: true)]\n    private string $email;\n\n    public function getId(): ?int\n    {\n        return $this->id;\n    }\n\n    public function getName(): string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name): self\n    {\n        $this->name = $name;\n        return $this;\n    }\n\n    public function getEmail                    

Recommendations