diff --git a/frontend/utils/api.ts b/frontend/utils/api.ts index 6e673ec..4384a23 100644 --- a/frontend/utils/api.ts +++ b/frontend/utils/api.ts @@ -33,13 +33,27 @@ export async function fetchAllHydra( const first = await fetchPage(1) const all = extractHydraMembers(first) const total = extractHydraTotal(first) + const pageSize = all.length - if (total === undefined) { + // 1ʳᵉ page vide → collection vide, rien de plus à récupérer. + if (pageSize === 0) { return all } let page = 2 - while (all.length < total && page <= maxPages) { + while (page <= maxPages) { + if (total !== undefined) { + // Total connu : on s'arrête dès qu'on a tout récupéré. + if (all.length >= total) { + break + } + } else if (all.length % pageSize !== 0) { + // Total inconnu (provider custom sans `hydra:totalItems`) : la dernière + // page récupérée n'était pas pleine → fin de collection. On ne s'arrête + // pas en silence sur la 1ʳᵉ page, contrairement à `extractHydraMembers`. + break + } + const next = await fetchPage(page) const members = extractHydraMembers(next) if (members.length === 0) { diff --git a/src/Repository/NotificationRepository.php b/src/Repository/NotificationRepository.php index 76d642d..7dba9a8 100644 --- a/src/Repository/NotificationRepository.php +++ b/src/Repository/NotificationRepository.php @@ -7,7 +7,9 @@ namespace App\Repository; use App\Entity\Notification; use App\Entity\User; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; +use Symfony\Component\Security\Core\User\UserInterface; /** * @extends ServiceEntityRepository @@ -19,6 +21,15 @@ class NotificationRepository extends ServiceEntityRepository parent::__construct($registry, Notification::class); } + public function createUserNotificationsQueryBuilder(UserInterface $user): QueryBuilder + { + return $this->createQueryBuilder('n') + ->where('n.user = :user') + ->setParameter('user', $user) + ->orderBy('n.createdAt', 'DESC') + ; + } + public function countUnreadByUser(User $user): int { return (int) $this->createQueryBuilder('n') diff --git a/src/State/NotificationProvider.php b/src/State/NotificationProvider.php index 0a1b8b9..ff872c9 100644 --- a/src/State/NotificationProvider.php +++ b/src/State/NotificationProvider.php @@ -5,11 +5,17 @@ declare(strict_types=1); namespace App\State; use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\Pagination\Pagination; +use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; use App\Entity\Notification; use App\Repository\NotificationRepository; +use ArrayIterator; +use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Bundle\SecurityBundle\Security; +use function count; + /** * @implements ProviderInterface */ @@ -18,16 +24,28 @@ final readonly class NotificationProvider implements ProviderInterface public function __construct( private Security $security, private NotificationRepository $notificationRepository, + private Pagination $pagination, ) {} - public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|object + public function provide(Operation $operation, array $uriVariables = [], array $context = []): object { $user = $this->security->getUser(); - return $this->notificationRepository->findBy( - ['user' => $user], - ['createdAt' => 'DESC'], - 30, + [$page, $offset, $limit] = $this->pagination->getPagination($operation, $context); + + $queryBuilder = $this->notificationRepository + ->createUserNotificationsQueryBuilder($user) + ->setFirstResult($offset) + ->setMaxResults($limit) + ; + + $doctrinePaginator = new DoctrinePaginator($queryBuilder); + + return new TraversablePaginator( + new ArrayIterator(iterator_to_array($doctrinePaginator, false)), + $page, + $limit, + (float) count($doctrinePaginator), ); } }