feat(timetable): four custom validation rules for artist domain
StageActiveOnEvent — checks the candidate stage_id is linked to the given event_id via stage_days. Covers performance create/update (perf.event_id ↔ stage) and the timetable move endpoint (target_stage_id ↔ resolved target event). WithinEventBounds — checks a candidate datetime is inside the event's [start_at, end_at] window. Used for performance start/end dates and move-target dates against the relevant sub-event for festivals. OptionExpiresInFuture — conditional rule fired only when booking_status === 'option'. Asserts option_expires_at is set and in the future. Implementation of RFC §10.1 transition gate at the request layer (the service layer enforces the same invariant). ContractRequiresFee — conditional rule fired only when booking_status === 'contracted'. Asserts fee_amount is set and > 0. Same dual-layer enforcement as OptionExpiresInFuture. All four pass silently when the validated field is null or the context is irrelevant — the FormRequest still owns the surrounding required/nullable/exists rules. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
42
api/app/Rules/Artist/OptionExpiresInFuture.php
Normal file
42
api/app/Rules/Artist/OptionExpiresInFuture.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Rules\Artist;
|
||||
|
||||
use App\Enums\Artist\ArtistEngagementStatus;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
/**
|
||||
* Conditional rule: when `booking_status === 'option'`, the
|
||||
* `option_expires_at` field must be set and in the future.
|
||||
*
|
||||
* Bound from the engagement FormRequest, taking the inbound
|
||||
* booking_status value at construction time.
|
||||
*/
|
||||
final class OptionExpiresInFuture implements ValidationRule
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ?string $bookingStatus,
|
||||
) {}
|
||||
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
if ($this->bookingStatus !== ArtistEngagementStatus::Option->value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($value === null || $value === '') {
|
||||
$fail('Bij status "Optie" is een vervaldatum verplicht.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$candidate = CarbonImmutable::parse((string) $value);
|
||||
if ($candidate->isPast()) {
|
||||
$fail('De optie-vervaldatum moet in de toekomst liggen.');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user