API zdroje a validácia
use RoundlyConsulting\Lifecycle\Http\Resources\LifecycleResource;
use RoundlyConsulting\Lifecycle\Http\Resources\TransitionRecordResource;
// One response feeds the buttons: state, freeze, expiry and every transition with its reasons
return LifecycleResource::make(Lifecycles::for($listing)->by($request->user()));
// A list: a model stands for its primary lifecycle, with the actor from auth
return LifecycleResource::collection(Listing::query()->withLifecycle()->get());
// Another lifecycle of every model in a list
return LifecycleResource::collectionFor(Order::query()->withLifecycle()->get(), 'payment_status');
// History rows (context and snapshot only on request)
return TransitionRecordResource::collection(Lifecycles::for($listing)->history());
(new TransitionRecordResource($record))->withContext();LifecycleResource vráti všetko, čo obrazovka potrebuje — handle vytvorte cez by(), aby sa prechody overili pre daného aktéra; ak dostane model, použije jeho primárny cyklus a prihláseného aktéra. collection() vykreslí primárny cyklus každého modelu; collectionFor($models, 'payment_status') vykreslí pomenovaný cyklus. allowed_transitions obsahuje aj zamietnuté prechody s ich dôvodmi, takže rozhranie vykreslí neaktívne tlačidlá s vysvetlením, pole pre dôvod (requires_reason), formulár (payload_fields) aj odpočet (available_at). Časy sú ISO-8601 v UTC; state a to sú surové hodnoty. S withLifecycle() načíta kolekcia stav, zmrazenie, expiráciu a posledný prechod bez dotazu na každý model:
{
"lifecycle": "status",
"state": "active",
"state_label": "Active",
"terminal": false,
"entered_at": "2026-10-02T08:00:00+00:00",
"version": 2,
"frozen": {"until": "2026-10-05T08:00:00+00:00", "reason": "maintenance"},
"expiry": {"expires_at": "2026-11-01T08:00:00+00:00", "due_at": "2026-11-04T08:00:00+00:00", "in_grace": false},
"allowed_transitions": [
{
"name": "close", "label": "Close", "to": "closed", "to_label": "Closed", "allowed": false,
"denials": [{"code": "frozen", "message": "This record is frozen.", "params": {"transition": "Close", "state": "Active"}, "retry_after": null, "errors": []}],
"requires_reason": false, "payload_fields": [], "available_at": null
}
],
"last_transition": {
"id": 2, "kind": "transition", "transition": "publish", "from": "draft", "to": "active",
"actor": {"type": "App\\Models\\User", "id": 1}, "system": false, "reason": "ready",
"occurred_at": "2026-10-02T08:00:00+00:00", "reverted": false
}
}TransitionRecordResource vráti id, kind, transition, from, to, actor, system, reason, occurred_at a reverted; context a snapshot až po withContext().
Validačné pravidlá
use RoundlyConsulting\Lifecycle\Rules\ValidState;
use RoundlyConsulting\Lifecycle\Rules\ValidTransition;
$request->validate([
'transition' => ['required', ValidTransition::for($listing)->by($request->user())],
'target' => ['required', ValidTransition::for($listing, 'status')->by($request->user())->toState()],
'status' => ['nullable', ValidState::of(Listing::class)], // the model's first lifecycle
'payment' => ['nullable', ValidState::of(new Order, 'payment_status')],
'filter' => ['nullable', ValidState::of(ListingLifecycle::class)], // a definition class
]);ValidTransition spustí celú pipeline vrátane pravidiel pre aktéra a zlyhá so správou každého zamietnutia; toState() validuje cieľový stav namiesto názvu prechodu. ValidState prijme triedu alebo inštanciu modelu (s voliteľným cyklom) alebo triedu definície a vyžaduje deklarovaný stav. Obe sú informatívne ako check() — apply() rozhodne znova pod zámkom.
Zamietnutia ako 422 a Retry-After
use RoundlyConsulting\Lifecycle\Exceptions\TransitionDeniedException;
// A refusal as a 422, with payload errors under their own keys ($request is a FormRequest)
try {
Lifecycles::for($listing)->by($request->user())->with($request->validated())->apply('reopen');
} catch (TransitionDeniedException $e) {
throw $e->toValidationException();
}Odovzdávajte len zvalidovaný vstup, nikdy $request->all(). Prechod payload zvaliduje znova vlastnými rules() a ponechá len tieto kľúče.
toValidationException() majú TransitionDeniedException (pole transition) aj RollbackDeniedException (pole rollback). Obe implementujú HasRetryAfter z toolkitu: retryAfterSeconds() dá hodnotu pre Retry-After pri rate_limited alebo cooldown_active. decision() a denials() vrátia štruktúrované zamietnutie.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.