← Назад к вопросам

Какие паттерны используются в Doctrine?

2.2 Middle🔥 181 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерны проектирования в 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 – персистентностью.