refactor(form-field): extract legacy conditional_logic shape normaliser
Three byte-identical copies of `normaliseLegacyGroupShape` lived in
FormFieldService, StoreFormFieldRequest, and UpdateFormFieldRequest.
WS-5d (form_fields.options) would have been the fourth copy. Hoist
the helper to a single public static on FormFieldConditionalLogicService
and have all three call sites delegate.
Implementation:
- `FormFieldConditionalLogicService::normaliseLegacyShape(array)` —
pure recursive passthrough. Translates the ARCH §8 JSON group shape
(`{"all": [...]}` / `{"any": [...]}`) into the service's internal
`{"operator", "children"}` form. Does NOT validate; malformed shapes
return as-is and surface downstream as
`InvalidConditionalLogicSpecException` from `assertSpecsValid`.
- Group operator catalogue sourced from
`FormFieldConditionalLogicGroupOperator::values()` instead of an
`['all', 'any']` literal — single source of truth for future
operator additions.
- All three call sites switched to the static method. The two
FormRequests reach it via the existing `use` import; FormFieldService
sits in the same namespace.
Behaviour preserved exactly:
- Existing FormFieldApiTest (cyclic logic rejection),
FormFieldStrictConditionalLogicRequestTest (strict-validator
rejection paths), and FormFieldConditionalLogicServiceTest
(service-level paths) all green without modification.
New unit tests pin the passthrough contract (8 tests):
- Valid ALL / ANY translations
- Recursive nested-group translation (depth 2)
- Internal shape unchanged
- Condition leaf passthrough
- Unknown group key (`xor`) returned unchanged for downstream
`assertSpecsValid` to reject
- Empty array unchanged
- Non-array children stripped silently
Tests: 1150 → 1158 green (3110 → 3124 assertions).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -115,6 +115,57 @@ final class FormFieldConditionalLogicService
|
||||
$this->assertNodeValid($tree, isRoot: true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the legacy ARCH §8 JSON group shape (`{"all": [...]}` /
|
||||
* `{"any": [...]}`) into the service's internal tree form
|
||||
* (`{"operator": "all"|"any", "children": [...]}`). Pure recursive
|
||||
* passthrough — does NOT validate; malformed shapes are returned
|
||||
* as-is and surface as `InvalidConditionalLogicSpecException` from
|
||||
* the downstream `assertSpecsValid`. Static so both the service path
|
||||
* (`FormFieldService::extractConditionalLogicTree`) and the boundary
|
||||
* validators (Store/Update FormRequests' `after()` hooks) can call
|
||||
* it without container resolution.
|
||||
*
|
||||
* Group operator catalogue is sourced from
|
||||
* `FormFieldConditionalLogicGroupOperator::values()` so a future
|
||||
* operator addition lands in one place.
|
||||
*
|
||||
* @param array<string, mixed> $node
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function normaliseLegacyShape(array $node): array
|
||||
{
|
||||
if (isset($node['field_slug'])) {
|
||||
return $node;
|
||||
}
|
||||
|
||||
if (isset($node['operator'], $node['children']) && is_array($node['children'])) {
|
||||
$children = [];
|
||||
foreach ($node['children'] as $child) {
|
||||
if (is_array($child)) {
|
||||
$children[] = self::normaliseLegacyShape($child);
|
||||
}
|
||||
}
|
||||
|
||||
return ['operator' => $node['operator'], 'children' => $children];
|
||||
}
|
||||
|
||||
foreach (FormFieldConditionalLogicGroupOperator::values() as $candidate) {
|
||||
if (isset($node[$candidate]) && is_array($node[$candidate])) {
|
||||
$children = [];
|
||||
foreach ($node[$candidate] as $child) {
|
||||
if (is_array($child)) {
|
||||
$children[] = self::normaliseLegacyShape($child);
|
||||
}
|
||||
}
|
||||
|
||||
return ['operator' => $candidate, 'children' => $children];
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cross-field cycle detection (ARCH §8; contract preserved from the
|
||||
* pre-WS-5c `FormFieldService::assertNoConditionalCycle`). Builds a
|
||||
|
||||
Reference in New Issue
Block a user