mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
ThesisEditController::save() previously only regenerated the identifier when the year field changed during an edit. If a thesis had its year corrected in a past edit (or via other means) and the identifier still carried the old year prefix, subsequent edits that didn't touch the year field would leave the mismatched identifier in place. Now saves() also checks whether the existing identifier's 4-digit prefix matches the thesis year, and regenerates if not — regardless of whether year changed in the current edit. The migration runner (run.php) only scanned for .sql files, so PHP migrations (013, 016, 018, 038) were never auto-applied. Extended the runner to also discover and execute .php migrations in a subprocess. If a PHP migration fails with an idempotent error (no such column, already exists, duplicate column), the runner treats it as already-applied and continues rather than aborting — preventing a stale migration like 016 (banner_path already dropped by 028) from blocking migrations that come after it alphabetically (e.g. 038). Updated migrations 016 and 038 to accept an optional $argv[1] DB path. Fixed 016 to gracefully handle the banner_path column already being gone (exit 0 instead of fatal).
87 lines
3.0 KiB
PHP
87 lines
3.0 KiB
PHP
<?php
|
|
/**
|
|
* Migration 038 — fix thesis identifiers that don't match their year.
|
|
*
|
|
* Some entries have identifiers like "2024-026" with year=2025 (or vice-versa),
|
|
* typically because the year was corrected after initial creation. When editing
|
|
* a thesis and changing its year, the identifier is now auto-regenerated via
|
|
* ThesisEditController::save(), but pre-existing wrong identifiers need a
|
|
* one-off fix.
|
|
*
|
|
* Logic: for each thesis whose identifier year-prefix does NOT match its `year`
|
|
* column, assign a new identifier <year>-<NNN> using the next available sequence
|
|
* number for that year. Entries are ordered by id within each year so the
|
|
* numbering is deterministic and roughly chronological.
|
|
*
|
|
* Safe to re-run: only updates identifiers that are already mismatched.
|
|
*/
|
|
|
|
defined('APP_ROOT') || define('APP_ROOT', dirname(__DIR__, 2));
|
|
defined('STORAGE_ROOT') || define('STORAGE_ROOT', APP_ROOT . '/storage');
|
|
|
|
// Accept optional DB path from command line (used by run.php runner)
|
|
$dbPath = $argv[1] ?? (APP_ROOT . '/storage/xamxam.db');
|
|
if (!file_exists($dbPath)) {
|
|
echo "ERROR: database not found at $dbPath\n";
|
|
exit(1);
|
|
}
|
|
|
|
$pdo = new PDO('sqlite:' . $dbPath);
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
|
$pdo->exec('PRAGMA foreign_keys = ON');
|
|
|
|
// ── 1. Identify mismatched rows ──────────────────────────────────────────
|
|
$stmt = $pdo->query(
|
|
"SELECT id, year, identifier
|
|
FROM theses
|
|
WHERE deleted_at IS NULL
|
|
AND CAST(SUBSTR(identifier, 1, 4) AS INTEGER) != year"
|
|
);
|
|
$mismatched = $stmt->fetchAll();
|
|
|
|
if (empty($mismatched)) {
|
|
echo "No mismatched identifiers found. Nothing to fix.\n";
|
|
exit(0);
|
|
}
|
|
|
|
echo "Found " . count($mismatched) . " thesis(es) with mismatched identifiers.\n";
|
|
|
|
// Group by year, ordered by id within each year (deterministic renumbering)
|
|
$byYear = [];
|
|
foreach ($mismatched as $row) {
|
|
$year = (int)$row['year'];
|
|
$byYear[$year][] = $row;
|
|
}
|
|
|
|
$fixed = 0;
|
|
foreach ($byYear as $year => $rows) {
|
|
// Sort by id for deterministic sequencing
|
|
usort($rows, fn($a, $b) => (int)$a['id'] <=> (int)$b['id']);
|
|
|
|
// Find the max existing sequence for CORRECT identifiers of this year
|
|
$stmt = $pdo->prepare(
|
|
"SELECT COALESCE(MAX(CAST(SUBSTR(identifier, 6) AS INTEGER)), 0)
|
|
FROM theses
|
|
WHERE year = ?
|
|
AND deleted_at IS NULL
|
|
AND CAST(SUBSTR(identifier, 1, 4) AS INTEGER) = ?"
|
|
);
|
|
$stmt->execute([$year, $year]);
|
|
$maxSeq = (int)$stmt->fetchColumn();
|
|
|
|
foreach ($rows as $row) {
|
|
$maxSeq++;
|
|
$newIdentifier = sprintf('%d-%03d', $year, $maxSeq);
|
|
|
|
echo " Thesis {$row['id']}: {$row['identifier']} → {$newIdentifier} (year={$year})\n";
|
|
|
|
$pdo->prepare("UPDATE theses SET identifier = ? WHERE id = ?")
|
|
->execute([$newIdentifier, $row['id']]);
|
|
$fixed++;
|
|
}
|
|
}
|
|
|
|
echo "\nFixed $fixed identifier(s).\n";
|
|
echo "Migration 038 complete.\n";
|