authorize('view', $source); $source->load(['sourceType.fields', 'releves']); $fields = $source->sourceType->fields->sortBy('order'); $handle = fopen('php://temp', 'r+'); // BOM UTF-8 pour la compatibilité Excel fwrite($handle, "\xEF\xBB\xBF"); // En-tête fputcsv($handle, $fields->pluck('label')->toArray(), ';'); // Lignes foreach ($source->releves as $releve) { $row = []; foreach ($fields as $field) { $val = $releve->data[$field->name] ?? null; $row[] = $this->formatCsvValue($val, $field->type); } fputcsv($handle, $row, ';'); } rewind($handle); $csv = stream_get_contents($handle); fclose($handle); $filename = $this->sanitizeFilename($source->nom) . '.csv'; return response($csv, 200, [ 'Content-Type' => 'text/csv; charset=UTF-8', 'Content-Disposition' => "attachment; filename=\"{$filename}\"", ]); } private function formatCsvValue(mixed $val, FieldType $type): string { if ($val === null || $val === '') { return ''; } return match ($type) { FieldType::Boolean => $val ? 'Oui' : 'Non', FieldType::Date => is_array($val) ? trim(($val['valeur'] ?? '') . ( ! empty($val['calendrier']) && $val['calendrier'] !== 'gregorien' ? ' (' . $val['calendrier'] . ')' : '' )) : (string) $val, FieldType::Place => is_array($val) ? ($val['nom_long'] ?? '') : (string) $val, default => (string) $val, }; } private function sanitizeFilename(string $name): string { $name = iconv('UTF-8', 'ASCII//TRANSLIT', $name) ?: $name; return preg_replace('/[^a-zA-Z0-9_-]/', '_', $name); } }