diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php index 6b10955..735f89a 100644 --- a/app/Http/Controllers/ExportController.php +++ b/app/Http/Controllers/ExportController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Enums\FieldType; use App\Enums\SourceStatus; use App\Models\Releve; use App\Models\Source; @@ -17,6 +18,44 @@ class ExportController extends Controller private readonly GedcomExportService $gedcom, ) {} + /** Export CSV de tous les relevés d'une source */ + public function sourceCsv(Source $source): Response + { + $this->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}\"", + ]); + } + /** Export de tous les relevés d'une source */ public function source(Source $source): Response { @@ -106,6 +145,26 @@ class ExportController extends Controller ]); } + 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; diff --git a/resources/views/sources/show.blade.php b/resources/views/sources/show.blade.php index 86b349d..e9d083e 100644 --- a/resources/views/sources/show.blade.php +++ b/resources/views/sources/show.blade.php @@ -134,12 +134,24 @@

Relevés ({{ $source->releves->count() }})

- @can('create', [App\Models\Releve::class, $source]) - - + Nouveau relevé - - @endcan +
+ @if($source->releves->isNotEmpty()) + + ↓ CSV + + + ↓ GEDCOM + + @endif + @can('create', [App\Models\Releve::class, $source]) + + + Nouveau relevé + + @endcan +
@if($source->releves->isEmpty())

Aucun relevé pour cette source.

diff --git a/routes/web.php b/routes/web.php index 8a3bb03..78559da 100644 --- a/routes/web.php +++ b/routes/web.php @@ -61,6 +61,7 @@ Route::middleware('auth')->group(function () { Route::get('carte', [CarteController::class, 'index'])->name('carte'); Route::get('carte/data', [CarteController::class, 'data'])->name('carte.data'); Route::get('export/source/{source}', [ExportController::class, 'source'])->name('export.source'); + Route::get('export/source/{source}/csv', [ExportController::class, 'sourceCsv'])->name('export.source.csv'); Route::get('export/recherche', [ExportController::class, 'recherche'])->name('export.recherche'); Route::get('notifications', [NotificationController::class, 'index'])->name('notifications.index');