From ed2d2ec74aa5619a29c8392030e169c321d7dc0b Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Tue, 18 Aug 2026 08:43:11 +0330 Subject: [PATCH] fix(blog): order every blog list by id as well as created_at created_at is a second-resolution integer, so dozens of posts routinely share one value and MySQL is free to return tied rows in any order. Two consecutive pages of the same list could hand back one post twice and never show another, and the admin-list tests failed at random on whichever post got shuffled past the page boundary. Co-Authored-By: Claude Opus 5 (1M context) --- src/Blog/Repository/BlogRepository.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Blog/Repository/BlogRepository.php b/src/Blog/Repository/BlogRepository.php index 08b05620..e427fe3d 100644 --- a/src/Blog/Repository/BlogRepository.php +++ b/src/Blog/Repository/BlogRepository.php @@ -53,6 +53,13 @@ class BlogRepository extends ServiceEntityRepository * The admin review queue: posts awaiting a doctor's decision, newest first. * @return Blog[] */ + /* + * هر چهار فهرست روی `id` هم مرتب می‌شوند، نه فقط `createdAt`. + * + * `created_at` ثانیه‌ای است و ده‌ها مقاله می‌توانند دقیقاً یک مقدار داشته باشند؛ + * ترتیب بین ردیف‌های برابر در MySQL تضمین‌شده نیست. بدون این tiebreaker، دو صفحهٔ + * پیاپیِ همان فهرست می‌توانند یک مقاله را دوبار بدهند و مقالهٔ دیگری را هرگز. + */ public function findByReviewStatus(string $reviewStatus, int $page = 1, int $limit = 20): array { return $this->createQueryBuilder('b') @@ -61,6 +68,7 @@ class BlogRepository extends ServiceEntityRepository ->where('b.reviewStatus = :rs') ->setParameter('rs', $reviewStatus) ->orderBy('b.createdAt', 'DESC') + ->addOrderBy('b.id', 'DESC') ->setFirstResult(($page - 1) * $limit) ->setMaxResults($limit) ->getQuery()->getResult(); @@ -86,6 +94,7 @@ class BlogRepository extends ServiceEntityRepository $qb = $this->adminQb($status, $search) ->leftJoin('b.city', 'c')->addSelect('c') ->orderBy('b.createdAt', 'DESC') + ->addOrderBy('b.id', 'DESC') ->setFirstResult(($page - 1) * $limit) ->setMaxResults($limit); return $qb->getQuery()->getResult(); @@ -120,6 +129,7 @@ class BlogRepository extends ServiceEntityRepository ->where('b.representation = :rep') ->setParameter('rep', $rep) ->orderBy('b.createdAt', 'DESC') + ->addOrderBy('b.id', 'DESC') ->setFirstResult(($page - 1) * $limit) ->setMaxResults($limit); if ($status !== null && $status !== '') { @@ -166,6 +176,7 @@ class BlogRepository extends ServiceEntityRepository ->where('b.status = :status') ->setParameter('status', Blog::STATUS_PUBLISHED) ->orderBy('b.createdAt', 'DESC') + ->addOrderBy('b.id', 'DESC') ->setFirstResult(($page - 1) * $limit) ->setMaxResults($limit);