Files
crewli/api/app/Http/Requests/Api/V1/FormBuilder/SavePublicDraftRequest.php
bert.hausmans 0cbdad70cd fix(api): accept submitter details on public draft PUT and submit POST
S3a PR 1 frontend sends public_submitter_name and public_submitter_email
on draft saves (PUT) and final submit (POST /submit), but the matching
SavePublicDraftRequest and SubmitPublicSubmissionRequest did not whitelist
these fields — Laravel's validated() silently stripped them, preventing
mid-form name/email updates from persisting.

Align both form requests with StartPublicDraftRequest to accept the same
submitter fields with identical rules (string, max:150 / email, max:255,
nullable). Controller copies present keys onto the submission model and
saves when dirty, matching standard Laravel update() semantics — missing
keys leave prior values untouched.

Closes the backend gap identified in PR 1 smoke test.
2026-04-23 16:36:31 +02:00

60 lines
1.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Requests\Api\V1\FormBuilder;
use App\Models\FormBuilder\FormSchema;
use App\Services\FormBuilder\FormFieldRuleBuilder;
use App\Services\FormBuilder\PublicFormTokenResolver;
use Illuminate\Foundation\Http\FormRequest;
/**
* Body for `PUT /api/v1/public/forms/{public_token}/submissions/{id}`.
* Auto-save endpoint — relaxed rule set per S2c D8. Only the field
* slugs present in the body are written; everything is nullable.
*/
final class SavePublicDraftRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, mixed>
*/
public function rules(): array
{
$base = [
'values' => ['sometimes', 'array'],
'first_interacted_at' => ['nullable', 'date'],
'public_submitter_name' => ['nullable', 'string', 'max:150'],
'public_submitter_email' => ['nullable', 'email', 'max:255'],
];
$schema = $this->resolveSchema();
if (! $schema instanceof FormSchema) {
return $base;
}
return array_merge(
$base,
app(FormFieldRuleBuilder::class)->relaxed($schema),
);
}
private function resolveSchema(): ?FormSchema
{
$token = (string) $this->route('public_token');
if ($token === '') {
return null;
}
try {
return app(PublicFormTokenResolver::class)->resolve($token);
} catch (\Throwable) {
return null;
}
}
}