…]) آدرس کلینیک دیگری را هم برمی‌گرداند. هر کنترلری که * address_uuid می‌گیرد از اینجا رد می‌شود تا این بررسی جایی جا نیفتد. * * قبلاً `App\Branch\Service\BranchResolver` بود. با حذف مفهوم «شعبه» از محصول، اسم * و خانه‌اش عوض شد ولی خودش نمی‌توانست حذف شود: موتور رزرو، دسترس‌پذیری، قیمت و * کاتالوگ همگی از همین رد می‌شوند. */ final class AddressResolver { public function __construct( private readonly DoctorAddressRepository $addresses, private readonly EntityContextResolver $contexts, private readonly SecretaryAccessChecker $secretaryAccess, private readonly RequestStack $requestStack, ) {} /** * جفت محیطِ این درخواست. * * منشی جدا حساب می‌شود چون EntityContextResolver او را مالک هیچ محیطی نمی‌شناسد — * همان استثنایی که ClinicServiceController::resolveEntity() هم دارد. مجوزش جداگانه * با denyUnlessGranted سنجیده می‌شود، اینجا فقط «کدام محیط» است. * * @return array{0: string, 1: int} * @throws AppException وقتی محیطی حل نشود */ public function pair(User $user): array { [$type, $id] = $user->hasRole('ROLE_SECRETARY') ? $this->secretaryAccess->resolveOwnerEntity($user) : $this->contexts->resolve($user, $this->requestedClinicUuid())->toEntityPair(); if ($id === null) { throw new AppException(ErrorCodes::ERR_FORBIDDEN_001, 'محیط کاری انتخاب نشده است', 403); } return [$type, (int) $id]; } /** * ۴۰۴ می‌دهد نه ۴۰۳ — همان رفتار TenantFilter: وجودِ دادهٔ محیط دیگر لو نمی‌رود. * * @throws AppException */ public function resolve(User $user, string $addressUuid): DoctorAddress { [$entityType, $entityId] = $this->pair($user); $address = $this->addresses->findByUuidForEntityPair($addressUuid, $entityType, $entityId); if ($address === null) { throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, 'محل نوبت‌دهی یافت نشد', 404); } return $address; } /** @return DoctorAddress[] محل‌های نوبت‌دهی محیط جاری */ public function listForContext(User $user): array { [$entityType, $entityId] = $this->pair($user); return $this->addresses->findForEntityPair($entityType, $entityId); } private function requestedClinicUuid(): ?string { $request = $this->requestStack->getCurrentRequest(); if ($request === null) { return null; } $fromQuery = $request->query->get('clinic_uuid'); if (is_string($fromQuery) && $fromQuery !== '') { return $fromQuery; } if (!in_array($request->getMethod(), ['POST', 'PATCH', 'PUT'], true)) { return null; } $body = json_decode($request->getContent(), true); return is_array($body) && is_string($body['clinic_uuid'] ?? null) && $body['clinic_uuid'] !== '' ? $body['clinic_uuid'] : null; } }