fix(migrations): load composer autoloader so run.php works on a fresh DB

run.php never loaded vendor/autoload.php. SQL migrations were fine, but PHP
migrations run as isolated subprocesses that require src/ files directly, and
those files reference sibling classes (e.g. Database -> DatabaseMigrations)
resolvable only via composer's classmap. On a fresh schema.sql database the run
died at 013_fix_remarks_keywords.php with:

  Class "DatabaseMigrations" not found in app/src/Database.php:89

- run.php now resolves and requires the autoloader (vendor/ is a sibling dir in
  dev, same-dir in prod, matching app/bootstrap.php).
- Subprocess PHP migrations get it injected via -d auto_prepend_file so each
  migration's own contract is untouched ($argv[1] stays the DB path).

Verified: fresh schema.sql DB applies 47 migrations, exit 0; second run is a
no-op (0 applied).
This commit is contained in:
Pontoporeia
2026-09-18 16:26:49 +02:00
parent 82d678c7b0
commit 3ab03e2c7a
2 changed files with 39 additions and 4 deletions
+38 -2
View File
@@ -14,6 +14,33 @@
$root = dirname(__DIR__);
$dbPath = $argv[1] ?? ($root . '/storage/xamxam.db');
// Load the composer autoloader (classmap over src/). PHP migrations require
// src/ files directly, and those files reference sibling classes
// (e.g. Database -> DatabaseMigrations) that are only resolvable via the
// autoloader. Without this, run.php dies on a fresh database.
// vendor/ is a sibling dir in dev (repo root) and same-dir in prod.
$autoloadCandidates = [
dirname($root) . '/vendor/autoload.php',
$root . '/vendor/autoload.php',
];
$autoloadPath = null;
foreach ($autoloadCandidates as $candidate) {
if (file_exists($candidate)) {
$autoloadPath = $candidate;
require_once $candidate;
break;
}
}
// PHP migrations run as isolated subprocesses, so they do not inherit the
// autoloader above. Export the resolved path so run.php (and any code it
// invokes) can inject it into those subprocesses.
if ($autoloadPath !== null) {
putenv('XAMXAM_AUTOLOAD=' . $autoloadPath);
$_ENV['XAMXAM_AUTOLOAD'] = $autoloadPath;
$_SERVER['XAMXAM_AUTOLOAD'] = $autoloadPath;
}
if (!file_exists($dbPath)) {
die("Database not found: $dbPath\n");
}
@@ -68,9 +95,18 @@ foreach ($files as $name => $file) {
try {
if ($isPhp) {
// PHP migrations: execute in a subprocess for isolation
// PHP migrations: execute in a subprocess for isolation.
// The subprocess only requires the migration file, so composer's
// autoloader has to be loaded there too. -d auto_prepend_file
// injects it without altering the migration's own $argv contract
// ($argv[1] must remain the DB path).
$phpArgs = '';
if ($autoloadPath !== null) {
$phpArgs = '-d auto_prepend_file=' . escapeshellarg($autoloadPath) . ' ';
}
$cmd = sprintf(
'php %s %s 2>&1',
'php %s%s %s 2>&1',
$phpArgs,
escapeshellarg($file),
escapeshellarg($dbPath)
);