altre migrations sistemate

This commit is contained in:
Mariano
2026-06-17 19:35:20 +02:00
parent 92ba47e99f
commit 3b2ad1a0d5
9 changed files with 90 additions and 79 deletions
+24
View File
@@ -578,3 +578,27 @@ if (!empty($contatto['individuo_id'])) { create }
- Test IMAP OAuth: sync email via connessione OAuth - Test IMAP OAuth: sync email via connessione OAuth
- Verificare refresh token automatico allo scadere - Verificare refresh token automatico allo scadere
- Verificare revoca e riconnessione - Verificare revoca e riconnessione
## 2026-06-17 — Fix: tutte le migration + seeders idempotenti
### Problema
`php artisan migrate` falliva su tabelle già esistenti (`tenants`, `tipologie_documenti`, ecc.).
`php artisan db:seed` creava duplicati su re-run (admin user, diocesi, comuni).
Migrations con `insert` dopo il guard `hasTable` violavano unique constraint al re-run.
### Migration: hasTable guard su 28 CREATE mancanti
Aggiunto `if (!Schema::hasTable('table_name')) { ... }` wrapper a 28 migration file (45 `Schema::create()` calls) via script Node.js, più `2026_06_17_000001_create_google_oauth_connections_table.php` manualmente.
### Fix: insert fuori dai guard (4 file)
- `2026_05_10_000001_create_tipologie_documenti_table.php` — spostato insert dentro l'if
- `2026_05_26_000001_create_tipologie_eventi_table.php` — spostato insert dentro l'if
- `2026_05_12_000001_create_ruoli_table.php` — spostato insert dentro l'if
- `2026_05_11_000006_add_email_attachment_tipologia.php``insert()``updateOrInsert()`
### Seeder: firstOrCreate
- `DiocesiSeeder.php`: `Diocesi::create()``::firstOrCreate(['nome' => ...])`
- `ComuniSeeder.php`: `Comune::create()``::firstOrCreate(['codice_istat' => ...])`
- `DatabaseSeeder.php`: `User::create()``::firstOrCreate(['email' => ...])` + guardia `role_preset_id`
### Risultato
`php artisan migrate --seed` è ora completamente idempotente. Zero errori su 64 migration + 6 seeder. Re-run è un no-op.
@@ -17,18 +17,18 @@ return new class extends Migration
$table->boolean('attiva')->default(true); $table->boolean('attiva')->default(true);
$table->timestamps(); $table->timestamps();
}); });
}
$defaultTipologie = ['avatar', 'galleria', 'documento', 'statuto', 'altro']; $defaultTipologie = ['avatar', 'galleria', 'documento', 'statuto', 'altro'];
foreach ($defaultTipologie as $i => $nome) { foreach ($defaultTipologie as $i => $nome) {
DB::table('tipologie_documenti')->insert([ DB::table('tipologie_documenti')->insert([
'nome' => $nome, 'nome' => $nome,
'descrizione' => ucfirst($nome), 'descrizione' => ucfirst($nome),
'ordine' => $i, 'ordine' => $i,
'attiva' => true, 'attiva' => true,
'created_at' => now(), 'created_at' => now(),
'updated_at' => now(), 'updated_at' => now(),
]); ]);
}
} }
} }
@@ -7,14 +7,15 @@ return new class extends Migration
{ {
public function up(): void public function up(): void
{ {
DB::table('tipologie_documenti')->insert([ DB::table('tipologie_documenti')->updateOrInsert(
'nome' => 'email_attachment', ['nome' => 'email_attachment'],
'descrizione' => 'Allegato email', [
'ordine' => 100, 'descrizione' => 'Allegato email',
'attiva' => true, 'ordine' => 100,
'created_at' => now(), 'attiva' => true,
'updated_at' => now(), 'updated_at' => now(),
]); ]
);
} }
public function down(): void public function down(): void
@@ -17,27 +17,27 @@ return new class extends Migration
$table->boolean('attiva')->default(true); $table->boolean('attiva')->default(true);
$table->timestamps(); $table->timestamps();
}); });
}
$defaultRuoli = [ $defaultRuoli = [
['nome' => 'Membro', 'descrizione' => 'Membro del gruppo'], ['nome' => 'Membro', 'descrizione' => 'Membro del gruppo'],
['nome' => 'Catechista', 'descrizione' => 'Catechista del gruppo'], ['nome' => 'Catechista', 'descrizione' => 'Catechista del gruppo'],
['nome' => 'Animatore', 'descrizione' => 'Animatore del gruppo'], ['nome' => 'Animatore', 'descrizione' => 'Animatore del gruppo'],
['nome' => 'Responsabile', 'descrizione' => 'Responsabile del gruppo'], ['nome' => 'Responsabile', 'descrizione' => 'Responsabile del gruppo'],
['nome' => 'Vice Responsabile', 'descrizione' => 'Vice responsabile del gruppo'], ['nome' => 'Vice Responsabile', 'descrizione' => 'Vice responsabile del gruppo'],
['nome' => 'Segretario', 'descrizione' => 'Segretario del gruppo'], ['nome' => 'Segretario', 'descrizione' => 'Segretario del gruppo'],
['nome' => 'Tesoriere', 'descrizione' => 'Tesoriere del gruppo'], ['nome' => 'Tesoriere', 'descrizione' => 'Tesoriere del gruppo'],
]; ];
foreach ($defaultRuoli as $i => $ruolo) { foreach ($defaultRuoli as $i => $ruolo) {
DB::table('ruoli')->insert([ DB::table('ruoli')->insert([
'nome' => $ruolo['nome'], 'nome' => $ruolo['nome'],
'descrizione' => $ruolo['descrizione'], 'descrizione' => $ruolo['descrizione'],
'ordine' => $i, 'ordine' => $i,
'attiva' => true, 'attiva' => true,
'created_at' => now(), 'created_at' => now(),
'updated_at' => now(), 'updated_at' => now(),
]); ]);
}
} }
if (!Schema::hasColumn('gruppo_individuo', 'ruolo_id')) { if (!Schema::hasColumn('gruppo_individuo', 'ruolo_id')) {
@@ -19,18 +19,18 @@ return new class extends Migration
$table->boolean('attiva')->default(true); $table->boolean('attiva')->default(true);
$table->timestamps(); $table->timestamps();
}); });
}
DB::table('tipologie_eventi')->insert([ DB::table('tipologie_eventi')->insert([
['nome' => 'catechesi', 'descrizione' => 'Catechesi', 'ordine' => 0, 'attiva' => true], ['nome' => 'catechesi', 'descrizione' => 'Catechesi', 'ordine' => 0, 'attiva' => true],
['nome' => 'liturgia', 'descrizione' => 'Liturgia', 'ordine' => 1, 'attiva' => true], ['nome' => 'liturgia', 'descrizione' => 'Liturgia', 'ordine' => 1, 'attiva' => true],
['nome' => 'animazione', 'descrizione' => 'Animazione', 'ordine' => 2, 'attiva' => true], ['nome' => 'animazione', 'descrizione' => 'Animazione', 'ordine' => 2, 'attiva' => true],
['nome' => 'formazione', 'descrizione' => 'Formazione', 'ordine' => 3, 'attiva' => true], ['nome' => 'formazione', 'descrizione' => 'Formazione', 'ordine' => 3, 'attiva' => true],
['nome' => 'incontro', 'descrizione' => 'Incontro', 'ordine' => 4, 'attiva' => true], ['nome' => 'incontro', 'descrizione' => 'Incontro', 'ordine' => 4, 'attiva' => true],
['nome' => 'riunione', 'descrizione' => 'Riunione', 'ordine' => 5, 'attiva' => true], ['nome' => 'riunione', 'descrizione' => 'Riunione', 'ordine' => 5, 'attiva' => true],
['nome' => 'festa', 'descrizione' => 'Festa / Sagra', 'ordine' => 6, 'attiva' => true], ['nome' => 'festa', 'descrizione' => 'Festa / Sagra', 'ordine' => 6, 'attiva' => true],
['nome' => 'altro', 'descrizione' => 'Altro', 'ordine' => 7, 'attiva' => true], ['nome' => 'altro', 'descrizione' => 'Altro', 'ordine' => 7, 'attiva' => true],
]); ]);
}
} }
public function down(): void public function down(): void
@@ -10,6 +10,10 @@ return new class extends Migration
{ {
public function up(): void public function up(): void
{ {
if (Schema::hasTable('google_oauth_connections')) {
return;
}
Schema::create('google_oauth_connections', function (Blueprint $table) { Schema::create('google_oauth_connections', function (Blueprint $table) {
$table->id(); $table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete(); $table->foreignId('user_id')->constrained()->cascadeOnDelete();
+4 -1
View File
@@ -14,7 +14,10 @@ if (PHP_VERSION_ID < 50600) {
echo $err; echo $err;
} }
} }
throw new RuntimeException($err); trigger_error(
$err,
E_USER_ERROR
);
} }
require_once __DIR__ . '/composer/autoload_real.php'; require_once __DIR__ . '/composer/autoload_real.php';
+4 -25
View File
@@ -26,12 +26,6 @@ use Composer\Semver\VersionParser;
*/ */
class InstalledVersions class InstalledVersions
{ {
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/** /**
* @var mixed[]|null * @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
@@ -317,18 +311,6 @@ class InstalledVersions
self::$installedByVendor = array(); self::$installedByVendor = array();
} }
/**
* @return string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/** /**
* @return array[] * @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
@@ -340,7 +322,6 @@ class InstalledVersions
} }
$installed = array(); $installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) { if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
@@ -349,11 +330,9 @@ class InstalledVersions
} elseif (is_file($vendorDir.'/composer/installed.php')) { } elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php'; $required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required; $installed[] = self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1];
self::$installed = $required;
$copiedLocalDir = true;
} }
} }
} }
@@ -371,7 +350,7 @@ class InstalledVersions
} }
} }
if (self::$installed !== array() && !$copiedLocalDir) { if (self::$installed !== array()) {
$installed[] = self::$installed; $installed[] = self::$installed;
} }
+4 -4
View File
@@ -3,7 +3,7 @@
'name' => 'laravel/laravel', 'name' => 'laravel/laravel',
'pretty_version' => 'dev-main', 'pretty_version' => 'dev-main',
'version' => 'dev-main', 'version' => 'dev-main',
'reference' => '6909e21b677ae5b7bfe8d8ef3f31b61982b5436e', 'reference' => '92ba47e99f4839d49d5f002915c30a88bb842c6a',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
@@ -427,7 +427,7 @@
'laravel/laravel' => array( 'laravel/laravel' => array(
'pretty_version' => 'dev-main', 'pretty_version' => 'dev-main',
'version' => 'dev-main', 'version' => 'dev-main',
'reference' => '6909e21b677ae5b7bfe8d8ef3f31b61982b5436e', 'reference' => '92ba47e99f4839d49d5f002915c30a88bb842c6a',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
@@ -732,8 +732,8 @@
'dev_requirement' => false, 'dev_requirement' => false,
'provided' => array( 'provided' => array(
0 => '1.0 || 2.0 || 3.0', 0 => '1.0 || 2.0 || 3.0',
1 => '1.0|2.0|3.0', 1 => '3.0.0',
2 => '3.0.0', 2 => '1.0|2.0|3.0',
), ),
), ),
'psr/simple-cache' => array( 'psr/simple-cache' => array(