Files
xamxam/public/search.php

357 lines
16 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
// Bootstrap application
require_once __DIR__ . '/../config/bootstrap.php';
require_once APP_ROOT . '/src/Database.php';
require_once APP_ROOT . '/src/RateLimit.php';
// Rate limiting: 30 requests per minute
$rateLimit = new RateLimit(30, 60);
// Check rate limit
if (!$rateLimit->check()) {
http_response_code(429);
header('Retry-After: ' . $rateLimit->getResetTime());
$rateLimit->sendHeaders();
// Simple error page
echo '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Rate Limit</title></head><body>';
echo '<h1>Trop de requêtes</h1>';
echo '<p>Vous avez dépassé la limite de 30 recherches par minute. Veuillez réessayer dans ' . $rateLimit->getResetTime() . ' secondes.</p>';
echo '</body></html>';
exit;
}
$rateLimit->sendHeaders();
if (rand(1, 100) === 1) {
$rateLimit->cleanup();
}
// Pagination - adjust to grid
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$itemsPerPage = 9; // Default grid size (3 rows × 3 columns)
// Collect search parameters
$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['finality'])) {
$searchParams['finality'] = $_GET['finality'];
}
if (!empty($_GET['keyword'])) {
$searchParams['keyword'] = $_GET['keyword'];
}
if (!empty($_GET['format'])) {
$searchParams['format'] = $_GET['format'];
}
if (!empty($_GET['language'])) {
$searchParams['language'] = $_GET['language'];
}
if (isset($_GET['is_doctoral'])) {
$searchParams['is_doctoral'] = $_GET['is_doctoral'] === '1';
}
$validationError = null;
$showFilters = isset($_GET['filters']) && $_GET['filters'] === 'show';
try {
$db = Database::getInstance();
// Get search results
$offset = ($page - 1) * $itemsPerPage;
$results = $db->searchTheses($searchParams, $itemsPerPage, $offset);
$totalItems = $db->countSearchResults($searchParams);
$totalPages = ceil($totalItems / $itemsPerPage);
// Get filter options
$years = $db->getAvailableYears();
$orientations = $db->getOrientations();
$apPrograms = $db->getApPrograms();
$finalityTypes = $db->getFinalityTypes();
$keywords = $db->getUsedKeywords();
$formats = $db->getFormatTypes();
$languages = $db->getLanguages();
} catch (InvalidArgumentException $e) {
error_log("Search validation error: " . $e->getMessage());
$validationError = $e->getMessage();
$results = [];
$totalPages = 0;
$totalItems = 0;
$years = [];
$orientations = [];
$apPrograms = [];
$finalityTypes = [];
$keywords = [];
$formats = [];
$languages = [];
} catch (Exception $e) {
error_log("Error in search: " . $e->getMessage());
$validationError = "Une erreur est survenue lors de la recherche.";
$results = [];
$totalPages = 0;
$totalItems = 0;
$years = [];
$orientations = [];
$apPrograms = [];
$finalityTypes = [];
$keywords = [];
$formats = [];
$languages = [];
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Recherche - Posterg</title>
<link rel="stylesheet" href="assets/modern-normalize.min.css">
<link rel="stylesheet" href="assets/common.css">
<link rel="stylesheet" href="assets/search.css">
</head>
<body>
<header>
<div class="search-header">
<a href="index.php" class="back-button">← Retour</a>
<form method="GET" action="search.php" class="search-form">
<input
type="text"
name="query"
class="search-input"
placeholder="Rechercher..."
value="<?= htmlspecialchars($_GET['query'] ?? ''); ?>"
autofocus
>
<div class="search-actions">
<button type="submit" class="search-button">Rechercher</button>
<button type="button" class="filter-button <?= $showFilters ? 'active' : ''; ?>" onclick="toggleFilters()">
Filtres
</button>
</div>
<!-- Hidden field to maintain filter panel state -->
<input type="hidden" name="filters" id="filters-state" value="<?= $showFilters ? 'show' : 'hide'; ?>">
<!-- Preserve other filter values as hidden fields when searching -->
<?php foreach (['year', 'orientation', 'ap_program', 'finality', 'keyword', 'format', 'language', 'is_doctoral'] as $field): ?>
<?php if (!empty($_GET[$field])): ?>
<input type="hidden" name="<?= $field; ?>" value="<?= htmlspecialchars($_GET[$field]); ?>">
<?php endif; ?>
<?php endforeach; ?>
</form>
</div>
<?php if ($validationError): ?>
<div class="error-message">
⚠ <?= htmlspecialchars($validationError); ?>
</div>
<?php endif; ?>
<div class="filters-panel <?= $showFilters ? 'show' : ''; ?>" id="filters-panel">
<form method="GET" action="search.php">
<!-- Preserve query when using filters -->
<?php if (!empty($_GET['query'])): ?>
<input type="hidden" name="query" value="<?= htmlspecialchars($_GET['query']); ?>">
<?php endif; ?>
<input type="hidden" name="filters" value="show">
<div class="filters-grid">
<div class="filter-group">
<label class="filter-label">Année</label>
<select name="year" class="filter-select">
<option value="">Toutes</option>
<?php foreach ($years as $year): ?>
<option value="<?= (int)$year; ?>" <?= (isset($_GET['year']) && $_GET['year'] == $year) ? 'selected' : ''; ?>>
<?= (int)$year; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="filter-group">
<label class="filter-label">Orientation</label>
<select name="orientation" class="filter-select">
<option value="">Toutes</option>
<?php foreach ($orientations as $orientation): ?>
<option value="<?= htmlspecialchars($orientation['name']); ?>"
<?= (isset($_GET['orientation']) && $_GET['orientation'] == $orientation['name']) ? 'selected' : ''; ?>>
<?= htmlspecialchars($orientation['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="filter-group">
<label class="filter-label">AP</label>
<select name="ap_program" class="filter-select">
<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>
<div class="filter-group">
<label class="filter-label">Finalité</label>
<select name="finality" class="filter-select">
<option value="">Toutes</option>
<?php foreach ($finalityTypes as $finality): ?>
<option value="<?= htmlspecialchars($finality['name']); ?>"
<?= (isset($_GET['finality']) && $_GET['finality'] == $finality['name']) ? 'selected' : ''; ?>>
<?= htmlspecialchars($finality['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="filter-group">
<label class="filter-label">Format</label>
<select name="format" class="filter-select">
<option value="">Tous</option>
<?php foreach ($formats as $format): ?>
<option value="<?= htmlspecialchars($format['name']); ?>"
<?= (isset($_GET['format']) && $_GET['format'] == $format['name']) ? 'selected' : ''; ?>>
<?= htmlspecialchars($format['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="filter-group">
<label class="filter-label">Langue</label>
<select name="language" class="filter-select">
<option value="">Toutes</option>
<?php foreach ($languages as $language): ?>
<option value="<?= htmlspecialchars($language['name']); ?>"
<?= (isset($_GET['language']) && $_GET['language'] == $language['name']) ? 'selected' : ''; ?>>
<?= htmlspecialchars($language['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="filter-group">
<label class="filter-label">Mot-clé</label>
<select name="keyword" class="filter-select">
<option value="">Tous</option>
<?php foreach ($keywords as $keyword): ?>
<option value="<?= htmlspecialchars($keyword['keyword']); ?>"
<?= (isset($_GET['keyword']) && $_GET['keyword'] == $keyword['keyword']) ? 'selected' : ''; ?>>
<?= htmlspecialchars($keyword['keyword']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="filter-group">
<label class="filter-label">Type</label>
<select name="is_doctoral" class="filter-select">
<option value="">Tous</option>
<option value="0" <?= (isset($_GET['is_doctoral']) && $_GET['is_doctoral'] == '0') ? 'selected' : ''; ?>>
TFE uniquement
</option>
<option value="1" <?= (isset($_GET['is_doctoral']) && $_GET['is_doctoral'] == '1') ? 'selected' : ''; ?>>
Thèses doctorales
</option>
</select>
</div>
</div>
<div class="filter-actions">
<button type="submit" class="search-button">Appliquer</button>
<a href="search.php?filters=show" class="reset-button">Réinitialiser</a>
</div>
</form>
</div>
</header>
<div class="main-wrapper">
<main>
<div class="cards-container">
<?php if (count($results) > 0): ?>
<?php foreach ($results as $item): ?>
<a href="tfe.php?id=<?= (int)$item['id']; ?>" class="card-link">
<div class="card">
<div class="card-content">
<h3 class="title"><?= htmlspecialchars($item['title']); ?></h3>
<p class="authors"><?= htmlspecialchars($item['authors'] ?? 'Auteur inconnu'); ?></p>
<p class="year"><?= htmlspecialchars($item['year']); ?></p>
<?php if (!empty($item['orientation'])): ?>
<div class="tags">
<span class="tag"><?= htmlspecialchars($item['orientation']); ?></span>
</div>
<?php endif; ?>
</div>
</div>
</a>
<?php endforeach; ?>
<?php elseif (!empty($searchParams)): ?>
<div style="grid-column: 1 / -1; display: flex; align-items: center; justify-content: center; color: white; font-size: 1.2rem;">
Aucun résultat trouvé pour cette recherche.
</div>
<?php else: ?>
<div style="grid-column: 1 / -1; display: flex; align-items: center; justify-content: center; color: white; font-size: 1.2rem;">
Utilisez la barre de recherche pour trouver des mémoires.
</div>
<?php endif; ?>
</div>
<?php if ($totalPages > 1): ?>
<div class="pagination">
<a href="?<?= http_build_query(array_merge($_GET, ['page' => max(1, $page - 1)])); ?>"
class="pagination-btn <?= $page <= 1 ? 'disabled' : ''; ?>">
</a>
<div class="pagination-info">
<span class="page-current"><?= $page; ?></span>
<span class="page-separator">/</span>
<span class="page-total"><?= $totalPages; ?></span>
</div>
<a href="?<?= http_build_query(array_merge($_GET, ['page' => min($totalPages, $page + 1)])); ?>"
class="pagination-btn <?= $page >= $totalPages ? 'disabled' : ''; ?>">
</a>
</div>
<?php endif; ?>
</main>
<footer>
<div class="results-footer">
<span class="results-count"><?= (int)$totalItems; ?></span>
<span>résultat<?= $totalItems > 1 ? 's' : ''; ?></span>
</div>
</footer>
</div>
<script>
function toggleFilters() {
const panel = document.getElementById('filters-panel');
const button = document.querySelector('.filter-button');
const state = document.getElementById('filters-state');
panel.classList.toggle('show');
button.classList.toggle('active');
// Update hidden field
state.value = panel.classList.contains('show') ? 'show' : 'hide';
}
</script>
</body>
</html>