fix(form-builder): restore FK on form_schemas.default_crowd_type_id (WS-6)
The original session 2.5 migration had to omit this FK due to an SQLite-only "rebuild on FK add" cascade-delete quirk. Now that the test infrastructure has moved to MySQL (Task 1 of this session), the quirk does not apply and the FK is restored to match every other FK in this table. Changes: - New migration `2026_04_28_100000_restore_default_crowd_type_id_foreign_key` adds a FOREIGN KEY (default_crowd_type_id) REFERENCES crowd_types(id) ON DELETE SET NULL. Deleting a CrowdType nulls the column on dependent schemas instead of cascading the schema delete. - Original migration's comment block rewritten — the SQLite-quirk rationale was demonstrably misleading; replaced with a forward-looking pointer to the FK-restore migration. - PersonProvisioner::resolveCrowdTypeId() docblock updated: the runtime failsafe is now defense in depth alongside the DB-level FK + publish guard, not the sole load-bearing check. New test (`DefaultCrowdTypeForeignKeyTest`) exercises both the ON-DELETE-SET-NULL cascade and the existence of the FK in information_schema.REFERENTIAL_CONSTRAINTS — the second assertion would have been impossible on SQLite, which is exactly the point. Migration step counts in 5 backfill tests bumped +1 because the FK- restore migration sits at the top of the migration stack: - FormFieldBindingMigrationTest: 17→18, 15→16 - ConditionalLogicBackfillTest: 6→7 - FormFieldConfigBackfillAndDropTest: 12→13 - FormFieldOptionsBackfillTest: 2→3 - FormFieldValidationRuleBackfillTest: 15→16 All 1388 tests pass on MySQL (1386 prior + 2 new FK tests). Larastan baseline unchanged. Refs: RFC-WS-6.md v1.1 §3 Q9 addendum, WS-6 session 2.5 deviation #1 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature\FormBuilder\Schema;
|
||||
|
||||
use App\Models\CrowdType;
|
||||
use App\Models\FormBuilder\FormSchema;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* RFC-WS-6.md v1.1 §3 Q9 addendum — the FK on
|
||||
* form_schemas.default_crowd_type_id is restored once the test
|
||||
* infrastructure moved off SQLite (session 2.6). Asserts both the
|
||||
* DB-level constraint exists AND the nullOnDelete cascade behaviour
|
||||
* holds, so a future migration that quietly drops the FK is caught
|
||||
* here, not in production.
|
||||
*/
|
||||
final class DefaultCrowdTypeForeignKeyTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_deleting_crowd_type_nulls_default_on_form_schemas(): void
|
||||
{
|
||||
$crowdType = CrowdType::factory()->create();
|
||||
$schema = FormSchema::factory()->create([
|
||||
'organisation_id' => $crowdType->organisation_id,
|
||||
'default_crowd_type_id' => $crowdType->id,
|
||||
]);
|
||||
|
||||
$this->assertSame($crowdType->id, $schema->fresh()->default_crowd_type_id);
|
||||
|
||||
// Force-delete bypasses the SoftDeletes trait — only the
|
||||
// DB-level FK can null the column on form_schemas.
|
||||
$crowdType->forceDelete();
|
||||
|
||||
$this->assertNull($schema->fresh()->default_crowd_type_id);
|
||||
}
|
||||
|
||||
public function test_database_level_foreign_key_constraint_exists(): void
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'SELECT rc.CONSTRAINT_NAME, kcu.REFERENCED_TABLE_NAME, '
|
||||
.'kcu.REFERENCED_COLUMN_NAME, rc.DELETE_RULE '
|
||||
.'FROM information_schema.REFERENTIAL_CONSTRAINTS rc '
|
||||
.'JOIN information_schema.KEY_COLUMN_USAGE kcu '
|
||||
.' ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME '
|
||||
.' AND kcu.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA '
|
||||
.'WHERE rc.CONSTRAINT_SCHEMA = DATABASE() '
|
||||
." AND kcu.TABLE_NAME = 'form_schemas' "
|
||||
." AND kcu.COLUMN_NAME = 'default_crowd_type_id'"
|
||||
);
|
||||
|
||||
$this->assertNotNull($row, 'Expected FK on form_schemas.default_crowd_type_id');
|
||||
$this->assertSame('crowd_types', $row->REFERENCED_TABLE_NAME);
|
||||
$this->assertSame('id', $row->REFERENCED_COLUMN_NAME);
|
||||
$this->assertSame('SET NULL', $row->DELETE_RULE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user