236d37976c
DbCompat (app/Support/DbCompat.php) : - like() → ilike (pgsql) ou like (mysql) - jsonRegexRaw() → data::text ~* ? (pgsql) ou CAST(data AS CHAR) REGEXP ? (mysql) - ftsRaw() → to_tsvector/plainto_tsquery (pgsql) ou null/fallback LIKE (mysql) - generatedJsonCol() → syntaxe colonne générée JSON selon le SGBD - generatedJsonNestedCol() → idem pour champs imbriqués Migrations : - create_releves_table : JSON/JSONB selon SGBD, colonnes générées adaptées, index GIN uniquement pour PostgreSQL Controllers : - LieuController (search + index) : ilike → DbCompat::like() - Admin\UserController (index) : ilike → DbCompat::like() - RechercheController : FTS + regex → DbCompat, fallback LIKE MySQL - ExportController : regex → DbCompat::jsonRegexRaw() UpdateService : - backupDatabase() : pg_dump (pgsql) ou mysqldump (mysql) - restoreBackup() : psql (pgsql) ou mysql (mysql) Docker : - docker-compose.yml : suppression Redis (plus requis) - docker-compose.mysql.yml : nouveau fichier pour dev MySQL - docker-compose.prod.yml : suppression Redis, DB_IMAGE configurable, CACHE_STORE/SESSION_DRIVER/QUEUE_CONNECTION → database par défaut .env.example : - DB_PORT commenté avec les deux valeurs (5432/3306) - CACHE_STORE et QUEUE_CONNECTION commentés (database par défaut) - Redis marqué optionnel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
115 lines
4.1 KiB
PHP
115 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Enums\SourceStatus;
|
|
use App\Models\Releve;
|
|
use App\Models\Source;
|
|
use App\Services\GedcomExportService;
|
|
use App\Support\DbCompat;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class ExportController extends Controller
|
|
{
|
|
public function __construct(
|
|
private readonly GedcomExportService $gedcom,
|
|
) {}
|
|
|
|
/** Export de tous les relevés d'une source */
|
|
public function source(Source $source): Response
|
|
{
|
|
$this->authorize('view', $source);
|
|
|
|
$gedcomContent = $this->gedcom->exportSource($source);
|
|
$filename = $this->sanitizeFilename($source->nom) . '.ged';
|
|
|
|
return response($gedcomContent, 200, [
|
|
'Content-Type' => 'text/plain; charset=UTF-8',
|
|
'Content-Disposition' => "attachment; filename=\"{$filename}\"",
|
|
]);
|
|
}
|
|
|
|
/** Export depuis les résultats de recherche (avec les mêmes filtres) */
|
|
public function recherche(Request $request): Response
|
|
{
|
|
$user = auth()->user();
|
|
|
|
$query = Releve::with(['source.sourceType', 'createur'])
|
|
->whereHas('source', function ($q) use ($user, $request) {
|
|
if (! $user->isSectionManager()) {
|
|
$assignedIds = $user->sourcesAssignees()->pluck('sources.id');
|
|
$q->where(function ($sq) use ($assignedIds) {
|
|
$sq->where('status', SourceStatus::Termine)
|
|
->orWhereIn('id', $assignedIds);
|
|
});
|
|
}
|
|
if ($request->filled('source_type_id')) {
|
|
$q->where('source_type_id', $request->integer('source_type_id'));
|
|
}
|
|
}); // $request déjà dans le use()
|
|
|
|
if ($request->filled('q')) {
|
|
$q = trim($request->get('q'));
|
|
$like = DbCompat::like();
|
|
$fts = DbCompat::ftsRaw();
|
|
|
|
$query->where(function ($wq) use ($q, $like, $fts) {
|
|
$wq->where('nom', $like, "%{$q}%")
|
|
->orWhere('prenom', $like, "%{$q}%")
|
|
->orWhere('date_evenement', $like, "%{$q}%");
|
|
if ($fts) {
|
|
$wq->orWhereRaw($fts, [$q]);
|
|
}
|
|
});
|
|
}
|
|
|
|
if ($request->filled('lieu_id')) {
|
|
$rows = DB::select("
|
|
WITH RECURSIVE descendants AS (
|
|
SELECT id, nom FROM lieux WHERE id = ?
|
|
UNION ALL
|
|
SELECT l.id, l.nom FROM lieux l
|
|
INNER JOIN descendants d ON l.lieu_parent_id = d.id
|
|
)
|
|
SELECT DISTINCT nom FROM descendants WHERE nom IS NOT NULL
|
|
", [$request->integer('lieu_id')]);
|
|
|
|
$noms = collect($rows)->pluck('nom')->filter();
|
|
if ($noms->isNotEmpty()) {
|
|
$pattern = $noms->map(fn ($n) => preg_quote($n, '/'))->join('|');
|
|
$query->whereRaw(DbCompat::jsonRegexRaw('data'), [$pattern]);
|
|
}
|
|
}
|
|
|
|
if ($request->filled('annee_debut')) {
|
|
$query->whereRaw('date_evenement >= ?', [$request->integer('annee_debut') . '-01-01']);
|
|
}
|
|
if ($request->filled('annee_fin')) {
|
|
$query->whereRaw('date_evenement <= ?', [$request->integer('annee_fin') . '-12-31']);
|
|
}
|
|
|
|
$releves = $query->orderByRaw('nom ASC NULLS LAST')->get();
|
|
|
|
if ($releves->isEmpty()) {
|
|
return back()->with('error', 'Aucun relevé à exporter.');
|
|
}
|
|
|
|
$titre = $request->filled('q') ? 'Recherche_' . $request->get('q') : 'Export';
|
|
$gedcomContent = $this->gedcom->exportReleves($releves, $titre);
|
|
$filename = $this->sanitizeFilename($titre) . '.ged';
|
|
|
|
return response($gedcomContent, 200, [
|
|
'Content-Type' => 'text/plain; charset=UTF-8',
|
|
'Content-Disposition' => "attachment; filename=\"{$filename}\"",
|
|
]);
|
|
}
|
|
|
|
private function sanitizeFilename(string $name): string
|
|
{
|
|
$name = iconv('UTF-8', 'ASCII//TRANSLIT', $name) ?: $name;
|
|
return preg_replace('/[^a-zA-Z0-9_-]/', '_', $name);
|
|
}
|
|
}
|