where('stabile_id', (int) $activeStabile->id); } elseif (! $user->hasAnyRole(['super-admin', 'admin'])) { $allowedIds = StabileContext::accessibleStabili($user) ->pluck('id') ->map(fn($value): int => (int) $value) ->all(); if ($allowedIds === []) { $query->whereRaw('1 = 0'); return $query; } $query->whereIn('stabile_id', $allowedIds); } return $query->where(function (Builder $documentQuery) use ($user): void { $documentQuery->whereNull('cartella_archivio_id') ->where(function (Builder $baseVisibility) use ($user): void { $baseVisibility->whereNull('visibility_scope') ->orWhere('visibility_scope', 'interno') ->orWhere(function (Builder $restricted) use ($user): void { $this->applyVisibilityConstraint($restricted, $user, 'documenti'); }); }) ->orWhereHas('cartellaArchivio', function (Builder $folderQuery) use ($user): void { $folderQuery->where('is_active', true); $this->applyVisibilityConstraint($folderQuery, $user, 'documento_archivio_cartelle'); }); }); } public function scopeVisibleCartelle(Builder $query, User $user, ?int $stabileId = null): Builder { if ($stabileId !== null && $stabileId > 0) { $query->where('stabile_id', $stabileId); } else { $activeStabile = StabileContext::getActiveStabile($user); if ($activeStabile !== null) { $query->where('stabile_id', (int) $activeStabile->id); } elseif (! $user->hasAnyRole(['super-admin', 'admin'])) { $allowedIds = StabileContext::accessibleStabili($user) ->pluck('id') ->map(fn($value): int => (int) $value) ->all(); if ($allowedIds === []) { $query->whereRaw('1 = 0'); return $query; } $query->whereIn('stabile_id', $allowedIds); } } $query->where('is_active', true); $this->applyVisibilityConstraint($query, $user, 'documento_archivio_cartelle'); return $query; } public function canAccessDocumento(User $user, Documento $documento): bool { return $this->scopeVisibleDocumenti(Documento::query()->whereKey($documento->getKey()), $user)->exists(); } public function canAccessDocumentoStabile(User $user, DocumentoStabile $documentoStabile): bool { $allowedIds = StabileContext::accessibleStabili($user) ->pluck('id') ->map(fn($value): int => (int) $value) ->all(); return in_array((int) $documentoStabile->stabile_id, $allowedIds, true); } private function applyVisibilityConstraint(Builder $query, User $user, string $table): void { if (! $this->hasVisibilityColumn($table, 'visibility_scope')) { return; } $roles = $user->getRoleNames()->map(fn($role): string => (string) $role)->values()->all(); $groupLabels = $this->resolveAudienceGroupsForUser($user); $userId = (int) $user->id; $hasRolesColumn = $this->hasVisibilityColumn($table, 'visibility_roles'); $hasGroupsColumn = $this->hasVisibilityColumn($table, 'visibility_groups'); $hasAllowedUsersColumn = $this->hasVisibilityColumn($table, 'allowed_user_ids'); $query->where(function (Builder $visibilityQuery) use ($table, $roles, $groupLabels, $userId, $hasRolesColumn, $hasGroupsColumn, $hasAllowedUsersColumn): void { $visibilityQuery->whereNull($table . '.visibility_scope') ->orWhere($table . '.visibility_scope', 'interno') ->orWhere($table . '.visibility_scope', 'studio') ->orWhere(function (Builder $restrictedQuery) use ($table, $roles, $groupLabels, $userId, $hasRolesColumn, $hasGroupsColumn, $hasAllowedUsersColumn): void { $restrictedQuery->where($table . '.visibility_scope', 'restricted') ->where(function (Builder $matchQuery) use ($table, $roles, $groupLabels, $userId, $hasRolesColumn, $hasGroupsColumn, $hasAllowedUsersColumn): void { $hasAudienceConstraint = false; if ($hasRolesColumn && $roles !== []) { foreach ($roles as $role) { $matchQuery->orWhereJsonContains($table . '.visibility_roles', $role); } $hasAudienceConstraint = true; } if ($hasGroupsColumn && $groupLabels !== []) { foreach ($groupLabels as $groupLabel) { $matchQuery->orWhereJsonContains($table . '.visibility_groups', $groupLabel); } $hasAudienceConstraint = true; } if ($hasAllowedUsersColumn) { $matchQuery->orWhereJsonContains($table . '.allowed_user_ids', $userId); $hasAudienceConstraint = true; } if (! $hasAudienceConstraint) { $matchQuery->whereRaw('1 = 0'); } }); }); }); } private function hasVisibilityColumn(string $table, string $column): bool { static $cache = []; $cacheKey = $table . '.' . $column; if (! array_key_exists($cacheKey, $cache)) { $cache[$cacheKey] = Schema::hasColumn($table, $column); } return $cache[$cacheKey]; } private function resolveAudienceGroupsForUser(User $user): array { $groups = []; if ($user->hasAnyRole(['super-admin', 'admin', 'amministratore'])) { $groups[] = 'Amministratore'; $groups[] = 'Studio completo'; } if ($user->hasRole('collaboratore')) { $groups[] = 'Collaboratori interni'; } return array_values(array_unique($groups)); } }