admin/index.php: add server-side pagination (25/page)

- Add Database::getThesesListCount(array $filters) — runs the same WHERE
  clauses as getThesesList() but with COUNT(DISTINCT t.id); used to compute
  total pages without loading all rows.
- Extend Database::getThesesList() with $limit/$offset parameters; when
  $limit > 0 appends LIMIT/OFFSET and re-binds positional params individually
  to avoid the PDO mixed-style restriction.
- Fix getThesesList() SELECT: add LEFT JOIN access_types + at.name as
  access_type — the column was referenced in the template but never fetched.
- Wire admin/index.php: read ?page=, compute $totalPages/$offset, pass
  $perPage=25 + $offset to getThesesList(); include pagination.php partial
  below the table with filter-preserving $baseParams.
- Add result-count line (<p class="admin-list-meta">) showing "X–Y sur Z TFE"
  when multiple pages exist.
- Add .admin-body .pagination-wrap / .pagination-btn / .pagination-info styles
  to admin.css (scoped to .admin-body to avoid colliding with public pages).
This commit is contained in:
Pontoporeia
2026-04-03 12:29:09 +02:00
parent ff8e33727d
commit 234d7bae40
6 changed files with 183 additions and 25 deletions

View File

@@ -524,14 +524,12 @@ class Database {
* @param array $filters
* @return array
*/
public function getThesesList(array $filters = []): array {
$sql = "SELECT
t.id, t.identifier, t.title, t.subtitle, t.year,
o.name as orientation,
ap.name as ap_program,
GROUP_CONCAT(DISTINCT a.name) as authors,
t.submitted_at,
t.is_published
/**
* Count theses matching the given admin filters (no LIMIT).
* Used alongside getThesesList() to calculate total pages.
*/
public function getThesesListCount(array $filters = []): int {
$sql = "SELECT COUNT(DISTINCT t.id)
FROM theses t
LEFT JOIN orientations o ON t.orientation_id = o.id
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
@@ -559,10 +557,69 @@ class Database {
$params[] = intval($filters['orientation']);
}
$sql .= " GROUP BY t.id ORDER BY t.year DESC, t.submitted_at DESC";
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return (int) $stmt->fetchColumn();
}
public function getThesesList(array $filters = [], int $limit = 0, int $offset = 0): array {
$sql = "SELECT
t.id, t.identifier, t.title, t.subtitle, t.year,
o.name as orientation,
ap.name as ap_program,
GROUP_CONCAT(DISTINCT a.name) as authors,
t.submitted_at,
t.is_published,
at.name as access_type
FROM theses t
LEFT JOIN orientations o ON t.orientation_id = o.id
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
LEFT JOIN authors a ON ta.author_id = a.id
LEFT JOIN access_types at ON t.access_type_id = at.id
WHERE 1=1";
$params = [];
if (!empty($filters['search'])) {
$sql .= " AND (t.title LIKE ? OR t.subtitle LIKE ? OR a.name LIKE ?)";
$searchParam = '%' . $filters['search'] . '%';
$params[] = $searchParam;
$params[] = $searchParam;
$params[] = $searchParam;
}
if (!empty($filters['year'])) {
$sql .= " AND t.year = ?";
$params[] = intval($filters['year']);
}
if (!empty($filters['orientation'])) {
$sql .= " AND t.orientation_id = ?";
$params[] = intval($filters['orientation']);
}
$sql .= " GROUP BY t.id ORDER BY t.year DESC, t.submitted_at DESC";
if ($limit > 0) {
$sql .= " LIMIT :limit OFFSET :offset";
}
$stmt = $this->pdo->prepare($sql);
// Bind named params only when LIMIT is used (mix of ? and : is not allowed).
if ($limit > 0) {
// Re-bind all positional params by index.
foreach ($params as $i => $val) {
$stmt->bindValue($i + 1, $val);
}
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
} else {
$stmt->execute($params);
}
return $stmt->fetchAll();
}