$attributes */ public function create(ArtistEngagement $engagement, array $attributes): Performance { return DB::transaction(function () use ($engagement, $attributes): Performance { $perf = new Performance($attributes); $perf->engagement_id = $engagement->id; $perf->event_id = $attributes['event_id'] ?? $engagement->event_id; $perf->version = 1; $perf->save(); return $perf->refresh(); }); } /** * Non-placement update only. start_at/end_at/stage_id/lane changes * MUST go through LaneCascadeService::move so the cascade-bump and * optimistic-lock contract are honoured. * * @param array $attributes */ public function update(Performance $performance, array $attributes): Performance { unset( $attributes['stage_id'], $attributes['start_at'], $attributes['end_at'], $attributes['lane'], $attributes['version'], $attributes['event_id'], $attributes['engagement_id'], ); $performance->fill($attributes); $performance->save(); return $performance->refresh(); } public function delete(Performance $performance): void { $performance->delete(); } /** * Move into the wachtrij. lane preserved so the user can drag back * to roughly the same visual position (D12 — wachtrij is just * stage_id=null, no separate table). */ public function park(Performance $performance, int $clientVersion): Performance { $result = $this->laneCascade->move( performance: $performance, targetStage: null, start: null, end: null, targetLane: null, clientVersion: $clientVersion, ); return $result->moved; } public function unpark( Performance $performance, Stage $targetStage, CarbonImmutable $start, CarbonImmutable $end, int $targetLane, int $clientVersion, ): Performance { $result = $this->laneCascade->move( performance: $performance, targetStage: $targetStage, start: $start, end: $end, targetLane: $targetLane, clientVersion: $clientVersion, ); return $result->moved; } }