Doctrine ORM для PHP: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Doctrine ORM и зачем она нужна?

Doctrine ORM (Object-Relational Mapping) — это мощная библиотека для PHP, которая позволяет разработчикам работать с базами данных, используя объектно-ориентированный подход, а не писать сырые SQL-запросы. Doctrine ORM является де-факто стандартом для Symfony, но может использоваться и в любом другом PHP-проекте (Laravel, Yii, чистый PHP).

Основная проблема, которую решает Doctrine: несоответствие между реляционной моделью данных (таблицы, строки, столбцы) и объектной моделью (классы, объекты, свойства). Doctrine автоматически преобразует объекты PHP в записи базы данных и обратно.

Ключевые возможности:

  • Автоматическое создание схемы БД — на основе аннотаций/атрибутов в классах
  • Repository Pattern — удобные методы для поиска и фильтрации данных
  • DQL (Doctrine Query Language) — объектно-ориентированный язык запросов
  • Lazy Loading — загрузка связанных данных только по необходимости
  • Миграции — управление изменениями схемы БД
  • Транзакции — полная поддержка ACID
  • Кэширование — метаданных, запросов, результатов

Doctrine ORM подходит для проектов любого масштаба: от небольших сайтов до корпоративных систем с сотнями таблиц.

Установка Doctrine ORM

Установка производится через Composer (менеджер пакетов PHP). Откройте терминал в корне вашего проекта и выполните:

composer require doctrine/orm

Для работы с Symfony рекомендуется установить пакет DoctrineBundle:

composer require symfony/orm-pack
composer require --dev symfony/maker-bundle  # для генерации кода

Если вы используете чистый PHP без фреймворка, дополнительно потребуется установить драйвер для вашей БД:

composer require doctrine/dbal
composer require doctrine/annotations  # для работы с аннотациями (PHP 7.4 и ниже)

Для работы с атрибутами PHP 8+ (рекомендуемый способ): аннотации не нужны, Doctrine поддерживает нативные атрибуты.

Быстрый старт: пример кода

Рассмотрим простейший пример — создание сущности "Product" и сохранение её в базу данных.

1. Создаём класс сущности (Entity)

<?php
// src/Entity/Product.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'products')]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private int $id;

    #[ORM\Column(type: 'string', length: 255)]
    private string $name;

    #[ORM\Column(type: 'float')]
    private float $price;

    // Геттеры и сеттеры
    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 getPrice(): float
    {
        return $this->price;
    }

    public function setPrice(float $price): self
    {
        $this->price = $price;
        return $this;
    }
}

2. Создаём и сохраняем объект

<?php
// В контроллере Symfony или в любом другом месте
use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;

class ProductController
{
    public function createProduct(EntityManagerInterface $entityManager)
    {
        $product = new Product();
        $product->setName('Ноутбук');
        $product->setPrice(49999.99);

        // Говорим Doctrine, что объект нужно сохранить
        $entityManager->persist($product);
        
        // Выполняем INSERT в базу данных
        $entityManager->flush();

        // Теперь $product->getId() содержит ID новой записи
        return 'Создан продукт с ID: ' . $product->getId();
    }
}

3. Получаем данные из БД

<?php
// Получаем продукт по ID
$product = $entityManager->getRepository(Product::class)->find(1);

// Или получаем все продукты
$products = $entityManager->getRepository(Product::class)->findAll();

// Фильтрация
$cheapProducts = $entityManager->getRepository(Product::class)->findBy([
    'price' => 10000
]);

Основные методы и функции Doctrine ORM (8+ штук)

1. EntityManager::persist()

Что делает: Регистрирует объект для сохранения в базу данных. После вызова persist() объект попадает в UnitOfWork (менеджер изменений).

Параметры:

  • $entity (object) — объект сущности, который нужно сохранить

Рабочий пример:

$user = new User();
$user->setEmail('test@example.com');
$entityManager->persist($user); // Регистрируем
$entityManager->flush();        // Сохраняем

2. EntityManager::flush()

Что делает: Выполняет все накопленные операции (INSERT, UPDATE, DELETE) в базе данных. Без вызова flush() изменения не будут записаны.

Параметры:

  • $entity (object|null) — если передан, выполняется синхронизация только для этого объекта

Рабочий пример:

// Сохраняем несколько объектов
$entityManager->persist($product1);
$entityManager->persist($product2);
$entityManager->flush(); // Один транзакционный запрос

3. EntityManager::remove()

Что делает: Регистрирует объект для удаления из базы данных. Реальное удаление произойдёт после flush().

Параметры:

  • $entity (object) — объект сущности для удаления

Рабочий пример:

$product = $entityManager->getRepository(Product::class)->find(1);
$entityManager->remove($product);
$entityManager->flush(); // DELETE FROM products WHERE id = 1

4. EntityManager::find()

Что делает: Находит сущность по её первичному ключу (ID). Возвращает объект или null, если запись не найдена.

Параметры:

  • $className (string) — полное имя класса сущности
  • $id (mixed) — значение первичного ключа

Рабочий пример:

$user = $entityManager->find(User::class, 42);
if ($user) {
    echo $user->getEmail();
}

5. Repository::findBy()

Что делает: Находит все сущности, соответствующие заданным критериям. Возвращает массив объектов.

Параметры:

  • $criteria (array) — ассоциативный массив [поле => значение]
  • $orderBy (array|null) — сортировка [поле => 'ASC'|'DESC']
  • $limit (int|null) — ограничение количества записей
  • $offset (int|null) — смещение

Рабочий пример:

$activeUsers = $entityManager->getRepository(User::class)->findBy(
    ['status' => 'active'],
    ['createdAt' => 'DESC'],
    10,
    0
);

6. Repository::findOneBy()

Что делает: Находит одну сущность по заданным критериям. Возвращает объект или null.

Параметры:

  • $criteria (array) — ассоциативный массив [поле => значение]

Рабочий пример:

$admin = $entityManager->getRepository(User::class)->findOneBy([
    'email' => 'admin@example.com'
]);

7. QueryBuilder (создание сложных запросов)

Что делает: Позволяет программно строить DQL-запросы с помощью объектно-ориентированного API. Это основной способ создания сложных запросов.

Параметры:

  • Методы: select(), from(), where(), andWhere(), setParameter(), orderBy(), setMaxResults() и др.

Рабочий пример:

$queryBuilder = $entityManager->createQueryBuilder();
$query = $queryBuilder
    ->select('p')
    ->from(Product::class, 'p')
    ->where('p.price > :minPrice')
    ->andWhere('p.name LIKE :searchTerm')
    ->setParameter('minPrice', 1000)
    ->setParameter('searchTerm', '%ноут%')
    ->orderBy('p.price', 'DESC')
    ->setMaxResults(5)
    ->getQuery();

$products = $query->getResult();

8. DQL (Doctrine Query Language)

Что делает: Позволяет писать SQL-подобные запросы, но оперируя объектами и их свойствами, а не таблицами и столбцами.

Параметры:

  • $dql (string) — строка DQL-запроса

Рабочий пример:

$dql = "SELECT p FROM App\Entity\Product p WHERE p.price > :minPrice ORDER BY p.price DESC";
$query = $entityManager->createQuery($dql);
$query->setParameter('minPrice', 5000);
$products = $query->getResult();

9. EntityManager::getRepository()

Что делает: Возвращает репозиторий для указанной сущности. Репозиторий содержит методы для поиска и работы с сущностями.

Параметры:

  • $className (string) — полное имя класса сущности

Рабочий пример:

$productRepo = $entityManager->getRepository(Product::class);
$product = $productRepo->find(1);

10. EntityManager::clear()

Что делает: Очищает UnitOfWork — сбрасывает все отслеживаемые объекты. Полезно при обработке больших объёмов данных для освобождения памяти.

Параметры:

  • $entityName (string|null) — если указано, очищаются только объекты этого типа

Рабочий пример:

foreach ($largeDataset as $data) {
    $entity = new Entity();
    // ... заполнение
    $entityManager->persist($entity);
    $entityManager->flush();
    $entityManager->clear(); // Очищаем память
}

Реальный практический пример: Система управления заказами

Создадим мини-систему для интернет-магазина с сущностями: Customer, Order, OrderItem, Product.

Сущность Customer (Покупатель)

#[ORM\Entity]
class Customer
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private int $id;

    #[ORM\Column(length: 255)]
    private string $name;

    #[ORM\Column(length: 255, unique: true)]
    private                    

Рекомендаций