getAttribute('tenant_id'); if ($tenantId === null || $tenantId === '') { self::requireExplicitWorkspaceId($model); return; } if (! is_numeric($tenantId)) { throw WorkspaceIsolationViolation::missingTenantId(class_basename($model)); } $tenantId = (int) $tenantId; self::ensureTenantIdIsImmutableOptional($model, $tenantId); $tenantWorkspaceId = self::resolveTenantWorkspaceIdOptional($model, $tenantId); $workspaceId = $model->getAttribute('workspace_id'); if ($workspaceId === null || $workspaceId === '') { $model->setAttribute('workspace_id', $tenantWorkspaceId); return; } if (! is_numeric($workspaceId)) { throw WorkspaceIsolationViolation::workspaceMismatch( class_basename($model), $tenantId, $tenantWorkspaceId, 0, ); } $workspaceId = (int) $workspaceId; if ($workspaceId !== $tenantWorkspaceId) { throw WorkspaceIsolationViolation::workspaceMismatch( class_basename($model), $tenantId, $tenantWorkspaceId, $workspaceId, ); } } private static function requireExplicitWorkspaceId(Model $model): void { $workspaceId = $model->getAttribute('workspace_id'); if (! is_numeric($workspaceId) || (int) $workspaceId <= 0) { throw WorkspaceIsolationViolation::missingTenantId( class_basename($model).' (tenantless record requires explicit workspace_id)', ); } } private static function ensureTenantIdIsImmutableOptional(Model $model, int $tenantId): void { if (! $model->exists || ! $model->isDirty('tenant_id')) { return; } $originalTenantId = $model->getOriginal('tenant_id'); if (! is_numeric($originalTenantId)) { return; } $originalTenantId = (int) $originalTenantId; if ($originalTenantId === $tenantId) { return; } throw WorkspaceIsolationViolation::tenantImmutable( class_basename($model), $originalTenantId, $tenantId, ); } private static function resolveTenantWorkspaceIdOptional(Model $model, int $tenantId): int { $tenant = $model->relationLoaded('tenant') ? $model->getRelation('tenant') : null; if (! $tenant instanceof Tenant || (int) $tenant->getKey() !== $tenantId) { $tenant = Tenant::query()->find($tenantId); } if (! $tenant instanceof Tenant) { throw WorkspaceIsolationViolation::tenantNotFound(class_basename($model), $tenantId); } if (! is_numeric($tenant->workspace_id)) { throw WorkspaceIsolationViolation::tenantWorkspaceMissing(class_basename($model), $tenantId); } return (int) $tenant->workspace_id; } }