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>
30 lines
831 B
PHP
30 lines
831 B
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Enums\FormBuilder;
|
|
|
|
/**
|
|
* Boolean group operator for relational conditional logic
|
|
* (ARCH-FORM-BUILDER §8). `All` ≡ AND, `Any` ≡ OR. Groups nest
|
|
* arbitrarily; Phase A seed-scan observed nesting depth ≤ 2 in the
|
|
* wild, well inside the OrganisationScope FK-chain cap.
|
|
*/
|
|
enum FormFieldConditionalLogicGroupOperator: string
|
|
{
|
|
case All = 'all';
|
|
case Any = 'any';
|
|
|
|
/**
|
|
* String values of every case — used by the legacy-shape normaliser
|
|
* to walk `{"all": [...]}` / `{"any": [...]}` JSON nodes without
|
|
* duplicating the operator catalogue at the call site.
|
|
*
|
|
* @return list<string>
|
|
*/
|
|
public static function values(): array
|
|
{
|
|
return array_map(static fn (self $case): string => $case->value, self::cases());
|
|
}
|
|
}
|