NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky
Lifecycle for Laravel

Modely so životným cyklom

Model so životným cyklom implementuje kontrakt LifecycleSubject, používa trait HasLifecycle a v lifecycleDefinitions() priradí každý atribút cyklu k jeho definícii:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use RoundlyConsulting\Lifecycle\Concerns\HasLifecycle;
use RoundlyConsulting\Lifecycle\Contracts\LifecycleSubject;

final class Listing extends Model implements LifecycleSubject
{
    use HasLifecycle;
    use SoftDeletes;

    protected $guarded = [];

    public function lifecycleDefinitions(): array
    {
        return ['status' => ListingLifecycle::class];
    }

    protected function casts(): array
    {
        return ['status' => ListingStatus::class, 'published_at' => 'datetime'];
    }
}

Nový model začína v počiatočnom stave. Odvtedy sa stav mení len prechodmi:

use Illuminate\Support\Facades\Gate;
use RoundlyConsulting\Lifecycle\Facades\Lifecycles;

Gate::define('publish', fn (User $user, Listing $listing): bool => $listing->user_id === $user->id);

$listing = Listing::query()->create(['user_id' => $user->id]);  // status = draft

Lifecycles::for($listing)->by($user)->apply('publish');

$listing->status;                         // ListingStatus::Active
$listing->published_at;                   // now
Lifecycles::for($listing)->expiresAt();   // now + 30 days (the sweep runs "expire" 3 days later)

Viac cyklov na jeden model

Kľúče sú názvy atribútov; prvý je predvolený cyklus pre Lifecycles::for($model). Jedna trieda definície môže slúžiť viacerým modelom a kvóty počítajú vlastnú tabuľku každého modelu:

final class Order extends Model implements LifecycleSubject
{
    use HasLifecycle;

    public function lifecycleDefinitions(): array
    {
        // attribute => definition; the first one is the default lifecycle
        return ['status' => OrderLifecycle::class, 'payment_status' => PaymentLifecycle::class];
    }
}

Lifecycles::for($order)->apply('pay');                         // the first lifecycle (status)
Lifecycles::for($order, 'payment_status')->apply('authorize'); // another one

Čo sa deje pri vytvorení

Atribút cyklu s hodnotou NULL dostane počiatočný stav, deklarovaný nepočiatočný stav sa prijme (factories môžu vytvárať subjekty v ľubovoľnom stave) a nedeklarovaná hodnota vyhodí výnimku. Vytvorenie zapíše záznam stavu a riadok histórie initial a naplánuje TTL stavu. Uloženie priamo zmeneného stavu potom vyhodí výnimku — pozri Striktné zápisy a drift.

Čo pridá trait

  • Vzťahy: lifecycleStates(), lifecycleHistory(), lifecycleSchedules() a lifecycleLatestTransitions() (MorphMany).
  • Skratky: lifecycle(), transition(), transitionTo(), canTransition() a canTransitionTo() — vytvoria rovnaký handle ako Lifecycles::for() a idú cez toho istého manažéra.
  • Query scopes: whereState(), whereNotState(), whereExpired(), whereNotExpired(), whereExpiringWithin(), whereInGrace(), whereFrozen(), whereInStateFor() a withLifecycle().
  • Hooky modelu: soft delete subjektu pozastaví jeho plány a obnovenie ich znova spustí (obnovenie bez udalostí modelu, napríklad restoreQuietly(), zachytí najbližší sweep); trvalé zmazanie odstráni jeho záznamy, históriu aj plány (history.purge_on_force_delete). Fungujú aj modely bez SoftDeletes.
  • Na soft-deleted subjekt nemožno do jeho obnovenia aplikovať prechod ani rollback: kontroly odpovedia subject_trashed a apply() aj rollback() vyhodia SubjectTrashedException.
$listing->transition('close', ['note' => 'Sold elsewhere']);   // name, payload, lifecycle
$listing->canTransition('reopen');                             // bool
$listing->lifecycle()->by($user)->because('Back in stock')->apply('reopen');
$listing->transitionTo(ListingStatus::Archived);

Rezervované názvy

Názvy metód traitu sú na modeli rezervované. Vzťah alebo atribút s názvom lifecycle či transition treba premenovať — alebo skratky vynechajte a použite fasádu (Lifecycles::for($model)), ktorá žiadnu metódu traitu nepotrebuje.

Voliteľný cast

S enginom funguje aj obyčajný enum cast. AsLifecycleState číta stav podľa definície (prípad enumu alebo reťazec) a ukladá len deklarované stavy — nedeklarovaná hodnota vyhodí UnknownStateException:

use RoundlyConsulting\Lifecycle\Casts\AsLifecycleState;

protected function casts(): array
{
    return ['status' => AsLifecycleState::class];
}

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

Odoslaní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.