Как реализовать связь HasManyThrough из Laravel в Doctrine?

«Как реализовать связь HasManyThrough из Laravel в Doctrine?» — вопрос из категории Laravel, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Doctrine нет прямой декларативной аннотации для связи HasManyThrough, как в Laravel Eloquent. Однако эту связь можно эффективно эмулировать с помощью DQL-запросов (Doctrine Query Language) в репозитории сущности.

Рассмотрим пример, где User имеет много Post, а Post имеет много Comment. Нам нужно получить все Comment, принадлежащие User.

1. Определяем базовые связи (сущности):

// src/Entity/User.php
/**
 * @ORMOneToMany(targetEntity=Post::class, mappedBy="user")
 */
private $posts;

// src/Entity/Post.php
/**
 * @ORMManyToOne(targetEntity=User::class, inversedBy="posts")
 * @ORMJoinColumn(nullable=false)
 */
private $user;

/**
 * @ORMOneToMany(targetEntity=Comment::class, mappedBy="post")
 */
private $comments;

// src/Entity/Comment.php
/**
 * @ORMManyToOne(targetEntity=Post::class, inversedBy="comments")
 * @ORMJoinColumn(nullable=false)
 */
private $post;

2. Создаём метод в репозитории CommentRepository:

// src/Repository/CommentRepository.php
use DoctrineORMEntityRepository;

class CommentRepository extends EntityRepository
{
    public function findCommentsByUserId(int $userId): array
    {
        return $this->createQueryBuilder('c')
            ->innerJoin('c.post', 'p') // Присоединяем пост комментария
            ->innerJoin('p.user', 'u') // Присоединяем автора поста
            ->where('u.id = :userId')
            ->setParameter('userId', $userId)
            ->getQuery()
            ->getResult();
    }
}

3. Использование в сервисе или контроллере:

$userComments = $commentRepository->findCommentsByUserId(123);

Альтернативный подход — добавить метод-хелпер в сущность User: Можно создать метод в сущности User, который будет использовать DQL через EntityManager, но размещение такого запроса в репозитории считается более чистым с точки зрения архитектуры.