contextRepo->findByUser($user)?->getDbUuid(); if ($dbUuid === null) { return null; } $clinic = $this->clinicRepo->findByUuid($dbUuid); if ($clinic !== null) { return $this->secretaryRepo->findActiveBySecretaryForClinic($user, $clinic); } $doctor = $this->doctorRepo->findByUuid($dbUuid); if ($doctor !== null) { return $this->secretaryRepo->findActiveBySecretaryForDoctor($user, $doctor); } return null; } public function can(User $user, string $resource, string $action): bool { $relation = $this->activeRelation($user); return $relation !== null && $this->permissions->can($relation, $resource, $action); } /** * برای مسیرهایی که چند نقش دارند: فقط منشی را محدود کن. سایر نقش‌ها true. */ public function canOrNonSecretary(User $user, string $resource, string $action): bool { if (!$user->hasRole('ROLE_SECRETARY')) { return true; } return $this->can($user, $resource, $action); } /** 403 اگر منشی مجاز نباشد؛ نقش‌های دیگر بدون تغییر عبور می‌کنند. */ public function denyUnlessGranted(User $user, string $resource, string $action): void { if (!$this->canOrNonSecretary($user, $resource, $action)) { throw new AppException(ErrorCodes::ERR_FORBIDDEN_001, null, 403); } } }