Files
crewli/api/config/form_builder/binding_targets.php
bert.hausmans 0dd991c688 feat(form-builder): add BindingTypeRegistry as single source of truth for target shapes (WS-6)
Config-driven mapping from (target_entity, target_attribute) to storage
shape (scalar/collection/relation), PHP type, and identity-key
eligibility. Replaces any name-suffix matching (e.g. _tags, _skills) —
those are convention-not-contract and reject by design.

Used by publish guards now and (in session 2) by FormBindingApplicator.

Refs: RFC-WS-6.md §4 (V1)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:41:25 +02:00

50 lines
2.6 KiB
PHP

<?php
declare(strict_types=1);
/**
* RFC-WS-6 §4 (V1) — single source of truth for binding-target storage
* shape. Consulted by `BindingTypeRegistry`, `AppendStrategyRequiresCollectionTarget`
* publish guard, and (in session 2) by `FormBindingApplicator`.
*
* `type` values:
* - 'scalar' — single column (string/int/datetime/email/...)
* - 'collection' — JSON array column or pivot relation with set semantics
* - 'relation' — FK column resolving to another entity
*
* `php` values map to native PHP / cast types: 'string', 'int', 'bool',
* 'date', 'datetime', 'array'. Validated by
* BindingTypeRegistryConsistencyTest.
*
* `identity_key_eligible` permits a binding to set `is_identity_key=true`
* on this attribute. PurposeGuardProvider's RequiresIdentityKeyBinding
* may only target attributes that are eligible.
*/
return [
'person' => [
'email' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => true],
'first_name' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
'last_name' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
'date_of_birth' => ['type' => 'scalar', 'php' => 'date', 'identity_key_eligible' => false],
'phone_number' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
'dietary_preferences' => ['type' => 'collection', 'php' => 'array', 'identity_key_eligible' => false],
],
'artist' => [
'email' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => true],
'stage_name' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
'tech_rider' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
'hospitality_rider' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
],
'company' => [
'name' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => true],
'email' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => true],
'kvk_number' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => true],
'phone_number' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
],
'user' => [
'email' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => true],
'first_name' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
'last_name' => ['type' => 'scalar', 'php' => 'string', 'identity_key_eligible' => false],
],
];