Какие паттерны используются в Doctrine?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерны проектирования в Doctrine ORM
Doctrine ORM активно использует паттерны проектирования, которые обеспечивают гибкость, расширяемость и удобство работы с базой данных. Вот ключевые паттерны, применяемые в архитектуре Doctrine:
1. Data Mapper (Преобразователь данных)
Основной паттерн Doctrine, отделяющий бизнес-логику (сущности) от логики работы с базой данных (мапперы). Сущности не знают о том, как они сохраняются в БД.
// Сущность (бизнес-логика)
class User {
private $id;
private $name;
public function getName() {
return $this->name;
}
}
// Отдельно конфигурация маппинга (аннотации, XML, YAML)
/**
* @Entity
* @Table(name="users")
*/
class User {
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @Column(type="string") */
private $name;
}
2. Unit of Work (Единица работы)
Паттерн, который отслеживает изменения объектов и выполняет все необходимые SQL-запросы за один раз при вызове flush().
$user = $entityManager->find(User::class, 1);
$user->setName('Новое имя');
// Изменение отслеживается Unit of Work
$newUser = new User();
$newUser->setName('Новый пользователь');
$entityManager->persist($newUser);
// Объект добавлен в Unit of Work
$entityManager->flush();
// ВСЕ изменения сохранены одной транзакцией
3. Identity Map (Карта идентичности)
Гарантирует, что один и тот же объект сущности загружается только один раз в рамках сессии. Хранит ссылки на все загруженные объекты.
$user1 = $entityManager->find(User::class, 1);
$user2 = $entityManager->find(User::class, 1);
// $user1 и $user2 - один и тот же объект
var_dump($user1 === $user2); // true
4. Repository (Репозиторий)
Предоставляет абстрактный интерфейс для доступа к коллекциям объектов. Каждая сущность может иметь свой репозиторий с кастомными методами.
class UserRepository extends EntityRepository {
public function findActiveUsers() {
return $this->createQueryBuilder('u')
->where('u.active = :active')
->setParameter('active', true)
->getQuery()
->getResult();
}
}
// Использование
$activeUsers = $entityManager
->getRepository(User::class)
->findActiveUsers();
5. Query Builder (Построитель запросов)
Паттерн для постепенного построения сложных запросов DQL/ORM.
$queryBuilder = $entityManager->createQueryBuilder();
$query = $queryBuilder
->select('u', 'p')
->from(User::class, 'u')
->leftJoin('u.posts', 'p')
->where('u.age > :age')
->setParameter('age', 18)
->orderBy('u.name', 'ASC')
->getQuery();
6. Lazy Loading (Ленивая загрузка) через Proxy Objects
Загрузка связанных данных только при первом обращении к ним.
class User {
/** @OneToMany(targetEntity="Post", mappedBy="user") */
private $posts;
public function getPosts() {
// Коллекция загружается только при вызове этого метода
return $this->posts;
}
}
$user = $entityManager->find(User::class, 1);
$posts = $user->getPosts(); // Здесь выполняется запрос к БД
7. Strategy (Стратегия) для разных типов баз данных
Doctrine использует разные стратегии для генерации идентификаторов, работы с наследованием и поддержки различных СУБД.
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({"employee"="Employee", "manager"="Manager"})
*/
abstract class Person { /* ... */ }
class Employee extends Person { /* ... */ }
class Manager extends Person { /* ... */ }
8. Event Listeners / Subscribers (Слушатели событий)
Реализация паттерна Наблюдатель для реагирования на события жизненного цикла сущностей.
class AuditListener {
public function prePersist(LifecycleEventArgs $args) {
$entity = $args->getEntity();
if ($entity instanceof Auditable) {
$entity->setCreatedAt(new DateTime());
}
}
}
// Регистрация слушателя
$entityManager->getEventManager()->addEventListener(
['prePersist'],
new AuditListener()
);
9. Metadata Mapping (Метаданные маппинга)
Конфигурация маппинга через аннотации, XML, YAML или PHP-код, что позволяет отделить конфигурацию от бизнес-логики.
10. Identity Field / Foreign Key Mapping
Маппинг первичных и внешних ключей на свойства объектов.
Почему эти паттерны важны
- Сокращение дублирования кода – общая логика работы с БД инкапсулирована
- Упрощение тестирования – сущности можно тестировать без БД
- Гибкость – легко сменить СУБД или стратегии работы
- Производительность – Identity Map и Unit of Work оптимизируют запросы
- Поддержка сложных сценариев – наследование, полиморфные запросы, каскадные операции
Doctrine успешно комбинирует эти паттерны, предоставляя мощный ORM, который остается гибким и эффективным для enterprise-приложений. Ключевое преимущество – разделение ответственности: сущности занимаются бизнес-логикой, а Doctrine – персистентностью.