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

Subjekty, vlastníci a strany

Typy subjektov

Subjekt je model, ktorého sa inštancia týka. Každý typ zaregistrujte raz, v metóde boot() service providera. Polia sú to, čo smú podmienky, odkazy a set_field čítať a zapisovať — nič iné na modeli:

use RoundlyConsulting\Workflows\Facades\Workflows;

Workflows::subjects()->register(
    Workflows::subject('purchase_request', PurchaseRequest::class)   // SubjectTypeBuilder
        ->label('Purchase request')
        ->ownedBy('team')                     // relation or attribute naming the owner
        ->field('amount', 'decimal', 'Amount')
        ->field('status', 'enum', 'Status', options: PurchaseStatus::class)   // enum class or list
        ->field('requester', 'party', 'Requester')                             // relation to a user
        ->field('approver_manager', 'party', "Approver's manager", path: 'approver.manager')
        ->field('due_on', 'date', 'Due on')
        ->field('priority', 'string', 'Priority', writable: true)              // set_field may write it
        ->ability('update'),                  // the ability set_field checks on this type
);
  • Typy polí: string, text, integer, decimal, boolean, date, datetime, enum, party, list. Názvy zodpovedajú ^[a-z][a-z0-9_]{0,63}$.
  • Čítanie ide cez registrovanú cestu (atribút alebo reláciu s bodkou). Neregistrované atribúty sa nikdy nečítajú. Enumy sa čítajú ako ich hodnota, dátumy sa prevedú do časového pásma verzie (dátum o polnoci si zachová uložený kalendárny deň) a desatinné čísla sa čítajú ako reťazce.
  • Definície, šablóny, resources aj API ukladajú a zobrazujú kľúč z registra (purchase_request), nikdy názov triedy.
  • Definícia nemusí mať typ subjektu (subjectType: null): jej inštancie potom bežia bez subjektu.

Namiesto registrácie v provideri môžete do workflows.subjects uviesť triedy, ktoré implementujú Contracts\DescribesWorkflowSubject:

use RoundlyConsulting\Workflows\Builders\SubjectTypeBuilder;
use RoundlyConsulting\Workflows\Contracts\DescribesWorkflowSubject;
use RoundlyConsulting\Workflows\Facades\Workflows;

final class PurchaseRequestSubject implements DescribesWorkflowSubject
{
    public function describe(): SubjectTypeBuilder
    {
        return Workflows::subject('purchase_request', PurchaseRequest::class)
            ->label('Purchase request')
            ->ownedBy('team')
            ->field('amount', 'decimal', 'Amount');
    }
}

// config/workflows.php
'subjects' => [App\Workflows\PurchaseRequestSubject::class],

Z registra čerpá výber polí v editore:

Workflows::subjects()->find('purchase_request');     // ?SubjectTypeDefinition
Workflows::subjects()->all();                        // array<string, SubjectTypeDefinition>
Workflows::subjects()->export('purchase_request');   // key, label, fields with type, label, writable, options

Trait HasWorkflows

$request->workflows()->start('purchase-approval', $team)->dispatch();
$request->workflows()->emit('purchase_request.submitted', ['note' => 'urgent']);
$request->workflows()->instances();     // cursor-paginated history, newest first
$request->workflows()->running();       // running or waiting instances
$request->workflows()->cancelAll('withdrawn');
$request->workflows()->touch();         // re-evaluate its condition waits
$request->workflowInstances();          // the morphMany relation

// The same handle without the trait:
Workflows::for($request)->running();

Po commite aktualizácie trait spraví touch subjektu, ak má čakajúce podmienkové čakania — no len vtedy, keď aktualizácia zmenila atribút registrovaného poľa alebo cudzí kľúč poľa typu belongs-to, takže bežné uloženie nepridá žiadny dopyt. Po zmazaní subjects_on_deleted = cancel (predvolené) zruší jeho bežiace inštancie; keep ich ponechá (zlyhajú so subject_missing, keď subjekt najbližšie potrebujú). Všetko ide cez manažéra, takže to Workflows::fake() vidí.

Vlastníci

Vlastník je tenant, ktorému definícia patrí — tím, firma. Null = celá aplikácia. Vlastník subjektu sa určuje v tomto poradí:

  • Contracts\HasWorkflowOwner::workflowOwner() na subjekte;
  • ownedBy(relation|attribute) typu subjektu;
  • prepojenie s teams (BelongsToTeam / ScopedToTeam: stĺpec tímu);
  • inak neznámy.
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Workflows\Contracts\HasWorkflowOwner;

class PurchaseRequest extends Model implements HasWorkflowOwner
{
    public function workflowOwner(): ?Model
    {
        return $this->department->company;   // checked before ownedBy() and the teams bridge
    }
}

Definícia pre celú aplikáciu prijme akýkoľvek subjekt. Definícia s vlastníkom prijme subjekt len vtedy, keď má jeho vlastník rovnakú morph triedu a kľúč; neznámy vlastník je nezhoda (fail closed). Definíciu s vlastníkom, ktorej typ subjektu nemá určenie vlastníka, nemožno publikovať (subject_owner_unresolvable).

Vlastník inštancie je vlastník definície, alebo — pri definícii pre celú aplikáciu — vlastník subjektu určený pri spustení. Všetky ďalšie kontroly aj kontext vlastníka používajú vlastníka inštancie. Ak sa subjekt počas behu presunie k inému vlastníkovi, ďalší krok zlyhá s owner_mismatch ešte pred spustením handlera. Typy vlastníkov sa registrujú ako subjekty, aby sa dali overiť odkazy owner.<field>:

// Owner types register like subjects, so owner.<field> refs validate.
Workflows::subjects()->register(
    Workflows::subject('team', Team::class)->ownerType()->field('plan', 'string', 'Plan'),
);

Strany

Schvaľovatelia, príjemcovia a ciele eskalácie sú odkazy na strany, rozlíšené podľa kind:

{"kind": "user", "id": 12}
{"kind": "field", "field": "subject.requester"}
{"kind": "role", "role": "legal"}
{"kind": "triggered_by"}
DruhJSONVyhodnotí sa naŠpecifické pre vlastníka
user{"kind":"user","id":12}Model používateľa (workflows.parties.user_model, predvolene auth.providers.users.model).áno
field{"kind":"field","field":"subject.requester"}Registrované pole typu party na subjekte alebo vlastníkovi.nie
role{"kind":"role","role":"legal"}ResolvesRoles::members($owner, $role) — prepojenie s teams alebo workflows.parties.roles.nie
triggered_by{"kind":"triggered_by"}Ten, kto inštanciu spustil.nie
  • Členstvo: strany user, field a triggered_by musia prejsť Contracts\ChecksOwnerMembership::isMember($owner, $user) (workflows.owners.membership; prepojenie s teams vyžaduje aktívne členstvo; bez neho je členom každý).
  • Bez vyhodnocovania rolí sa strany typu role pri publikovaní odmietnu (roles_unavailable).
  • Duplicity sa odstránia podľa kľúča; mäkko zmazaní používatelia sa preskočia.
  • Prázdne vyhodnotenie nikdy neznamená „ktokoľvek“: fáza schvaľovania bez schvaľovateľov zlyhá s no_approvers; krok notify bez príjemcov sa dokončí s recipients: 0.
  • Hodnoty špecifické pre vlastníka (strany typu user) sa pri importe šablóny pre iného vlastníka vymažú a označia na kontrolu.

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.