array_map('strval', $activeFilters['years'] ?? []), 'ap' => $activeFilters['ap'] ?? [], 'or' => $activeFilters['or'] ?? [], 'fi' => $activeFilters['fi'] ?? [], 'kw' => $activeFilters['kw'] ?? [], ]; // Build the student map from matched students only // name => [id, id, ...] (a student may have multiple theses) $studentWorks = []; // name => [thesis ids] foreach ($repData['students'] as $s) { if (empty($s['authors'])) continue; foreach (explode(',', $s['authors']) as $name) { $name = trim($name); if ($name === '') continue; $studentWorks[$name][] = (int)$s['id']; } } ksort($studentWorks); // Legacy alias for single-id use $studentMap = array_map(fn($ids) => $ids[0], $studentWorks); /** * Build the toggle URL for a filter button. * Toggles $value in $dim; keeps all other active filters intact. */ function repToggleUrl(array $sets, string $dim, string $value): string { if (in_array($value, $sets[$dim], true)) { $sets[$dim] = array_values(array_filter($sets[$dim], fn($v) => $v !== $value)); } else { $sets[$dim][] = $value; } $params = []; foreach ($sets['years'] as $v) $params[] = 'fy[]=' . urlencode((string)$v); foreach ($sets['ap'] as $v) $params[] = 'ap[]=' . urlencode($v); foreach ($sets['or'] as $v) $params[] = 'or[]=' . urlencode($v); foreach ($sets['fi'] as $v) $params[] = 'fi[]=' . urlencode($v); foreach ($sets['kw'] as $v) $params[] = 'kw[]=' . urlencode($v); $qs = implode('&', $params); return '/repertoire' . ($qs ? '?' . $qs : ''); } $anyActive = !empty($activeSets['years']) || !empty($activeSets['ap']) || !empty($activeSets['or']) || !empty($activeSets['fi']) || !empty($activeSets['kw']); // Per-column: does this dimension have ANY matched entry in the current result set? // When a column has zero matched entries despite other filters being active, it means // no thesis in the matched set carries that FK — the column has no useful cross-filter // signal and its entries must NOT be faded (the user may still want to select them). $colHasMatches = [ 'years' => !empty(array_filter($repData['years'], fn($i) => $i['matched'])), 'ap' => !empty(array_filter($repData['ap_programs'], fn($i) => $i['matched'])), 'or' => !empty(array_filter($repData['orientations'], fn($i) => $i['matched'])), 'fi' => !empty(array_filter($repData['finality_types'], fn($i) => $i['matched'])), 'kw' => !empty(array_filter($repData['keywords'], fn($i) => $i['matched'])), ]; // Common HTMX attributes for all active filter buttons $hx = 'hx-target="#repertoire-index" hx-swap="outerHTML" hx-push-url="true" hx-indicator="#rep-indicator"'; ?>

Années

Ateliers Pluridisciplinaires

Orientations

Finalité du Master

Étudiantes

Mots-clés