feat(form-builder): form_field_conditional_logic_{groups,conditions} tables + OrganisationScope cap raise to 5
WS-5c commit 1 of 4 — relational infrastructure for the conditional- logic tree that replaces form_fields.conditional_logic JSON (ARCH- FORM-BUILDER §8; addendum Q3 WS-5c). Tables: groups (nesting via parent_group_id) + conditions (leaves, value JSON nullable for empty/not_empty). Simple FK to form_fields — addendum Q3 explicitly excludes form_field_library from conditional_ logic scope, so no polymorphic morph here. OrganisationScope cap raised 3 → 5 hops. The conditions chain is 4 hops (condition → group → field → schema → organisation_id column) and the new cap gives headroom for future deeper trees without denormalising form_field_id onto conditions. Cascade observer (FormFieldChildTablesCascadeObserver) extended to physically delete the new groups table on FormField delete (hard or soft). Conditions cascade automatically via the group_id FK on the groups table. Factories: FormFieldConditionalLogicGroupFactory, FormFieldConditional LogicConditionFactory, and FormFieldFactory::withConditionalLogic($tree) for concise test fixtures. Tests: 16 new under tests/Feature/FormBuilder/ConditionalLogic/ (relation, scope, cascade, enum catalogue). 3 new scope-cap tests in ScopeLeakageTest verify 4/5-hop chains pass and 6-hop throws. Hardcoded rollback step counts in WS-5a/b migration tests bumped for the 2 new WS-5c migrations. Baseline 1104 → 1122 green (2988 → 3032 assertions). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,11 +33,12 @@ final class FormFieldBindingMigrationTest extends TestCase
|
||||
|
||||
public function test_forward_migrations_backfill_rows_from_both_json_sources(): void
|
||||
{
|
||||
// Roll back to pre-WS-5a state: 5 WS-5b migrations
|
||||
// (drop-validation-cols, configs-backfill, create-configs,
|
||||
// validation-rules-backfill, create-validation-rules) +
|
||||
// 2 WS-5a migrations (drop-binding-cols, create-bindings) = 7.
|
||||
$this->artisan('migrate:rollback', ['--step' => 7])->assertSuccessful();
|
||||
// Roll back to pre-WS-5a state: 2 WS-5c migrations
|
||||
// (create-conditional-logic-conditions, create-conditional-logic-groups) +
|
||||
// 5 WS-5b migrations (drop-validation-cols, configs-backfill,
|
||||
// create-configs, validation-rules-backfill, create-validation-rules) +
|
||||
// 2 WS-5a migrations (drop-binding-cols, create-bindings) = 9.
|
||||
$this->artisan('migrate:rollback', ['--step' => 9])->assertSuccessful();
|
||||
$this->assertFalse(Schema::hasTable('form_field_bindings'));
|
||||
$this->assertTrue(Schema::hasColumn('form_fields', 'binding'));
|
||||
$this->assertTrue(Schema::hasColumn('form_field_library', 'default_binding'));
|
||||
@@ -98,8 +99,8 @@ final class FormFieldBindingMigrationTest extends TestCase
|
||||
|
||||
public function test_rollback_reconstructs_json_and_drops_table(): void
|
||||
{
|
||||
// Walk back the full WS-5b + WS-5a stack (7 migrations).
|
||||
$this->artisan('migrate:rollback', ['--step' => 7])->assertSuccessful();
|
||||
// Walk back the full WS-5c + WS-5b + WS-5a stack (9 migrations).
|
||||
$this->artisan('migrate:rollback', ['--step' => 9])->assertSuccessful();
|
||||
[$fieldAId, , ] = $this->seedFieldsWithBindingJson();
|
||||
[$libAId, ] = $this->seedLibraryWithBindingJson();
|
||||
|
||||
@@ -109,11 +110,13 @@ final class FormFieldBindingMigrationTest extends TestCase
|
||||
$this->assertFalse(Schema::hasColumn('form_fields', 'binding'));
|
||||
$this->assertSame(5, DB::table('form_field_bindings')->count());
|
||||
|
||||
// Step back over all five WS-5b migrations in one go → restores the
|
||||
// pre-WS-5b state (validation-rules and configs tables gone,
|
||||
// validation_rules JSON columns reappear on source tables; binding
|
||||
// contract intact).
|
||||
$this->artisan('migrate:rollback', ['--step' => 5])->assertSuccessful();
|
||||
// Step back over WS-5c (2 migrations) + WS-5b (5 migrations) in one
|
||||
// go → restores the pre-WS-5b state (conditional-logic,
|
||||
// validation-rules and configs tables gone, validation_rules JSON
|
||||
// columns reappear on source tables; binding contract intact).
|
||||
$this->artisan('migrate:rollback', ['--step' => 7])->assertSuccessful();
|
||||
$this->assertFalse(Schema::hasTable('form_field_conditional_logic_groups'));
|
||||
$this->assertFalse(Schema::hasTable('form_field_conditional_logic_conditions'));
|
||||
$this->assertFalse(Schema::hasTable('form_field_validation_rules'));
|
||||
$this->assertFalse(Schema::hasTable('form_field_configs'));
|
||||
$this->assertTrue(Schema::hasTable('form_field_bindings'));
|
||||
|
||||
Reference in New Issue
Block a user