Что такое 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 Также в библиотеке
Парсинг HTML в C# (.NET): библиотеки HtmlAgilityPack и AngleSharp
Redis-rs для Rust: полное руководство с примерами
Обработка изображений в Node.js: библиотеки Sharp, Jimp и gm
Машинное обучение на Kotlin: обзор библиотек KMath, Smile, KotlinDL и DeepLearning4J