mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
feat: migration 038 to fix thesis identifiers mismatched with their year
This commit is contained in:
85
app/migrations/applied/038_fix_mismatched_identifiers.php
Normal file
85
app/migrations/applied/038_fix_mismatched_identifiers.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?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');
|
||||
|
||||
$dbPath = 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";
|
||||
Reference in New Issue
Block a user