refactor(form-field): drop form_fields.options + form_field_library.options
Final WS-5d cleanup. The JSON columns that have been unread since
commit 3 are now physically dropped on both source tables. Their
canonical rich-shape lives in form_field_options, accessed
exclusively through the morphMany relation.
Defensive sweep: any lingering translations.{locale}.options key in
either source table's translations bag is stripped. Commit 2's
backfill should already have done so exhaustively; this is
belt-and-braces.
Rollback re-creates the columns as nullable JSON but leaves them
empty. Pair with commit 2's rollback to restore the pre-WS-5d data
shape on every owner row.
The commit-3 getOptionsAttribute accessor-bridge on FormField +
FormFieldLibrary is removed — Eloquent's getAttribute() resolution
now naturally falls through to the morphMany relation since there's
no underlying column to shadow it. New regression test
FormFieldOptionsAccessTest asserts $field->options resolves to an
Eloquent Collection of FormFieldOption instances and lazy-loads in
exactly 2 queries (1 parent + 1 lazy-load options) on a fresh fetch
without with() preload. Same trio for FormFieldLibrary.
Migration step-count tests in WS-5a/b/c bumped by 1 to account for
the new drop_form_field_options_json_columns migration on the
rollback stack.
Documentation:
- SCHEMA.md v2.6: form_field_options table documented; options row
removed from form_fields and form_field_library; morphMany
relations updated; cross-references to ARCH-FORM-BUILDER §17.6
and addendum §Q3 WS-5d Uitvoering added on both source-table
docblocks.
- ARCH-FORM-BUILDER.md v1.8: new §17.6 "Field options (relational)"
mirrors the §17.4 / §17.5 relational-sibling structure with
sub-sections 17.6.1 rationale, 17.6.2 table + catalogue, 17.6.3
service / scope / cascade / activity log, 17.6.4 snapshot
embedding, 17.6.5 external API contract. Existing Webhooks
section renumbered from §17.6 to §17.7.
- ARCH-CONSOLIDATION-ADDENDUM-2026-04-24.md: "Uitvoering — WS-5d
(2026-04-27)" section added. Eight paragraphs covering the
snapshot atomic rewrite, strict-fail backfill dispatch, dual
activity-log emit, four-sibling base-class extraction warrant,
commit 0 dead-code precondition, the temporary getOptionsAttribute
accessor-bridge pattern (with reusability note for future
JSON→relational refactors), the dev-seeder vergoedingstype RADIO
normalisation (drift correction explicitly distinguished from the
parallel apps/app RegistrationFieldTemplate description domain),
and the WS-5 family completion note.
- BACKLOG.md: FORM-BUILDER-LIBRARY-AUDIT-LOG entry extended to four
services (adds library.options_replaced); new
FORM-BUILDER-MORPH-SCOPE-BASE-CLASS entry added as the WS-5d
follow-up now that all four concrete morph-scope siblings exist.
Tests: 1193 → 1208 green (+15 across commits 3+4+5; this commit alone:
+2 from the regression test).
This completes the WS-5 family.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,14 +33,15 @@ final class FormFieldBindingMigrationTest extends TestCase
|
||||
|
||||
public function test_forward_migrations_backfill_rows_from_both_json_sources(): void
|
||||
{
|
||||
// Roll back to pre-WS-5a state: 2 WS-5d migrations (backfill-options,
|
||||
// create-options) + 4 WS-5c migrations (drop-conditional-logic-col,
|
||||
// backfill-conditional-logic, create-conditional-logic-conditions,
|
||||
// Roll back to pre-WS-5a state: 3 WS-5d migrations (drop-options-cols,
|
||||
// backfill-options, create-options) + 4 WS-5c migrations
|
||||
// (drop-conditional-logic-col, backfill-conditional-logic,
|
||||
// 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) = 13.
|
||||
$this->artisan('migrate:rollback', ['--step' => 13])->assertSuccessful();
|
||||
// 2 WS-5a migrations (drop-binding-cols, create-bindings) = 14.
|
||||
$this->artisan('migrate:rollback', ['--step' => 14])->assertSuccessful();
|
||||
$this->assertFalse(Schema::hasTable('form_field_bindings'));
|
||||
$this->assertTrue(Schema::hasColumn('form_fields', 'binding'));
|
||||
$this->assertTrue(Schema::hasColumn('form_field_library', 'default_binding'));
|
||||
@@ -101,8 +102,8 @@ final class FormFieldBindingMigrationTest extends TestCase
|
||||
|
||||
public function test_rollback_reconstructs_json_and_drops_table(): void
|
||||
{
|
||||
// Walk back the full WS-5d + WS-5c + WS-5b + WS-5a stack (13 migrations).
|
||||
$this->artisan('migrate:rollback', ['--step' => 13])->assertSuccessful();
|
||||
// Walk back the full WS-5d + WS-5c + WS-5b + WS-5a stack (14 migrations).
|
||||
$this->artisan('migrate:rollback', ['--step' => 14])->assertSuccessful();
|
||||
[$fieldAId, , ] = $this->seedFieldsWithBindingJson();
|
||||
[$libAId, ] = $this->seedLibraryWithBindingJson();
|
||||
|
||||
@@ -112,12 +113,12 @@ final class FormFieldBindingMigrationTest extends TestCase
|
||||
$this->assertFalse(Schema::hasColumn('form_fields', 'binding'));
|
||||
$this->assertSame(5, DB::table('form_field_bindings')->count());
|
||||
|
||||
// Step back over WS-5d (2 migrations) + WS-5c (4 migrations) +
|
||||
// Step back over WS-5d (3 migrations) + WS-5c (4 migrations) +
|
||||
// WS-5b (5 migrations) in one go → restores the pre-WS-5b state
|
||||
// (conditional-logic, validation-rules, configs and options tables
|
||||
// gone, validation_rules JSON columns reappear on source tables;
|
||||
// binding contract intact).
|
||||
$this->artisan('migrate:rollback', ['--step' => 11])->assertSuccessful();
|
||||
// gone, validation_rules + options JSON columns reappear on source
|
||||
// tables; binding contract intact).
|
||||
$this->artisan('migrate:rollback', ['--step' => 12])->assertSuccessful();
|
||||
$this->assertFalse(Schema::hasTable('form_field_options'));
|
||||
$this->assertFalse(Schema::hasTable('form_field_conditional_logic_groups'));
|
||||
$this->assertFalse(Schema::hasTable('form_field_conditional_logic_conditions'));
|
||||
|
||||
Reference in New Issue
Block a user