*/ class DoctrineMailMessageRepository extends ServiceEntityRepository implements MailMessageRepositoryInterface { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, MailMessage::class); } public function findById(int $id): ?MailMessage { return $this->find($id); } public function findByMessageId(string $messageId): ?MailMessage { return $this->findOneBy(['messageId' => $messageId]); } public function findByFolderAndUid(MailFolder $folder, int $uid): ?MailMessage { return $this->findOneBy(['folder' => $folder, 'uid' => $uid]); } /** * @return list */ public function findByFolderPaginated(MailFolder $folder, int $limit, int $offset): array { return $this->createQueryBuilder('m') ->andWhere('m.folder = :folder') ->setParameter('folder', $folder) ->orderBy('m.sentAt', 'DESC') ->addOrderBy('m.id', 'DESC') ->setMaxResults($limit) ->setFirstResult($offset) ->getQuery() ->getResult() ; } public function countUnreadByFolder(MailFolder $folder): int { return (int) $this->createQueryBuilder('m') ->select('COUNT(m.id)') ->andWhere('m.folder = :folder') ->andWhere('m.isRead = false') ->setParameter('folder', $folder) ->getQuery() ->getSingleScalarResult() ; } public function findMaxUidInFolder(MailFolder $folder): int { $result = $this->createQueryBuilder('m') ->select('MAX(m.uid)') ->andWhere('m.folder = :folder') ->setParameter('folder', $folder) ->getQuery() ->getSingleScalarResult() ; return (int) ($result ?? 0); } /** * @return list */ public function findLastNByFolder(MailFolder $folder, int $limit): array { return $this->createQueryBuilder('m') ->andWhere('m.folder = :folder') ->setParameter('folder', $folder) ->orderBy('m.sentAt', 'DESC') ->addOrderBy('m.id', 'DESC') ->setMaxResults($limit) ->getQuery() ->getResult() ; } /** * @return list */ public function findAllUidsByFolder(MailFolder $folder): array { $rows = $this->createQueryBuilder('m') ->select('m.uid') ->andWhere('m.folder = :folder') ->setParameter('folder', $folder) ->getQuery() ->getArrayResult() ; return array_column($rows, 'uid'); } /** * Pagination cursor : retourne $limit messages apres le cursor (sentAt DESC, id DESC). * Cursor format : base64url(sentAt_iso8601:id) - null pour la premiere page. * * @return array{messages: list, nextCursor: ?string} */ public function findByFolderCursor(MailFolder $folder, int $limit, ?string $cursor): array { $qb = $this->createQueryBuilder('m') ->andWhere('m.folder = :folder') ->setParameter('folder', $folder) ->orderBy('m.sentAt', 'DESC') ->addOrderBy('m.id', 'DESC') ->setMaxResults($limit + 1) ; if (null !== $cursor) { $decoded = base64_decode(strtr($cursor, '-_', '+/'), true); if (false !== $decoded && str_contains($decoded, ':')) { [$sentAtStr, $idStr] = explode(':', $decoded, 2); $cursorSentAt = DateTimeImmutable::createFromFormat(DateTimeInterface::ATOM, $sentAtStr); $cursorId = (int) $idStr; if ($cursorSentAt instanceof DateTimeImmutable) { $qb ->andWhere('m.sentAt < :cursorSentAt OR (m.sentAt = :cursorSentAt AND m.id < :cursorId)') ->setParameter('cursorSentAt', $cursorSentAt) ->setParameter('cursorId', $cursorId) ; } } } /** @var list $results */ $results = $qb->getQuery()->getResult(); $hasMore = count($results) > $limit; $messages = $hasMore ? array_slice($results, 0, $limit) : $results; $nextCursor = null; if ($hasMore && [] !== $messages) { $last = end($messages); $raw = $last->getSentAt()->format(DateTimeInterface::ATOM).':'.$last->getId(); $nextCursor = rtrim(strtr(base64_encode($raw), '+/', '-_'), '='); } return ['messages' => $messages, 'nextCursor' => $nextCursor]; } }