Pripomienky a eskalácie
Pravidlá pripomienok patria druhu so subject() a vzťahujú sa na jeho dátumový atribút:
use RoundlyConsulting\Notifications\Recipients;
use RoundlyConsulting\Notifications\Reminders\Reminder;
final class ContractExpiring extends NotificationType
{
public function key(): string { return 'contract.expiring'; }
public function category(): string { return 'contracts'; }
public function subject(): ?string { return Contract::class; }
public function reminders(): array
{
return [
Reminder::before('expires_at', 'P60D', 'P30D', 'P7D')
->to(Recipients::owner())
->while(fn (Contract $contract): bool => $contract->terminated_at === null)
->escalate(after: 'P3D', to: fn (Contract $contract) => Recipients::role($contract->company, 'manager')),
];
}
public function title(NotificationPayload $p): string
{
return __('app.contract_expiring', ['offset' => $p->data['reminder'] ?? '']); // '-P30D'
}
}| Builder | Význam |
|---|---|
Reminder::before($attribute, ...$offsets) / after(...) | Kotva ∓ posun (ISO-8601 alebo relatívne), 1–25 kladných posunov. |
Reminder::at(CarbonInterface $when) | Absolútny čas — len pre jednorazové pripomienky. |
->key('expiry') | Stabilný kľúč pravidla (predvolene {attribute}:{direction}); dve pravidlá na jednom atribúte a smere potrebujú rôzne kľúče. |
->to($recipients) | Koho pripomienka upozorní; pravidlo bez to() je šablóna pre schedule($type, to: …). |
->while(fn (Model $subject): bool) | Overí sa pri odoslaní s čerstvým subjektom; false zruší (condition). |
->escalate(after:, to:, type: null) | Opakovateľné — reťaz úrovní. Nečitateľné alebo nekladné oneskorenie vyhodí výnimku okamžite. |
->acknowledgedOnRead() | Prečítanie položky pripomienky v schránke ju potvrdí. |
->rearm(false) | Neobnovovať odoslané pripomienky, keď sa kotva posunie neskôr (predvolene sa obnovia). |
Reminder::after('signed_at', 'P1Y')
->key('anniversary') // two rules on one attribute and direction need distinct keys
->to(Recipients::owner())
->acknowledgedOnRead() // reading the item acknowledges it
->rearm(false); // don't re-arm sent reminders when the anchor moves later
Reminder::before('deadline', 'PT1H'); // a template rule without to(): schedule() supplies recipientsPravidlá sa overujú pri registrácii: druh má subjekt, atribút nie je prázdny, 1–25 kladných posunov, kľúče pravidiel sú v druhu unikátne, žiadne at() v pravidle druhu. Kotva sa číta cez váš cast a prevedie sa do UTC. Časové posuny (PT…) sú absolútne; kalendárne (P…D/W/M/Y) sa aplikujú na miestny čas kotvy v app.timezone, takže „7 dní pred 09:00“ zostane 09:00 aj cez zmenu času.
Sledovanie dátumu
S traitom HasNotificationReminders na subjekte (pozrite Modely príjemcov a subjektov) sa pri každom uložení vykoná synchronizácia. Pre každé pravidlo a posun:
- Kotva vymazaná → čakajúce riadky sa zrušia (anchor_cleared).
- Čakajúci riadok s posunutým časom → prečasuje sa (ReminderRescheduled), alebo zruší (passed), ak je nový čas už v minulosti — posun kotvy dopredu nikdy neodošle vynechané posuny naraz.
- Žiadny čakajúci riadok → naplánuje sa, ak je čas v budúcnosti, pokiaľ už riadok pre presne túto kotvu neskončil; odoslaný riadok staršej kotvy sa obnoví (predĺženie). Minulé posuny sa nikdy nedopĺňajú.
- Unikátny kľúč zaistí, že dve súbežné synchronizácie naplánujú jeden riadok; konflikt nikdy nevyhodí výnimku.
- Update cez query builder obíde udalosti modelu: krok odoslania kotvu znova prečíta, takže zastaraný čas sa prečasuje namiesto odoslania.
Výslovné API a jednorazové pripomienky
Notifications::for($contract)->reminders()->sync(); // ?string $type
Notifications::for($contract)->reminders()->schedule('task.due', to: $assignee); // template rules, stored recipients
Notifications::for($contract)->reminders()->cancel(); // ?string $type
Notifications::for($contract)->reminders()->pending(); // Collection<NotificationReminder>
Notifications::for($contract)->reminders()->all();
// Ad-hoc reminders
Notifications::for($task)->remind('task.due', Reminder::before('deadline', 'PT1H'), to: $task->assignee);
Notifications::for($report)->remind('report.ready', Reminder::at(now()->addDay()), to: $user, data: ['id' => 7]);
Notifications::reminders()->backfill('contract.expiring'); // every subject of the type's class
Notifications::reminders()->fireDue(); // FiredReminders — what the sweep runsJednorazové pripomienky si ukladajú príjemcov aj dáta; ukotvená sleduje svoju kotvu ako pripomienka z pravidla. Druhé remind() s rovnakým kľúčom (->key(), inak atribút + posun, alebo čas) nahradí čakajúci riadok. Jednorazové pripomienky neberú podmienku, eskaláciu ani acknowledgedOnRead() — pravidlo s niektorou z nich vyhodí InvalidReminderRuleException; na to deklarujte pravidlo na druhu. Príjemcovia musia byť uložiteľní (bez closures). Pre subjekty, ktoré existovali pred pridaním druhu, spustite notifications:reminders:sync.
Odosielanie
Sweep odosiela splatné riadky od najstarších (notifications.reminders.batch na sweep), každý prevzatý cez compare-and-set. V tomto poradí: druh či pravidlo neexistuje → zrušené; subjekt neexistuje → subject_deleted; kotva sa zmenila → prečasované alebo passed; podmienka false → condition; oneskorenie viac než reminders.max_lateness (P1D) a kotva už prešla → preskočené (late). Potom prebehne odoslanie s kľúčom idempotencie pripomienky (prístup pre každého príjemcu), riadok je sent, pripraví sa reťaz eskalácií a spustí sa ReminderFired. Riadok, ktorý sa po reminders.lease stále odosiela, sa vráti do pending a opakované odoslanie nič nepošle dvakrát; odoslanie, ktoré vyhodí výnimku, sa opakuje v ďalších sweepoch a po troch pokusoch sa zruší. data v payloade obsahuje posun so znamienkom (['reminder' => '-P30D']) a reminder obsahuje ReminderReference.
Eskalácie
Každá úroveň je riadok splatný after po predchádzajúcom odoslaní. Pri odoslaní: potvrdené → zrušené; subjekt neexistuje alebo podmienka je false → zrušené; inak príjemcovia úrovne dostanú druh (alebo type: danej úrovne) označený ako eskalácia, vo vlastnej dráhe — nikdy sa nezlúči s pôvodnou položkou ani e-mailom — a pripraví sa ďalšia úroveň. Spustí sa EscalationFired.
Potvrdenie
Notifications::for($contract)->acknowledge('contract.expiring', by: $user); // or acknowledge() for every type
Notifications::reminders()->acknowledge($contract, 'contract.expiring', by: $user);Označí otvorené pripomienky a eskalácie subjektu (a druhu) ako potvrdené a zruší ich čakajúce eskalácie. Neskoršie posuny pripomienok stále odídu — potvrdená 30-dňová pripomienka neumlčí 7-dňovú — a obnovená pripomienka začína nepotvrdená. Pravidlá s acknowledgedOnRead() sa potvrdia aj vtedy, keď ktorýkoľvek príjemca označí položku pripomienky ako prečítanú, ale len kým ten čitateľ subjekt stále vidí. POST /inbox/{item}/acknowledge robí to isté po rovnakej kontrole prístupu. Notifications::for($subject)->acknowledge(by:) je dôveryhodný kód aplikácie: nič neoveruje, preto ho volajte len pre používateľa, ktorého ste autorizovali.
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.