mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
Extract HomeController from public/index.php
Move all data-fetching and view-variable assembly out of public/index.php into a new src/HomeController.php, following the same pattern as SearchController, TfeController, SystemController, and ThesisEditController. HomeController::create() builds the Database singleton dependency. HomeController::handle() encapsulates: - GET param parsing (page, year) with safe type coercion - Display-mode detection: default random-latest view / year-filtered / paginated-all theses - All DB calls: getLatestPublishedYear, getLatestYearTheses, searchTheses, countSearchResults, getPublishedTheses, countPublishedTheses, getCoverPathsForTheses, getAvailableYears - Batch cover-image loading for theses without a banner_path - baseParams assembly for the pagination partial - OG / meta tag array construction - Graceful error handling (logs exception, returns safe empty state) - Returns a flat array of view variables public/index.php is now a 6-line dispatcher (require + create + handle + extract) followed by a pure view template. Reduced from 100 to 71 lines. All error-handling and data logic removed from the view layer entirely.
This commit is contained in:
140
src/HomeController.php
Normal file
140
src/HomeController.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* HomeController
|
||||
*
|
||||
* Handles all data-fetching and view-variable assembly for the public home page
|
||||
* (public/index.php).
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Parse and validate GET parameters (`page`, `year`)
|
||||
* - Determine the display mode (default random-latest / year-filtered / paginated all)
|
||||
* - Run the appropriate Database queries
|
||||
* - Batch-load cover images for theses without a banner_path
|
||||
* - Assemble OG / meta tag array
|
||||
* - Return a flat array of view variables ready for template extraction
|
||||
*
|
||||
* The class has NO output side-effects; all template rendering stays in
|
||||
* public/index.php so the view layer remains easy to inspect and modify.
|
||||
*/
|
||||
class HomeController
|
||||
{
|
||||
private const ITEMS_PER_PAGE = 24;
|
||||
|
||||
private Database $db;
|
||||
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
// ── Factory ───────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Convenience factory: loads the Database singleton and returns a ready
|
||||
* controller instance.
|
||||
*/
|
||||
public static function create(): self
|
||||
{
|
||||
require_once APP_ROOT . '/src/Database.php';
|
||||
|
||||
return new self(Database::getInstance());
|
||||
}
|
||||
|
||||
// ── Main entry point ─────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Process the current request and return all variables needed by the view.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
$page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
|
||||
$year = isset($_GET['year']) ? (int) $_GET['year'] : null;
|
||||
// Normalise zero (e.g. ?year=0) to null so it is treated as "no filter"
|
||||
if ($year === 0) {
|
||||
$year = null;
|
||||
}
|
||||
|
||||
// Default home view: random theses from latest year (no year filter, no explicit page)
|
||||
$isDefaultView = ($year === null && $page === 1);
|
||||
|
||||
$itemsToLoad = [];
|
||||
$totalItems = 0;
|
||||
$availableYears = [];
|
||||
$latestYear = null;
|
||||
$coverMap = [];
|
||||
|
||||
try {
|
||||
$offset = ($page - 1) * self::ITEMS_PER_PAGE;
|
||||
$availableYears = $this->db->getAvailableYears();
|
||||
|
||||
if ($year !== null) {
|
||||
$itemsToLoad = $this->db->searchTheses(['year' => $year], self::ITEMS_PER_PAGE, $offset);
|
||||
$totalItems = $this->db->countSearchResults(['year' => $year]);
|
||||
} elseif ($isDefaultView) {
|
||||
$latestYear = $this->db->getLatestPublishedYear();
|
||||
$itemsToLoad = $this->db->getLatestYearTheses(self::ITEMS_PER_PAGE);
|
||||
$totalItems = count($itemsToLoad); // no multi-page on default view
|
||||
} else {
|
||||
$itemsToLoad = $this->db->getPublishedTheses(self::ITEMS_PER_PAGE, $offset);
|
||||
$totalItems = $this->db->countPublishedTheses();
|
||||
}
|
||||
|
||||
// Batch-load cover images for theses that have no banner_path
|
||||
if (!empty($itemsToLoad)) {
|
||||
$needCover = array_column(
|
||||
array_filter($itemsToLoad, static fn($t) => empty($t['banner_path'])),
|
||||
'id'
|
||||
);
|
||||
if (!empty($needCover)) {
|
||||
$coverMap = $this->db->getCoverPathsForTheses($needCover);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log('HomeController: ' . $e->getMessage());
|
||||
// Return safe empty state; view will show "Aucun mémoire trouvé"
|
||||
$isDefaultView = false;
|
||||
}
|
||||
|
||||
$totalPages = $isDefaultView ? 1 : (int) ceil($totalItems / self::ITEMS_PER_PAGE);
|
||||
// Avoid division by zero on empty DB
|
||||
if ($totalPages < 1) {
|
||||
$totalPages = 0;
|
||||
}
|
||||
|
||||
$baseParams = array_filter(['year' => $year]);
|
||||
|
||||
return [
|
||||
// Pagination / filter state
|
||||
'page' => $page,
|
||||
'year' => $year,
|
||||
'isDefaultView' => $isDefaultView,
|
||||
'totalItems' => $totalItems,
|
||||
'totalPages' => $totalPages,
|
||||
'baseParams' => $baseParams,
|
||||
|
||||
// Thesis data
|
||||
'itemsToLoad' => $itemsToLoad,
|
||||
'latestYear' => $latestYear,
|
||||
'availableYears' => $availableYears,
|
||||
'coverMap' => $coverMap,
|
||||
|
||||
// Page meta
|
||||
'pageTitle' => 'Posterg – Mémoires de l\'ERG',
|
||||
'metaDescription' => 'Posterg répertorie et valorise les mémoires de fin d\'études (TFE) de l\'erg – École de Recherches Graphiques de Bruxelles.',
|
||||
'ogTags' => [
|
||||
'type' => 'website',
|
||||
'title' => 'Posterg – Mémoires de l\'ERG',
|
||||
'description' => 'Posterg répertorie et valorise les mémoires de fin d\'études (TFE) de l\'erg – École de Recherches Graphiques de Bruxelles.',
|
||||
'url' => 'https://posterg.erg.be/',
|
||||
'site_name' => 'Posterg – ERG',
|
||||
],
|
||||
|
||||
// Layout
|
||||
'currentNav' => '',
|
||||
'extraCss' => ['/assets/css/main.css'],
|
||||
'bodyClass' => 'home-body',
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user