mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 11:09:18 +02:00
Split search into search.php; repertoire.php is index-only
This commit is contained in:
7
TODO.md
7
TODO.md
@@ -1,6 +1,13 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
## Done
|
## Done
|
||||||
|
- [x] Split search logic into search.php
|
||||||
|
- [x] `public/search.php` — new page for text-query search results
|
||||||
|
- [x] `public/repertoire.php` — stripped to répertoire index only
|
||||||
|
- [x] `SearchController::handle()` split into `handleSearch()` + `handleRepertoire()`
|
||||||
|
- [x] Search bar (`header.php`, `search-bar.php`) now POSTs to `/search.php`
|
||||||
|
- [x] `tfe.php` `?query=` links updated to `/search.php`
|
||||||
|
- [x] Filter links (`?or[]=`, `?ap[]=`, `?fy[]=`, `?kw[]=`) stay on `repertoire.php`
|
||||||
- [x] TFE metadata values are hyperlinks to repertoire.php with correct filter/search params
|
- [x] TFE metadata values are hyperlinks to repertoire.php with correct filter/search params
|
||||||
- orientation → `or[]`, ap_program → `ap[]`, year → `fy[]`, keywords → `kw[]` (per keyword)
|
- orientation → `or[]`, ap_program → `ap[]`, year → `fy[]`, keywords → `kw[]` (per keyword)
|
||||||
- languages, formats → `query=` (text search); jury members → `query=` (text search)
|
- languages, formats → `query=` (text search); jury members → `query=` (text search)
|
||||||
|
|||||||
@@ -5,91 +5,17 @@ require_once APP_ROOT . '/src/SearchController.php';
|
|||||||
// Build controller (performs rate-limit check; exits with HTTP 429 if exceeded)
|
// Build controller (performs rate-limit check; exits with HTTP 429 if exceeded)
|
||||||
$ctrl = SearchController::create();
|
$ctrl = SearchController::create();
|
||||||
|
|
||||||
// Collect all view variables (may exit early if HTMX partial request)
|
// Collect all view variables for the répertoire index page
|
||||||
extract($ctrl->handle());
|
extract($ctrl->handleRepertoire());
|
||||||
?>
|
?>
|
||||||
<?php include APP_ROOT . '/templates/head.php'; ?>
|
<?php include APP_ROOT . '/templates/head.php'; ?>
|
||||||
<?php include APP_ROOT . '/templates/header.php'; ?>
|
<?php include APP_ROOT . '/templates/header.php'; ?>
|
||||||
|
|
||||||
<?php if ($validationError): ?>
|
|
||||||
<div class="search-error">⚠ <?= htmlspecialchars($validationError) ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($hasSearch): ?>
|
|
||||||
<!-- ── RESULTS VIEW ─────────────────────────────────── -->
|
|
||||||
|
|
||||||
<!-- Filter controls -->
|
|
||||||
<form class="search-controls" method="GET" action="repertoire.php">
|
|
||||||
<input type="hidden" name="query" value="<?= htmlspecialchars($_GET['query'] ?? '') ?>">
|
|
||||||
|
|
||||||
<label class="search-filter-label" for="filter-year">Année
|
|
||||||
<select class="search-filter-select" name="year" id="filter-year">
|
|
||||||
<option value="">Toutes</option>
|
|
||||||
<?php foreach ($years as $y): ?>
|
|
||||||
<option value="<?= (int)$y ?>" <?= (isset($_GET['year']) && $_GET['year'] == $y) ? 'selected' : '' ?>>
|
|
||||||
<?= (int)$y ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label class="search-filter-label" for="filter-orientation">Orientation
|
|
||||||
<select class="search-filter-select" name="orientation" id="filter-orientation">
|
|
||||||
<option value="">Toutes</option>
|
|
||||||
<?php foreach ($orientations as $o): ?>
|
|
||||||
<option value="<?= htmlspecialchars($o['name']) ?>"
|
|
||||||
<?= (isset($_GET['orientation']) && $_GET['orientation'] == $o['name']) ? 'selected' : '' ?>>
|
|
||||||
<?= htmlspecialchars($o['name']) ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label class="search-filter-label" for="filter-ap">AP
|
|
||||||
<select class="search-filter-select" name="ap_program" id="filter-ap">
|
|
||||||
<option value="">Tous</option>
|
|
||||||
<?php foreach ($apPrograms as $ap): ?>
|
|
||||||
<option value="<?= htmlspecialchars($ap['name']) ?>"
|
|
||||||
<?= (isset($_GET['ap_program']) && $_GET['ap_program'] == $ap['name']) ? 'selected' : '' ?>>
|
|
||||||
<?= htmlspecialchars($ap['name']) ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<button type="submit" class="search-apply-btn">Filtrer</button>
|
|
||||||
<a href="repertoire.php" class="search-reset-link">Réinitialiser</a>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<main class="search-main" id="main-content">
|
|
||||||
<output class="search-results-header" role="status"><?= $totalItems ?> résultat<?= $totalItems > 1 ? 's' : '' ?></output>
|
|
||||||
|
|
||||||
<?php if (!empty($results)): ?>
|
|
||||||
<ul class="results-grid">
|
|
||||||
<?php foreach ($results as $item): ?>
|
|
||||||
<li><a href="tfe.php?id=<?= (int)$item['id'] ?>" class="result-card">
|
|
||||||
<span class="result-card__authors"><?= htmlspecialchars($item['authors'] ?? '') ?></span>
|
|
||||||
<span class="result-card__title"><?= htmlspecialchars($item['title']) ?></span>
|
|
||||||
<small class="result-card__meta"><?= htmlspecialchars($item['year']) ?><?php if (!empty($item['orientation'])): ?> · <?= htmlspecialchars($item['orientation']) ?><?php endif; ?></small>
|
|
||||||
</a></li>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<?php include APP_ROOT . '/templates/partials/pagination.php'; ?>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
<p class="search-empty">Aucun résultat pour cette recherche.</p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
<!-- ── RÉPERTOIRE INDEX VIEW ─────────────────────────── -->
|
|
||||||
<main class="search-main" id="main-content">
|
<main class="search-main" id="main-content">
|
||||||
<h1 class="sr-only">Répertoire</h1>
|
<h1 class="sr-only">Répertoire</h1>
|
||||||
<span id="rep-indicator" class="rep-indicator htmx-indicator" aria-hidden="true"></span>
|
<span id="rep-indicator" class="rep-indicator htmx-indicator" aria-hidden="true"></span>
|
||||||
<?php include APP_ROOT . '/templates/partials/repertoire-index.php'; ?>
|
<?php include APP_ROOT . '/templates/partials/repertoire-index.php'; ?>
|
||||||
</main>
|
</main>
|
||||||
<script src="/assets/js/htmx.min.js"></script>
|
<script src="/assets/js/htmx.min.js"></script>
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php include APP_ROOT . '/templates/footer.php'; ?>
|
<?php include APP_ROOT . '/templates/footer.php'; ?>
|
||||||
|
|||||||
82
public/search.php
Normal file
82
public/search.php
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../config/bootstrap.php';
|
||||||
|
require_once APP_ROOT . '/src/SearchController.php';
|
||||||
|
|
||||||
|
// Build controller (performs rate-limit check; exits with HTTP 429 if exceeded)
|
||||||
|
$ctrl = SearchController::create();
|
||||||
|
|
||||||
|
// Collect all view variables for the search results page
|
||||||
|
extract($ctrl->handleSearch());
|
||||||
|
?>
|
||||||
|
<?php include APP_ROOT . '/templates/head.php'; ?>
|
||||||
|
<?php include APP_ROOT . '/templates/header.php'; ?>
|
||||||
|
|
||||||
|
<?php if ($validationError): ?>
|
||||||
|
<div class="search-error">⚠ <?= htmlspecialchars($validationError) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Filter controls -->
|
||||||
|
<form class="search-controls" method="GET" action="search.php">
|
||||||
|
<input type="hidden" name="query" value="<?= htmlspecialchars($_GET['query'] ?? '') ?>">
|
||||||
|
|
||||||
|
<label class="search-filter-label" for="filter-year">Année
|
||||||
|
<select class="search-filter-select" name="year" id="filter-year">
|
||||||
|
<option value="">Toutes</option>
|
||||||
|
<?php foreach ($years as $y): ?>
|
||||||
|
<option value="<?= (int)$y ?>" <?= (isset($_GET['year']) && $_GET['year'] == $y) ? 'selected' : '' ?>>
|
||||||
|
<?= (int)$y ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="search-filter-label" for="filter-orientation">Orientation
|
||||||
|
<select class="search-filter-select" name="orientation" id="filter-orientation">
|
||||||
|
<option value="">Toutes</option>
|
||||||
|
<?php foreach ($orientations as $o): ?>
|
||||||
|
<option value="<?= htmlspecialchars($o['name']) ?>"
|
||||||
|
<?= (isset($_GET['orientation']) && $_GET['orientation'] == $o['name']) ? 'selected' : '' ?>>
|
||||||
|
<?= htmlspecialchars($o['name']) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="search-filter-label" for="filter-ap">AP
|
||||||
|
<select class="search-filter-select" name="ap_program" id="filter-ap">
|
||||||
|
<option value="">Tous</option>
|
||||||
|
<?php foreach ($apPrograms as $ap): ?>
|
||||||
|
<option value="<?= htmlspecialchars($ap['name']) ?>"
|
||||||
|
<?= (isset($_GET['ap_program']) && $_GET['ap_program'] == $ap['name']) ? 'selected' : '' ?>>
|
||||||
|
<?= htmlspecialchars($ap['name']) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button type="submit" class="search-apply-btn">Filtrer</button>
|
||||||
|
<a href="search.php?query=<?= urlencode($_GET['query'] ?? '') ?>" class="search-reset-link">Réinitialiser</a>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<main class="search-main" id="main-content">
|
||||||
|
<output class="search-results-header" role="status"><?= $totalItems ?> résultat<?= $totalItems > 1 ? 's' : '' ?></output>
|
||||||
|
|
||||||
|
<?php if (!empty($results)): ?>
|
||||||
|
<ul class="results-grid">
|
||||||
|
<?php foreach ($results as $item): ?>
|
||||||
|
<li><a href="tfe.php?id=<?= (int)$item['id'] ?>" class="result-card">
|
||||||
|
<span class="result-card__authors"><?= htmlspecialchars($item['authors'] ?? '') ?></span>
|
||||||
|
<span class="result-card__title"><?= htmlspecialchars($item['title']) ?></span>
|
||||||
|
<small class="result-card__meta"><?= htmlspecialchars($item['year']) ?><?php if (!empty($item['orientation'])): ?> · <?= htmlspecialchars($item['orientation']) ?><?php endif; ?></small>
|
||||||
|
</a></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<?php include APP_ROOT . '/templates/partials/pagination.php'; ?>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
<p class="search-empty">Aucun résultat pour cette recherche.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php include APP_ROOT . '/templates/footer.php'; ?>
|
||||||
@@ -53,7 +53,7 @@ extract($ctrl->handle());
|
|||||||
<dt>Langue :</dt>
|
<dt>Langue :</dt>
|
||||||
<dd><?php
|
<dd><?php
|
||||||
$langs = array_map('trim', explode(',', $data['languages']));
|
$langs = array_map('trim', explode(',', $data['languages']));
|
||||||
$langLinks = array_map(fn($l) => '<a href="/repertoire.php?query=' . urlencode($l) . '">' . htmlspecialchars($l) . '</a>', $langs);
|
$langLinks = array_map(fn($l) => '<a href="/search.php?query=' . urlencode($l) . '">' . htmlspecialchars($l) . '</a>', $langs);
|
||||||
echo implode(', ', $langLinks);
|
echo implode(', ', $langLinks);
|
||||||
?></dd>
|
?></dd>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +64,7 @@ extract($ctrl->handle());
|
|||||||
<dt>Format :</dt>
|
<dt>Format :</dt>
|
||||||
<dd><?php
|
<dd><?php
|
||||||
$fmts = array_map('trim', explode(',', $data['formats']));
|
$fmts = array_map('trim', explode(',', $data['formats']));
|
||||||
$fmtLinks = array_map(fn($f) => '<a href="/repertoire.php?query=' . urlencode($f) . '">' . htmlspecialchars($f) . '</a>', $fmts);
|
$fmtLinks = array_map(fn($f) => '<a href="/search.php?query=' . urlencode($f) . '">' . htmlspecialchars($f) . '</a>', $fmts);
|
||||||
echo implode(', ', $fmtLinks);
|
echo implode(', ', $fmtLinks);
|
||||||
?></dd>
|
?></dd>
|
||||||
</div>
|
</div>
|
||||||
@@ -92,7 +92,7 @@ extract($ctrl->handle());
|
|||||||
<div>
|
<div>
|
||||||
<dt>Promoteur·ice interne :</dt>
|
<dt>Promoteur·ice interne :</dt>
|
||||||
<dd><?php
|
<dd><?php
|
||||||
$links = array_map(fn($n) => '<a href="/repertoire.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $promoteursInternes);
|
$links = array_map(fn($n) => '<a href="/search.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $promoteursInternes);
|
||||||
echo implode(', ', $links);
|
echo implode(', ', $links);
|
||||||
?></dd>
|
?></dd>
|
||||||
</div>
|
</div>
|
||||||
@@ -102,7 +102,7 @@ extract($ctrl->handle());
|
|||||||
<div>
|
<div>
|
||||||
<dt>Promoteur·ice externe :</dt>
|
<dt>Promoteur·ice externe :</dt>
|
||||||
<dd><?php
|
<dd><?php
|
||||||
$links = array_map(fn($n) => '<a href="/repertoire.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $promoteursExternes);
|
$links = array_map(fn($n) => '<a href="/search.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $promoteursExternes);
|
||||||
echo implode(', ', $links);
|
echo implode(', ', $links);
|
||||||
?></dd>
|
?></dd>
|
||||||
</div>
|
</div>
|
||||||
@@ -112,7 +112,7 @@ extract($ctrl->handle());
|
|||||||
<div>
|
<div>
|
||||||
<dt>Président·e du jury :</dt>
|
<dt>Président·e du jury :</dt>
|
||||||
<dd><?php
|
<dd><?php
|
||||||
$links = array_map(fn($n) => '<a href="/repertoire.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $juryPresidents);
|
$links = array_map(fn($n) => '<a href="/search.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $juryPresidents);
|
||||||
echo implode(', ', $links);
|
echo implode(', ', $links);
|
||||||
?></dd>
|
?></dd>
|
||||||
</div>
|
</div>
|
||||||
@@ -122,7 +122,7 @@ extract($ctrl->handle());
|
|||||||
<div>
|
<div>
|
||||||
<dt>Lecteur·ices :</dt>
|
<dt>Lecteur·ices :</dt>
|
||||||
<dd><?php
|
<dd><?php
|
||||||
$links = array_map(fn($n) => '<a href="/repertoire.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $juryLecteurs);
|
$links = array_map(fn($n) => '<a href="/search.php?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>', $juryLecteurs);
|
||||||
echo implode(', ', $links);
|
echo implode(', ', $links);
|
||||||
?></dd>
|
?></dd>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
/**
|
/**
|
||||||
* SearchController
|
* SearchController
|
||||||
*
|
*
|
||||||
* Handles all data-fetching logic for the public search / répertoire page.
|
* Handles all data-fetching logic for the public search and répertoire pages.
|
||||||
* The entry point (public/repertoire.php) delegates to this class and receives
|
*
|
||||||
* a plain array of view variables ready for template inclusion.
|
* Entry points:
|
||||||
|
* - public/search.php calls handleSearch() — text-query results
|
||||||
|
* - public/repertoire.php calls handleRepertoire() — filter index + HTMX swaps
|
||||||
*
|
*
|
||||||
* Responsibilities:
|
* Responsibilities:
|
||||||
* - Rate-limit enforcement (returns early HTTP 429 response when needed)
|
* - Rate-limit enforcement (returns early HTTP 429 response when needed)
|
||||||
@@ -13,8 +15,8 @@
|
|||||||
* - OG / meta tag assembly
|
* - OG / meta tag assembly
|
||||||
* - HTMX partial response for repertoire filter swaps
|
* - HTMX partial response for repertoire filter swaps
|
||||||
*
|
*
|
||||||
* The class has NO output side-effects; all template rendering stays in
|
* The class has NO output side-effects; all template rendering stays in the
|
||||||
* public/repertoire.php so the view layer remains easy to inspect and modify.
|
* respective public/*.php files so the view layer remains easy to inspect.
|
||||||
* Exception: renderRepertoirePartial() exits early for HTMX requests.
|
* Exception: renderRepertoirePartial() exits early for HTMX requests.
|
||||||
*/
|
*/
|
||||||
class SearchController
|
class SearchController
|
||||||
@@ -59,47 +61,93 @@ class SearchController
|
|||||||
return new self(Database::getInstance(), $rateLimit);
|
return new self(Database::getInstance(), $rateLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Main entry point ─────────────────────────────────────────────────────
|
// ── Entry points ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the current request and return all variables needed by the view.
|
* Handle the search results page (public/search.php).
|
||||||
|
* Requires a ?query= parameter; always returns search-result view variables.
|
||||||
*
|
*
|
||||||
* @return array<string, mixed>
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
public function handle(): array
|
public function handleSearch(): array
|
||||||
{
|
{
|
||||||
$isHtmx = !empty($_SERVER['HTTP_HX_REQUEST']);
|
$searchParams = $this->collectSearchParams();
|
||||||
$searchParams = $this->collectSearchParams();
|
|
||||||
$hasSearch = !empty($searchParams);
|
|
||||||
|
|
||||||
$activeFilters = $this->collectFilterParams();
|
|
||||||
|
|
||||||
$page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
|
$page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
|
||||||
$offset = ($page - 1) * self::ITEMS_PER_PAGE;
|
$offset = ($page - 1) * self::ITEMS_PER_PAGE;
|
||||||
$validationError = null;
|
$validationError = null;
|
||||||
|
|
||||||
$results = [];
|
$results = [];
|
||||||
$totalItems = 0;
|
$totalItems = 0;
|
||||||
$totalPages = 0;
|
$totalPages = 0;
|
||||||
$repData = null;
|
|
||||||
|
|
||||||
// For search filter dropdowns (text search mode only)
|
|
||||||
$years = [];
|
$years = [];
|
||||||
$orientations = [];
|
$orientations = [];
|
||||||
$apPrograms = [];
|
$apPrograms = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($hasSearch) {
|
$results = $this->db->searchTheses($searchParams, self::ITEMS_PER_PAGE, $offset);
|
||||||
$results = $this->db->searchTheses($searchParams, self::ITEMS_PER_PAGE, $offset);
|
$totalItems = $this->db->countSearchResults($searchParams);
|
||||||
$totalItems = $this->db->countSearchResults($searchParams);
|
$totalPages = (int) ceil($totalItems / self::ITEMS_PER_PAGE);
|
||||||
$totalPages = (int) ceil($totalItems / self::ITEMS_PER_PAGE);
|
$years = $this->db->getAvailableYears();
|
||||||
$years = $this->db->getAvailableYears();
|
$orientations = $this->db->getAllOrientations();
|
||||||
$orientations = $this->db->getAllOrientations();
|
$apPrograms = $this->db->getAllAPPrograms();
|
||||||
$apPrograms = $this->db->getAllAPPrograms();
|
} catch (InvalidArgumentException $e) {
|
||||||
} else {
|
$validationError = $e->getMessage();
|
||||||
// Repertoire index: compute filter data (all columns + matched flags)
|
} catch (Exception $e) {
|
||||||
$repData = $this->db->getRepertoireFilterData($activeFilters);
|
error_log('SearchController: ' . $e->getMessage());
|
||||||
}
|
$validationError = 'Une erreur est survenue.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve all active params, strip 'page' (pagination partial adds it)
|
||||||
|
$baseParams = array_diff_key($_GET, ['page' => '']);
|
||||||
|
|
||||||
|
$query = $_GET['query'] ?? '';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'searchParams' => $searchParams,
|
||||||
|
'page' => $page,
|
||||||
|
'totalItems' => $totalItems,
|
||||||
|
'totalPages' => $totalPages,
|
||||||
|
'results' => $results,
|
||||||
|
'validationError' => $validationError,
|
||||||
|
'baseParams' => $baseParams,
|
||||||
|
|
||||||
|
// Filter dropdowns
|
||||||
|
'years' => $years,
|
||||||
|
'orientations' => $orientations,
|
||||||
|
'apPrograms' => $apPrograms,
|
||||||
|
|
||||||
|
// Page meta
|
||||||
|
'searchBarValue' => $query,
|
||||||
|
'pageTitle' => $query !== '' ? 'Recherche : ' . $query . ' – Posterg' : 'Recherche – Posterg',
|
||||||
|
'metaDescription' => "Résultats de recherche dans le répertoire des TFE de l'erg.",
|
||||||
|
'ogTags' => [
|
||||||
|
'type' => 'website',
|
||||||
|
'title' => 'Recherche – Posterg',
|
||||||
|
'description' => "Résultats de recherche dans le répertoire des TFE de l'erg.",
|
||||||
|
'url' => 'https://posterg.erg.be/search.php',
|
||||||
|
'site_name' => 'Posterg – ERG',
|
||||||
|
],
|
||||||
|
'currentNav' => 'repertoire',
|
||||||
|
'extraCss' => ['/assets/css/search.css'],
|
||||||
|
'bodyClass' => 'search-body',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the répertoire index page (public/repertoire.php).
|
||||||
|
* Serves the filter-column index; HTMX partial swaps are handled here too.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function handleRepertoire(): array
|
||||||
|
{
|
||||||
|
$isHtmx = !empty($_SERVER['HTTP_HX_REQUEST']);
|
||||||
|
$activeFilters = $this->collectFilterParams();
|
||||||
|
$repData = null;
|
||||||
|
$validationError = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$repData = $this->db->getRepertoireFilterData($activeFilters);
|
||||||
} catch (InvalidArgumentException $e) {
|
} catch (InvalidArgumentException $e) {
|
||||||
$validationError = $e->getMessage();
|
$validationError = $e->getMessage();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@@ -108,36 +156,18 @@ class SearchController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HTMX partial: render just the index div and exit
|
// HTMX partial: render just the index div and exit
|
||||||
if ($isHtmx && !$hasSearch && $repData !== null) {
|
if ($isHtmx && $repData !== null) {
|
||||||
$this->renderRepertoirePartial($repData, $activeFilters);
|
$this->renderRepertoirePartial($repData, $activeFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preserve all active search/filter params, strip 'page' (pagination partial adds it)
|
|
||||||
$baseParams = array_diff_key($_GET, ['page' => '']);
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
// Search state
|
|
||||||
'searchParams' => $searchParams,
|
|
||||||
'hasSearch' => $hasSearch,
|
|
||||||
'page' => $page,
|
|
||||||
'totalItems' => $totalItems,
|
|
||||||
'totalPages' => $totalPages,
|
|
||||||
'results' => $results,
|
|
||||||
'validationError' => $validationError,
|
|
||||||
'baseParams' => $baseParams,
|
|
||||||
|
|
||||||
// Repertoire filter state
|
|
||||||
'repData' => $repData,
|
'repData' => $repData,
|
||||||
'activeFilters' => $activeFilters,
|
'activeFilters' => $activeFilters,
|
||||||
'isHtmx' => $isHtmx,
|
'isHtmx' => $isHtmx,
|
||||||
|
'validationError' => $validationError,
|
||||||
// Search filter dropdowns (text search mode only)
|
|
||||||
'years' => $years,
|
|
||||||
'orientations' => $orientations,
|
|
||||||
'apPrograms' => $apPrograms,
|
|
||||||
|
|
||||||
// Page meta
|
// Page meta
|
||||||
'searchBarValue' => $_GET['query'] ?? '',
|
'searchBarValue' => '',
|
||||||
'pageTitle' => 'Répertoire – Posterg',
|
'pageTitle' => 'Répertoire – Posterg',
|
||||||
'metaDescription' => "Parcourez le répertoire des mémoires de fin d'études (TFE) de l'erg – École de Recherches Graphiques de Bruxelles.",
|
'metaDescription' => "Parcourez le répertoire des mémoires de fin d'études (TFE) de l'erg – École de Recherches Graphiques de Bruxelles.",
|
||||||
'ogTags' => [
|
'ogTags' => [
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ $_thesisId = $_GET['id'] ?? null;
|
|||||||
$searchBarValue = $searchBarValue ?? $_GET['query'] ?? '';
|
$searchBarValue = $searchBarValue ?? $_GET['query'] ?? '';
|
||||||
?>
|
?>
|
||||||
<div class="header-search-wrap">
|
<div class="header-search-wrap">
|
||||||
<form method="GET" action="/repertoire.php"
|
<form method="GET" action="/search.php"
|
||||||
role="search" aria-label="Recherche">
|
role="search" aria-label="Recherche">
|
||||||
<label for="site-search-input" class="sr-only">Recherche</label>
|
<label for="site-search-input" class="sr-only">Recherche</label>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// $searchValue: current search query (optional)
|
// $searchValue: current search query (optional)
|
||||||
$_sbValue = $searchBarValue ?? $_GET['query'] ?? '';
|
$_sbValue = $searchBarValue ?? $_GET['query'] ?? '';
|
||||||
?>
|
?>
|
||||||
<form method="GET" action="/repertoire.php"
|
<form method="GET" action="/search.php"
|
||||||
role="search" aria-label="Recherche">
|
role="search" aria-label="Recherche">
|
||||||
<label for="site-search-input" class="sr-only">Recherche</label>
|
<label for="site-search-input" class="sr-only">Recherche</label>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
|||||||
Reference in New Issue
Block a user