---
title: "API zdroje a validácia — Lifecycle for Laravel | Roundly"
description: "LifecycleResource a TransitionRecordResource pre API, validačné pravidlá ValidTransition a ValidState a 422 či Retry-After zo zamietnutí."
url: https://roundly-consulting.com/sk/open-source/navody/lifecycle-for-laravel/api-zdroje
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Lifecycle for Laravel](https://roundly-consulting.com/sk/open-source/navody/lifecycle-for-laravel.md)

# API zdroje a validácia

```php
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:

```json
{
  "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": {"id": 1, "type": "User"}, "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(). Pri riadku bez aktéra (systémové a počiatočné riadky) je actor null.

## Resource aktéra

actor sa vykreslí cez TransitionActorResource ako {id, type}: kľúč aktéra a krátky názov triedy jeho modelu (User) — nikdy nie názov PHP triedy ako App\\Models\\User. Pri morph mape sa alias najprv preloží na triedu, takže 'member' => User::class sa vykreslí ako User, nie member. Resource obaľuje TransitionRecord, nie model aktéra, takže vykreslenie histórie nenačíta žiadneho aktéra a nepridá dotaz na riadok.

Cez lifecycle.resources.actor ho nahradíte vlastným, keď vaše API potrebuje viac, napríklad meno či avatar. Vaša podtrieda JsonResource dostane ten istý TransitionRecord a aktéra si načíta sama z actorType a actorId:

```php
// config/lifecycle.php
'resources' => [
    'actor' => App\Http\Resources\HistoryActorResource::class,
],

// app/Http/Resources/HistoryActorResource.php
use App\Models\User;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use RoundlyConsulting\Lifecycle\DataTransferObjects\TransitionRecord;

/** @property TransitionRecord $resource */
final class HistoryActorResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        $class = Relation::getMorphedModel((string) $this->resource->actorType) ?? $this->resource->actorType;

        return [
            'id' => $this->resource->actorId,
            'type' => class_basename((string) $class),
            'name' => $class === User::class ? User::query()->find($this->resource->actorId)?->name : null,
        ];
    }
}
```

Tento príklad načíta jedného používateľa na každý riadok; pri dlhej histórii načítajte aktérov stránky naraz (findMany() nad actorId) a vyhľadávajte v nich. Prázdna hodnota alebo null použije resource balíka. Čokoľvek, čo nie je inštanciovateľná podtrieda JsonResource — model, samotný JsonResource, abstraktná či neexistujúca trieda — vyhodí pri vykreslení prvého riadku s aktérom InvalidLifecycleConfigurationException (notAResource) s názvom kľúča.

## Validačné pravidlá

```php
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

```php
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 kryptomien](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## 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.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/lifecycle-for-laravel.md)
