serviceItemRepo->findByUuid($data['service_item_uuid']); * * جست‌وجو با uuid **خودش** یک کوئری بی‌لنگر است، و فیلتر وقتی ستونی نباشد کاری * نمی‌تواند بکند. هر سه نشتی فاز ۷ همین شکل را داشتند. * * این تست‌ها عمداً **هیچ گارد دستی صدا نمی‌زنند** — فقط خودِ فیلتر. اگر ستون‌ها * برداشته شوند، همگی قرمز می‌شوند. */ class RequestReachableChildTenantTest extends ApiTestCase { private function em(): EntityManagerInterface { return static::getContainer()->get(EntityManagerInterface::class); } protected function tearDown(): void { $filters = $this->em()->getFilters(); if ($filters->isEnabled(TenantFilter::NAME)) { $filters->disable(TenantFilter::NAME); } parent::tearDown(); } private function enableFilterFor(string $type, int $id): void { $this->em()->getFilters() ->enable(TenantFilter::NAME) ->setParameter(TenantFilter::PARAM_TYPE, $type, 'string') ->setParameter(TenantFilter::PARAM_ID, $id, 'integer'); } private function makeDoctor(): Doctor { $doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر فرزند'); $this->em->persist($doctor); $this->em->flush(); return $doctor; } private function serviceItemOf(Doctor $doctor): ServiceItem { $section = new ServiceSection('doctor', $doctor->getId(), 'بخش'); $this->em->persist($section); $item = new ServiceItem($section, 'سرویس', 100); $this->em->persist($item); $this->em->flush(); return $item; } private function sessionOf(Doctor $doctor): PatientSession { $record = new PatientRecord('doctor', $doctor->getId(), $this->createUser(['ROLE_USER']), 'doctor', $doctor->getId()); $this->em->persist($record); $session = new PatientSession($record); $this->em->persist($session); $this->em->flush(); return $session; } /** جفت محیط از ریشه مشتق می‌شود، نه از ورودی سازنده — پس نمی‌تواند واگرا شود. */ public function testTheChildInheritsItsRootsEnvironmentOnConstruction(): void { $doctor = $this->makeDoctor(); $item = $this->serviceItemOf($doctor); $session = $this->sessionOf($doctor); self::assertSame('doctor', $item->getEntityType()); self::assertSame($doctor->getId(), $item->getEntityId()); self::assertSame($doctor->getId(), $session->getEntityId()); } /** ✅ در محیط خودی، جست‌وجو با uuid موجودیت را می‌دهد. */ public function testALookupByUuidSucceedsInsideItsOwnEnvironment(): void { $doctor = $this->makeDoctor(); $uuid = $this->serviceItemOf($doctor)->getUuid(); $this->em->clear(); $this->enableFilterFor('doctor', $doctor->getId()); self::assertNotNull($this->em->getRepository(ServiceItem::class)->findOneBy(['uuid' => $uuid])); } /** * ❌ همان جست‌وجو در محیط دیگر تهی برمی‌گردد — **بدون هیچ گارد دستی**. * این همان نشتی مالی فاز ۷ است که حالا در سطح داده بسته شده. */ public function testTheSameLookupReturnsNothingInAnotherEnvironment(): void { $doctor = $this->makeDoctor(); $uuid = $this->serviceItemOf($doctor)->getUuid(); $this->em->clear(); $this->enableFilterFor('doctor', $doctor->getId() + 1000); self::assertNull($this->em->getRepository(ServiceItem::class)->findOneBy(['uuid' => $uuid])); } /** ❌ همین قاعده برای مراجعه — که ۷ نقطهٔ جست‌وجو با uuid دارد. */ public function testASessionOfAnotherEnvironmentIsInvisible(): void { $doctor = $this->makeDoctor(); $uuid = $this->sessionOf($doctor)->getUuid(); $this->em->clear(); $this->enableFilterFor('doctor', $doctor->getId() + 1000); self::assertNull($this->em->getRepository(PatientSession::class)->findOneBy(['uuid' => $uuid])); } /** ⚠️ مرزی: نوهٔ ریشه (پرداختِ مراجعه) هم محیطش را از همان زنجیره می‌گیرد. */ public function testAGrandchildTakesTheEnvironmentOfTheChainToo(): void { $doctor = $this->makeDoctor(); $session = $this->sessionOf($doctor); $payment = new SessionPayment($session, 'cash', 50_000); $this->em->persist($payment); $this->em->flush(); $uuid = $payment->getUuid(); self::assertSame($doctor->getId(), $payment->getEntityId()); $this->em->clear(); $this->enableFilterFor('doctor', $doctor->getId() + 1000); self::assertNull($this->em->getRepository(SessionPayment::class)->findOneBy(['uuid' => $uuid])); } }