feat(tenant): implement tenant filter scope to manage cross-tenant data visibility

This commit is contained in:
hamed
2026-08-10 16:22:00 +03:30
parent ee2682e222
commit 2459625c41
8 changed files with 304 additions and 20 deletions
@@ -55,6 +55,7 @@ class AppointmentController extends BaseController
private readonly \App\Resource\Service\ResourceBookingSlotService $resourceSlots,
private readonly \App\Resource\Service\PublicResourceBookingService $publicResources,
private readonly \App\Treatment\Service\SessionBookingLink $sessionLink,
private readonly \App\Shared\Tenant\TenantFilterScope $tenantScope,
private readonly \Psr\Log\LoggerInterface $logger,
) {}
@@ -884,10 +885,19 @@ class AppointmentController extends BaseController
#[Route('/api/v1/appointments/user', methods: ['GET'])]
public function listByUser(Request $request, #[CurrentUser] User $user): JsonResponse
{
$status = $request->query->get('status');
$appointments = $this->appointmentRepo->findByUser($user, $status);
$status = $request->query->get('status');
return $this->success(['data' => array_map(fn(Appointment $a) => $a->toArray(), $appointments)]);
// نوبتِ بیمار در محیطِ پزشکِ مقصد ثبت می‌شود. کاربری که خودش صاحب محیط دیگری
// است — پزشک، منشی، مالک کلینیک — با فیلترِ محیطِ خودش نوبت‌های خودش را
// نمی‌دید. صاحب اینجا با `user_id` تعیین می‌شود، نه با محیط.
// `toArray()` هم داخل محدوده است: proxyهای پزشک و کلینیک آنجا باز می‌شوند و
// با فیلترِ برگشته، Doctrine `EntityNotFoundException` می‌دهد.
$rows = $this->tenantScope->withoutFilter(fn () => array_map(
fn(Appointment $a) => $a->toArray(),
$this->appointmentRepo->findByUser($user, $status),
));
return $this->success(['data' => $rows]);
}
private function canView(Appointment $a, User $user): bool