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

Vstavané kroky

Workflows::catalogue()->export() vráti každý typ s názvom, schémou konfigurácie, výsledkami, príznakom vedľajších efektov, balíkom, ktorý potrebuje (pri prepojených typoch), a informáciou, či je dostupný. php artisan workflows:catalogue vypíše to isté ako tabuľku:

$export = Workflows::catalogue()->export();   // CatalogueExport{types, definitions}

$approval = $export->find('approval');          // CatalogueEntry
$approval->available;                           // false when approvals-for-laravel is missing
$approval->package;                             // 'roundly-consulting/approvals-for-laravel'
$approval->configSchema;                        // the node config's JSON Schema
$approval->outcomes;                            // list<Outcome>: approved, rejected, expired, cancelled (optional)
TypKonfiguráciaVýsledkyVedľajšie efekty
triggerPozri Spúšťače.nextnie
condition{when: condition}true, falsenie
branch{cases: list<{outcome, when}>, default: "<outcome>"}výsledky prípadov + defaultnie
set_field{field: "subject.<field>", value: literal | {ref}}nextáno
transition{transition, lifecycle?, reason?}transitioned, denied (voliteľný)áno
delay{for: duration} | {until: date-time} | {until_field: "subject.<date>", offset?: duration}nextnie
wait{event, match?: "subject"|"any", where?} | {condition, poll?} + timeout?received / met (+ timed_out)nie
loop{max: 1…limits.max_loop_iterations}continue, exhaustednie
start_workflow{definition, subject?: "same"|{field}|null, input?: map of values, wait?: bool}started (bez wait) / completed, failed, cancelled (voliteľný)áno
end{status?: "completed"|"failed", reason?}—nie
approvalPrepojenie s approvals — pozri Prepojenia.approved, rejected, expired, cancelled (voliteľný)áno
notifyPrepojenie s notifications.nextáno
webhook{endpoint, event, payload?} — iba s adaptérom DeliversWebhooksqueuedáno

trigger, condition, branch

  • trigger — presne jeden v grafe. Dokončí sa pri spustení; jeho výstup je {input, trigger} (overený vstup a payload spúšťača), dostupný ako steps.<trigger id>.output.*.
  • condition — vyhodnotí podmienku nad subjektom, vstupom, spúšťačom, vlastníkom a skoršími výstupmi. Obe hrany sú povinné. Je čistý a beží v transakcii, v ktorej si engine vedie záznamy.
  • branch — vyhrá prvý prípad, ktorého when platí; inak default. Kľúče výsledkov zodpovedajú ^[a-z][a-z0-9_]{0,31}$ a sú jedinečné; každý výsledok potrebuje hranu.

set_field a transition

  • set_field zapíše zapisovateľné registrované pole subjektu (->field(..., writable: true)). Hodnota sa overí podľa typu poľa. Cesta cez reláciu sa pri publikovaní odmietne. Oprávnenie: ability() typu subjektu (predvolene update), ak ho neprepíše workflows.authorization.abilities.set_field. S prepojením na lifecycle sa pole so stavovým stĺpcom lifecycle odmietne pri publikovaní (field_not_writable) aj za behu (field_write_refused).
  • transition vykoná prechod lifecycle cez Contracts\TransitionAdapter (predvolene prepojenie s lifecycle alebo workflows.adapters.transition). Bez nich typ hlási adapter_missing. Zamietnutý prechod pokračuje hranou denied, ak existuje; inak krok zlyhá s transition_denied:<code> (opakuje sa, len ak lifecycle označí zamietnutie za opakovateľné).
// condition — both edges required
{ "id": "big", "type": "condition", "config": { "when": { "field": "subject.amount", "op": "gt", "value": "50000" } } }

// branch — the first case whose `when` holds wins, otherwise `default`
{ "id": "route", "type": "branch", "config": {
    "cases": [
      { "outcome": "legal", "when": { "field": "subject.department", "op": "equals", "value": "legal" } },
      { "outcome": "finance", "when": { "field": "subject.department", "op": "equals", "value": "finance" } } ],
    "default": "default" } }

// set_field — writes a writable registered field of the subject
{ "id": "mark", "type": "set_field", "config": { "field": "subject.priority", "value": { "ref": "input.priority" } } }

// transition — a lifecycle transition through the transition adapter
{ "id": "approve_state", "type": "transition", "config": { "transition": "approve", "reason": "Approved by the workflow" } }

delay a wait

  • delay — for pridá trvanie (kalendárny alebo pracovný čas); until čaká na okamih; until_field čaká na dátumové pole subjektu plus voliteľný posun so znamienkom (pole date uložené o polnoci je splatné o polnoci daného dňa v časovom pásme verzie). Čas v minulosti pokračuje hneď; prázdne pole zlyhá s delay_field_empty. Prerušovačom cyklu je len kladné for.
  • wait na udalosť — pokračuje pri Workflows::emit($key, $subject) (alebo signal()), výsledok received. match subject (predvolené) vyžaduje ten istý subjekt; any prijme akýkoľvek subjekt toho istého vlastníka — nikdy nie naprieč vlastníkmi. Rátajú sa len udalosti vyslané po tom, čo krok začal čakať. where (podmienka nad trigger.*, teda payloadom udalosti) čaká, kým nepríde udalosť so zodpovedajúcim payloadom; where bez event sa pri publikovaní odmietne.
  • wait na podmienku — vyhodnotí sa najprv pri vstupe, potom pri každom touch subjektu (hook updated v HasWorkflows, Workflows::for($subject)->touch()) a pri každej kontrole poll (≥ PT1M, predvolene PT15M); výsledok met.
  • timeout pridá povinný výsledok timed_out. wait podporuje eskalácie. Wake podmienku nikdy nevyhodnocuje sám: kontrolu odovzdá jobu, ktorý najprv obnoví kontext vlastníka.
// delay — a positive `for` (calendar or business time), an instant, or a date field ± an offset
{ "id": "cool_off", "type": "delay", "config": { "for": { "amount": 2, "unit": "business_days" } } }
{ "id": "until", "type": "delay", "config": { "until": "2026-12-01T09:00:00+01:00" } }
{ "id": "remind", "type": "delay", "config": { "until_field": "subject.due_on", "offset": { "amount": -3, "unit": "days" } } }

// wait for an event — only a payload that matches `where` resumes it
{ "id": "signed", "type": "wait", "config": {
    "event": "doc.signed", "match": "subject",
    "where": { "field": "trigger.role", "op": "equals", "value": "cfo" },
    "timeout": "P5D" } }

// wait until a condition holds — checked on every subject touch and every poll
{ "id": "paid", "type": "wait", "config": {
    "condition": { "field": "subject.status", "op": "equals", "value": "paid" },
    "poll": "PT15M", "timeout": "P14D" } }

loop — slučka prepracovania

Loop je prerušovač len cez svoju hranu continue. Počítadlo je počet návštev uzla v inštancii: continue, kým je ≤ max, potom exhausted — hrana exhausted, ktorá vedie späť do toho istého cyklu, teda nič nestráži a odmietne sa. Bežné opätovné podanie „schválenie → prepracovanie → znova schválenie“ ide cez loop, ktorý obmedzí počet kôl. Každý prechod cez approve je nová návšteva, takže otvorí nové kolo s novým idempotentným kľúčom:

"nodes": [
  { "id": "start", "type": "trigger", "config": { "trigger": "event", "event": "purchase_request.submitted" } },
  { "id": "round", "type": "loop", "config": { "max": 3 } },
  { "id": "approve", "type": "approval", "config": { "approvers": [ { "kind": "field", "field": "subject.approver" } ], "rule": "any" } },
  { "id": "rework", "type": "wait", "config": { "event": "purchase_request.resubmitted", "timeout": "P14D" } },
  { "id": "done", "type": "end" },
  { "id": "gave_up", "type": "end", "config": { "status": "failed", "reason": "too many rounds" } }
],
"edges": [
  { "from": "start", "to": "round" },
  { "from": "round", "to": "approve", "outcome": "continue" },
  { "from": "round", "to": "gave_up", "outcome": "exhausted" },
  { "from": "approve", "to": "done", "outcome": "approved" },
  { "from": "approve", "to": "rework", "outcome": "rejected" },
  { "from": "approve", "to": "gave_up", "outcome": "expired" },
  { "from": "rework", "to": "round", "outcome": "received" },
  { "from": "rework", "to": "gave_up", "outcome": "timed_out" }
]

start_workflow a end

// start_workflow — a manual definition of the same owner; wait for it or carry on
{ "id": "welcome", "type": "start_workflow", "config": {
    "definition": "welcome",
    "subject": "same",                                   // "same" (default), { "field": … } or null
    "input": { "employee": { "ref": "input.employee" } },
    "wait": true } }                                     // outcomes completed / failed / cancelled; without wait: started

// end — completes the instance, or fails it with ended_by_graph and the reason
{ "id": "done", "type": "end" }
{ "id": "gave_up", "type": "end", "config": { "status": "failed", "reason": "too many rounds" } }
  • start_workflow spustí ručnú definíciu toho istého vlastníka (hĺbka + 1, ≤ limits.max_depth). subject: same (predvolené), pole subjektu typu party alebo relácia, alebo null; definícia dieťaťa bez subjektu nikdy subjekt nedostane. input mapuje vstupy dieťaťa na hodnoty alebo odkazy.
  • wait: false sa dokončí okamžite s started; wait: true čaká na dieťa a pokračuje s completed, failed alebo cancelled. Je idempotentný: opakovanie nikdy nespustí druhé dieťa.
  • Dieťa, ktoré odmietne limit spustení (limits.max_starts_per_minute), sa nikdy nespustilo, preto sa krok nedokončí: zlyhá opakovateľne s child_not_started a opakuje sa s odstupom, kým sa v limite neuvoľní miesto a dieťa sa nespustí.
  • Publikovanie overí, že dieťa existuje, má ručný spúšťač a jeho povinné vstupy sú pokryté (za behu sa to overí znova voči aktuálnej verzii dieťaťa); statické spustenie seba samého bez wait: false je varovanie.
  • Zrušenie rodiča zruší aj dieťa, ktoré spustil — s wait aj bez neho, aj dieťa spustené pokusom, ktorý ešte bežal, aj dieťa kroku čakajúceho na opakovanie — no len kým je aktívne, v poradí zámkov rodič → dieťa.
  • end dokončí inštanciu, alebo so status: failed ju ukončí zlyhaním s ended_by_graph a dôvodom.

Prepojené kroky a kroky s adaptérom

approval (approvals-for-laravel) a notify (notifications-for-laravel) opisuje časť Prepojenia. Prepojený typ, ktorého balík chýba, ostáva v katalógu s available: false a názvom balíka a publikovanie hlási adapter_missing. Krok webhook ({endpoint, event, payload?}, výsledok queued) sa zaregistruje len vtedy, keď workflows.adapters.webhooks uvádza implementáciu Contracts\DeliversWebhooks; doručenie prebehne raz za návštevu cez once() a endpoint je špecifický pre vlastníka (pri importe šablóny sa vymaže).

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.