createUser(['ROLE_DOCTOR']), 'دکتر تست'); $this->em->persist($doctor); $root = (new Comment($this->createUser(), $doctor, 'نظر ریشه'))->approve(); $this->em->persist($root); // two likes + one dislike → like_count 2, dislike_count 1 $this->em->persist(new Like($this->createUser(), $root, 1)); $this->em->persist(new Like($this->createUser(), $root, 1)); $this->em->persist(new Like($this->createUser(), $root, -1)); $reply = (new Comment($this->createUser(), $doctor, 'پاسخ تأییدشده', $root))->approve(); $this->em->persist($reply); // a pending reply must NOT appear $this->em->persist(new Comment($this->createUser(), $doctor, 'پاسخ در انتظار', $root)); $this->em->flush(); $this->em->clear(); $body = $this->jsonGet('/api/v1/comments/' . $doctor->getUuid()); $roots = $body['data']['data']; $this->assertCount(1, $roots); $r = $roots[0]; $this->assertSame('نظر ریشه', $r['comment']); $this->assertSame(2, $r['like_status']['like_count']); $this->assertSame(1, $r['like_status']['dislike_count']); $this->assertCount(1, $r['replies']); // only the approved reply $this->assertSame('پاسخ تأییدشده', $r['replies'][0]['comment']); } private function jsonGet(string $uri): array { $this->client->request('GET', $uri); return json_decode($this->client->getResponse()->getContent(), true) ?? []; } /** * True N+1 regression: after the repository loads the roots, their likes and * replies collections must already be initialised (fetch-joined). Without the * fetch-join they are lazy and would each trigger a query during serialization. */ public function testRepositoryFetchJoinsCollections(): void { $doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر تست'); $this->em->persist($doctor); $root = (new Comment($this->createUser(), $doctor, 'نظر'))->approve(); $this->em->persist($root); $this->em->persist(new Like($this->createUser(), $root, 1)); $this->em->persist((new Comment($this->createUser(), $doctor, 'پاسخ', $root))->approve()); $this->em->flush(); $doctorId = $doctor->getId(); // fresh load — collections must come back initialised, not lazy proxies $this->em->clear(); $doctor = $this->em->getRepository(Doctor::class)->find($doctorId); $roots = $this->em->getRepository(Comment::class)->findApprovedRootsByDoctor($doctor); $this->assertNotEmpty($roots); foreach ($roots as $r) { $likes = $r->getLikes(); $replies = $r->getReplies(); $this->assertInstanceOf(PersistentCollection::class, $likes); $this->assertInstanceOf(PersistentCollection::class, $replies); $this->assertTrue($likes->isInitialized(), 'likes collection was not fetch-joined'); $this->assertTrue($replies->isInitialized(), 'replies collection was not fetch-joined'); } } }