feat(form-builder): add PersonProvisioner with race-safe firstOrCreate (WS-6)
PersonProvisioner reads bindings from schema_snapshot (RFC Q6) and provisions Persons via lockForUpdate + firstOrCreate (RFC Q8). Person is event-scoped (Person::$organisationScopeColumn = 'event_id'), so the lookup matches by (email, event_id) — cross-event submissions never collide. Throws PersonProvisioningException on misconfiguration (failsafe — publish guards should prevent these at config time): no_transaction, no_event, no_identity_key, identity_key_missing_value, no_crowd_type. Snapshot enrichment: FormFieldBindingService::toApplicatorShape + FormSubmissionService snapshot now adds a 'bindings' (plural) key with binding id, merge_strategy, trust_level, is_identity_key. Singular 'binding' key kept for legacy webhook / GDPR readers. Includes RFC V4 state-injection concurrency test asserting recovery semantics under lockForUpdate windows. Refs: RFC-WS-6.md §3 (Q6, Q8), §4 (V4) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\FormBuilder;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* RFC-WS-6 §3 (Q8) — failure during PersonProvisioner operation.
|
||||
*
|
||||
* Reason codes (informal contract):
|
||||
* - 'no_transaction' called outside DB::transaction
|
||||
* - 'no_identity_key' schema has no is_identity_key=true binding for person
|
||||
* - 'no_event' submission missing event_id (Person scope is event_id)
|
||||
* - 'identity_key_missing_value' identity-key form_value is absent or null
|
||||
*/
|
||||
final class PersonProvisioningException extends RuntimeException
|
||||
{
|
||||
public function __construct(
|
||||
public readonly string $reasonCode,
|
||||
public readonly string $submissionId,
|
||||
?string $message = null,
|
||||
) {
|
||||
parent::__construct($message ?? "Person provisioning failed: {$reasonCode} (submission {$submissionId})");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user