refactor(form-builder): strict validator on save; strip rules.unique fallback

This commit is contained in:
2026-04-24 22:26:44 +02:00
parent 800b1b6c01
commit 64ec4bcc5c
12 changed files with 469 additions and 29 deletions

View File

@@ -11,6 +11,7 @@ use App\Http\Resources\FormBuilder\FormFieldLibraryResource;
use App\Models\FormBuilder\FormFieldLibrary;
use App\Models\Organisation;
use App\Services\FormBuilder\FormFieldBindingService;
use App\Services\FormBuilder\FormFieldValidationRuleService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Facades\Gate;
@@ -20,6 +21,7 @@ final class FormFieldLibraryController extends Controller
{
public function __construct(
private readonly FormFieldBindingService $bindingService,
private readonly FormFieldValidationRuleService $validationRuleService,
) {}
public function index(Organisation $organisation): AnonymousResourceCollection
@@ -48,6 +50,7 @@ final class FormFieldLibraryController extends Controller
$data = $request->validated();
$bindingSpec = $this->extractBindingSpec($data);
$validationRuleSpecs = $this->extractValidationRuleSpecs($data);
$data['organisation_id'] = $organisation->id;
$data['is_system'] = false;
$data['is_active'] ??= true;
@@ -60,6 +63,10 @@ final class FormFieldLibraryController extends Controller
$this->bindingService->replaceBindings($library, [$bindingSpec]);
}
if ($validationRuleSpecs !== null) {
$this->validationRuleService->replaceRules($library, $validationRuleSpecs);
}
return $this->created(new FormFieldLibraryResource($library));
}
@@ -72,6 +79,9 @@ final class FormFieldLibraryController extends Controller
$bindingProvided = array_key_exists('default_binding', $data);
$bindingSpec = $bindingProvided ? $this->extractBindingSpec($data) : null;
$validationRulesProvided = array_key_exists('validation_rules', $data);
$validationRuleSpecs = $validationRulesProvided ? $this->extractValidationRuleSpecs($data) : null;
$fieldLibrary->fill($data);
$fieldLibrary->save();
@@ -82,9 +92,40 @@ final class FormFieldLibraryController extends Controller
);
}
if ($validationRulesProvided) {
$this->validationRuleService->replaceRules(
$fieldLibrary,
$validationRuleSpecs ?? [],
);
}
return $this->success(new FormFieldLibraryResource($fieldLibrary));
}
/**
* Extract validation rule specs from the request data array and return
* them for the service-layer writer. The JSON column is no longer
* written (WS-5b commit 3) writes go through
* `FormFieldValidationRuleService::replaceRules` after save.
*
* @param array<string, mixed> $data
* @return list<array<string, mixed>>|null
*/
private function extractValidationRuleSpecs(array &$data): ?array
{
if (! array_key_exists('validation_rules', $data)) {
return null;
}
$raw = $data['validation_rules'];
unset($data['validation_rules']);
if (! is_array($raw)) {
return [];
}
/** @var list<array<string, mixed>> $raw */
return array_values($raw);
}
/**
* @param array<string, mixed> $data
* @return array{target_entity:string,target_attribute:string,mode:string,sync_direction?:?string}|null