createUser(['ROLE_DOCTOR']); $doctor = new Doctor($owner, 'دکتر تست'); $this->em->persist($doctor); $this->em->flush(); $tenant = new TenantInsurance(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 1); $section = new ServiceSection(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 'بخش'); $this->em->persist($tenant); $this->em->persist($section); $this->em->flush(); $expectedUuids = []; for ($i = 0; $i < 4; $i++) { $item = new ServiceItem($section, "خدمت $i"); $this->em->persist($item); $this->em->flush(); $expectedUuids[] = $item->getUuid(); $this->em->persist(new TenantServiceCoverage($tenant->getId(), $item->getId())); } $this->em->flush(); $body = $this->authJson( 'GET', '/api/v1/billing/tenant-insurances/' . $tenant->getUuid() . '/service-coverage', $owner, ); $this->assertSame(200, $this->responseCode()); $rows = $body['data']['data'] ?? $body['data']; $this->assertCount(4, $rows); $returnedUuids = array_column($rows, 'service_item_uuid'); sort($expectedUuids); sort($returnedUuids); $this->assertSame($expectedUuids, $returnedUuids); } /** @return array{0: \App\Auth\Entity\User, 1: TenantInsurance} */ private function makeContract(int $coverageRows): array { $owner = $this->createUser(['ROLE_DOCTOR']); $doctor = new Doctor($owner, 'دکتر تست'); $this->em->persist($doctor); $this->em->flush(); $tenant = new TenantInsurance(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 1); $section = new ServiceSection(TenantInsurance::TYPE_DOCTOR, $doctor->getId(), 'بخش'); $this->em->persist($tenant); $this->em->persist($section); $this->em->flush(); for ($i = 0; $i < $coverageRows; $i++) { $item = new ServiceItem($section, "خدمت $i"); $this->em->persist($item); $this->em->flush(); $this->em->persist(new TenantServiceCoverage($tenant->getId(), $item->getId())); } $this->em->flush(); return [$owner, $tenant]; } public function testQueryCountDoesNotGrowWithCoverageRows(): void { $this->client->disableReboot(); [$ownerS, $small] = $this->makeContract(1); [$ownerL, $large] = $this->makeContract(6); $this->em->clear(); $url = fn (TenantInsurance $t) => '/api/v1/billing/tenant-insurances/' . $t->getUuid() . '/service-coverage'; $qSmall = $this->countQueries(fn () => $this->authJson('GET', $url($small), $ownerS)); $qLarge = $this->countQueries(fn () => $this->authJson('GET', $url($large), $ownerL)); // batch fetch → constant query count; per-row find() would add ~1/row. $this->assertLessThanOrEqual($qSmall + 1, $qLarge, "N+1: query count grew from $qSmall to $qLarge"); } }