get(['id', 'nom']); $resultats = null; $total = null; // Charger le lieu sélectionné pour pré-remplir le picker $lieuSelectionne = $request->filled('lieu_id') ? Lieu::find($request->integer('lieu_id'), ['id', 'nom', 'nom_long']) : null; if ($request->anyFilled(['q', 'source_type_id', 'lieu_id', 'annee_debut', 'annee_fin'])) { [$resultats, $total] = $this->search($request); } return view('recherche.index', compact('sourceTypes', 'resultats', 'total', 'lieuSelectionne')); } private function search(Request $request): array { $user = auth()->user(); $query = Releve::with(['source.sourceType', 'source.depot', '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')); } }); // ── Recherche textuelle ────────────────────────────────────────────── 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]); } }); } // ── Filtre par lieu (+ descendants via CTE récursive) ──────────────── if ($request->filled('lieu_id')) { $lieuNoms = $this->getLieuNoms($request->integer('lieu_id')); if ($lieuNoms->isNotEmpty()) { $pattern = $lieuNoms ->map(fn ($n) => preg_quote($n, '/')) ->join('|'); $query->whereRaw(DbCompat::jsonRegexRaw('data'), [$pattern]); } } // ── Filtre par plage d'années ──────────────────────────────────────── 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']); } // ── Tri + pagination ──────────────────────────────────────────────── $total = $query->count(); $resultats = $query ->orderByRaw('nom ASC NULLS LAST') ->orderByRaw('date_evenement ASC NULLS LAST') ->paginate(25) ->withQueryString(); return [$resultats, $total]; } /** * Retourne les noms du lieu et de tous ses descendants via CTE récursive PostgreSQL. */ private function getLieuNoms(int $lieuId): \Illuminate\Support\Collection { $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 ", [$lieuId]); return collect($rows)->pluck('nom')->filter(); } }