Files
xamxam/public/search.php
Pontoporeia 2e277b104e refactor(Database): remove dead CRUD helpers and alias proliferation
Remove 5 unused ID-lookup helpers (getOrientationId, getAPProgramId,
getFinalityId, getLanguageId, getFormatId) — forms have always passed
FK ids directly from <select> elements; these methods were never called
outside import.php, which now uses inline PDO queries instead.

Collapse 13 alias methods down to the single canonical name for each:
  getAllOrientations, getAllAPPrograms, getAllFinalityTypes,
  getAllFormatTypes, getAllLanguages, getAllLicenseTypes,
  getUsedTags, findOrCreateTag

The short-name variants (getOrientations, getApPrograms, etc.) and
compat aliases (getUsedKeywords, findOrCreateKeyword, getAllLicenseTypes
delegating to getLicenseTypes) are deleted. All call-sites updated:
  - public/search.php: getOrientations→getAllOrientations, etc.
  - public/admin/import.php: findOrCreateKeyword→findOrCreateTag,
    thesis_keywords→thesis_tags, keyword_id→tag_id (fixes stale table
    reference from pre-migration-001 that bypassed the M2M rename)
  - tests/Unit/DatabaseTest.php: remove alias smoke-test (test 7)

Database.php: 948 → 848 lines (-100).
2026-03-28 11:35:23 +01:00

257 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
require_once __DIR__ . '/../config/bootstrap.php';
require_once APP_ROOT . '/src/Database.php';
require_once APP_ROOT . '/src/RateLimit.php';
// Rate limiting
$rateLimit = new RateLimit(30, 60);
if (!$rateLimit->check()) {
http_response_code(429);
header('Retry-After: ' . $rateLimit->getResetTime());
echo '<!DOCTYPE html><html><body><h1>Trop de requêtes</h1><p>Réessayez dans ' . $rateLimit->getResetTime() . ' secondes.</p></body></html>';
exit;
}
$rateLimit->sendHeaders();
if (rand(1, 100) === 1) $rateLimit->cleanup();
// Collect search/filter params
$searchParams = [];
if (!empty($_GET['query'])) $searchParams['query'] = trim($_GET['query']);
if (!empty($_GET['year'])) $searchParams['year'] = intval($_GET['year']);
if (!empty($_GET['orientation'])) $searchParams['orientation'] = $_GET['orientation'];
if (!empty($_GET['ap_program'])) $searchParams['ap_program'] = $_GET['ap_program'];
if (!empty($_GET['keyword'])) $searchParams['keyword'] = $_GET['keyword'];
$hasSearch = !empty($searchParams);
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$itemsPerPage = 30;
$validationError = null;
try {
$db = Database::getInstance();
$offset = ($page - 1) * $itemsPerPage;
if ($hasSearch) {
$results = $db->searchTheses($searchParams, $itemsPerPage, $offset);
$totalItems = $db->countSearchResults($searchParams);
$totalPages = ceil($totalItems / $itemsPerPage);
} else {
$results = [];
$totalItems = 0;
$totalPages = 0;
}
$years = $db->getAvailableYears();
$orientations = $db->getAllOrientations();
$apPrograms = $db->getAllAPPrograms();
$keywords = $db->getUsedTags();
// Fetch all published theses for the student index (no artificial cap)
$students = $db->getAllPublishedTheses();
} catch (InvalidArgumentException $e) {
$validationError = $e->getMessage();
$results = []; $totalItems = 0; $totalPages = 0;
$years = []; $orientations = []; $apPrograms = []; $keywords = []; $students = [];
} catch (Exception $e) {
error_log("Search error: " . $e->getMessage());
$validationError = "Une erreur est survenue.";
$results = []; $totalItems = 0; $totalPages = 0;
$years = []; $orientations = []; $apPrograms = []; $keywords = []; $students = [];
}
$currentNav = 'repertoire';
$searchBarValue = $_GET['query'] ?? '';
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Répertoire Posterg</title>
<link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg">
<link rel="stylesheet" href="assets/modern-normalize.min.css">
<link rel="stylesheet" href="assets/common.css">
<link rel="stylesheet" href="assets/search.css">
<?php if (php_sapi_name() === 'cli-server'): ?>
<script>
(function poll() {
fetch('/live-reload.php').then(r=>r.json()).then(d=>{
if(d.changed) location.reload(); else setTimeout(poll,1000);
}).catch(()=>setTimeout(poll,2000));
})();
</script>
<?php endif; ?>
</head>
<body class="search-body">
<a href="#main-content" class="skip-link">Aller au contenu principal</a>
<?php include APP_ROOT . '/templates/nav.php'; ?>
<?php include APP_ROOT . '/templates/search-bar.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="search.php">
<input type="hidden" name="query" value="<?= htmlspecialchars($_GET['query'] ?? '') ?>">
<div class="search-filter-group">
<span class="search-filter-label">Année</span>
<select class="search-filter-select" name="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>
</div>
<div class="search-filter-group">
<span class="search-filter-label">Orientation</span>
<select class="search-filter-select" name="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>
</div>
<div class="search-filter-group">
<span class="search-filter-label">AP</span>
<select class="search-filter-select" name="ap_program">
<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>
</div>
<button type="submit" class="search-apply-btn">Filtrer</button>
<a href="search.php" class="search-reset-link">Réinitialiser</a>
</form>
<main class="search-main" id="main-content">
<div class="search-results-view">
<p class="search-results-header"><?= $totalItems ?> résultat<?= $totalItems > 1 ? 's' : '' ?></p>
<?php if (!empty($results)): ?>
<div class="results-grid">
<?php foreach ($results as $item): ?>
<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>
<span class="result-card__meta"><?= htmlspecialchars($item['year']) ?><?php if (!empty($item['orientation'])): ?> · <?= htmlspecialchars($item['orientation']) ?><?php endif; ?></span>
</a>
<?php endforeach; ?>
</div>
<?php if ($totalPages > 1): ?>
<div style="display:flex;gap:.5rem;justify-content:center;align-items:center;padding:1.5rem 0;">
<a href="?<?= http_build_query(array_merge($_GET, ['page' => max(1, $page - 1)])) ?>"
style="padding:.25rem .7rem;border:1px solid #ddd;border-radius:3px;color:#111;text-decoration:none;<?= $page <= 1 ? 'opacity:.3;pointer-events:none;' : '' ?>"></a>
<span style="font-size:.9rem;color:#666;"><?= $page ?> / <?= $totalPages ?></span>
<a href="?<?= http_build_query(array_merge($_GET, ['page' => min($totalPages, $page + 1)])) ?>"
style="padding:.25rem .7rem;border:1px solid #ddd;border-radius:3px;color:#111;text-decoration:none;<?= $page >= $totalPages ? 'opacity:.3;pointer-events:none;' : '' ?>"></a>
</div>
<?php endif; ?>
<?php else: ?>
<p class="search-empty">Aucun résultat pour cette recherche.</p>
<?php endif; ?>
</div>
</main>
<?php else: ?>
<!-- ── RÉPERTOIRE INDEX VIEW ─────────────────────────── -->
<main class="search-main" id="main-content">
<div class="repertoire-index">
<!-- ANNÉES -->
<div class="repertoire-col">
<h2 class="repertoire-col__header">Années</h2>
<?php foreach ($years as $y): ?>
<a href="search.php?year=<?= (int)$y ?>"
class="year-index-item <?= (isset($_GET['year']) && $_GET['year'] == $y) ? 'active' : '' ?>">
<?= (int)$y ?>
</a>
<?php endforeach; ?>
</div>
<!-- CATÉGORIES -->
<div class="repertoire-col">
<h2 class="repertoire-col__header">Catégories</h2>
<?php if (!empty($orientations)): ?>
<span class="cat-index-label">Orientation</span>
<?php foreach ($orientations as $o): ?>
<a href="search.php?orientation=<?= urlencode($o['name']) ?>"
class="cat-index-item <?= (isset($_GET['orientation']) && $_GET['orientation'] == $o['name']) ? 'active' : '' ?>">
<?= htmlspecialchars($o['name']) ?>
</a>
<?php endforeach; ?>
<?php endif; ?>
<?php if (!empty($apPrograms)): ?>
<span class="cat-index-label">Ateliers Pluridisciplinaires</span>
<?php foreach ($apPrograms as $ap): ?>
<a href="search.php?ap_program=<?= urlencode($ap['name']) ?>"
class="cat-index-item <?= (isset($_GET['ap_program']) && $_GET['ap_program'] == $ap['name']) ? 'active' : '' ?>">
<?= htmlspecialchars($ap['name']) ?>
</a>
<?php endforeach; ?>
<?php endif; ?>
</div>
<!-- ÉTUDIANTES -->
<div class="repertoire-col">
<h2 class="repertoire-col__header">Étudiantes</h2>
<?php
// Build unique author → thesis list
$authorMap = [];
foreach ($students as $s) {
if (empty($s['authors'])) continue;
$names = explode(',', $s['authors']);
foreach ($names as $name) {
$name = trim($name);
if ($name && !isset($authorMap[$name])) {
$authorMap[$name] = $s['id'];
}
}
}
ksort($authorMap);
foreach ($authorMap as $name => $id): ?>
<a href="tfe.php?id=<?= (int)$id ?>" class="student-index-item">
<?= htmlspecialchars($name) ?>
</a>
<?php endforeach; ?>
</div>
<!-- MOTS-CLÉS -->
<div class="repertoire-col">
<h2 class="repertoire-col__header">Mots-clés</h2>
<?php foreach ($keywords as $kw): ?>
<a href="search.php?keyword=<?= urlencode($kw['name']) ?>"
class="keyword-index-item <?= (isset($_GET['keyword']) && $_GET['keyword'] == $kw['name']) ? 'active' : '' ?>">
<?= htmlspecialchars($kw['name']) ?>
</a>
<?php endforeach; ?>
</div>
</div>
</main>
<?php endif; ?>
</body>
</html>