*/ protected $casts = [ 'options' => 'array', 'validation_rules' => 'array', 'binding' => 'array', 'conditional_logic' => 'array', 'role_restrictions' => 'array', 'translations' => 'array', 'is_required' => 'bool', 'is_filterable' => 'bool', 'is_portal_visible' => 'bool', 'is_admin_only' => 'bool', 'is_unique' => 'bool', 'is_pii' => 'bool', 'review_required' => 'bool', 'display_width' => FormFieldDisplayWidth::class, 'value_storage_hint' => FormValueStorageHint::class, 'sort_order' => 'int', ]; public function schema(): BelongsTo { return $this->belongsTo(FormSchema::class, 'form_schema_id'); } public function section(): BelongsTo { return $this->belongsTo(FormSchemaSection::class, 'form_schema_section_id'); } public function libraryField(): BelongsTo { return $this->belongsTo(FormFieldLibrary::class, 'library_field_id'); } public function values(): HasMany { return $this->hasMany(FormValue::class); } /** * Nuanced activity log (ARCH §17.1; S1 Phase 4b). Callers choose which * events are worth logging — e.g. created/deleted/restored, field_type * changed (value storage changes), binding changed, is_pii toggled, * is_filterable toggled (triggers backfill), structural options changes. * NOT logged (noise): label/help_text/sort_order/conditional_logic/ * translations. * * Bulk-fixture suppression: the activitylog.enabled config key is the * kill-switch. Seeders and one-shot commands wrap themselves in * App\Support\ActivityLog::suppressed(...). activity()->log() becomes * a silent no-op while disabled, so no guard is needed here. * * @param array $properties */ public function logFieldChange(string $event, array $properties = []): void { activity() ->performedOn($this) ->withProperties($properties) ->log($event); } }