Balík má vlastnú tabuľku schránky — jedna položka na príjemcu, druh, subjekt a kontext v rámci okna, s počtom a posledným aktérom.
Zlučovanie
Rovnaký druh + subjekt + kontext + príjemca v rámci window() druhu aktualizuje jednu položku namiesto pridania ďalšej: count stúpne, posledný aktér a dáta nahradia staré a prečítaná položka sa znova stane neprečítanou. Okno sa počíta od prvej udalosti, takže hlučný subjekt začne v každom okne novú položku namiesto nekonečného zlučovania.
- Bez okna → každá udalosť je samostatná položka.
- Archivovaná alebo zmazaná položka sa prestane zlučovať: ďalšia udalosť začne novú (položka vrátená z archívu zostane uzavretá).
- Kontext je súčasťou kľúča: rovnaký subjekt v dvoch kontextoch zostane dvoma položkami.
- Eskalácie majú vlastnú dráhu: príjemca, ktorý dostal pôvodnú notifikáciu, dostane eskaláciu ako samostatnú položku aj e-mail.
- Vyhľadávanie zahŕňa aj soft-deleted riadky, takže zmazaná položka nikdy neblokuje ďalšiu udalosť.
Dotazy a počty
$inbox = Notifications::inbox($user); // or $user->inbox()
$inbox->paginate(perPage: 20); // not archived, newest activity first
$inbox->cursorPaginate();
$inbox->get(); // capped at inbox.max_per_page
$inbox->first();
$inbox->find($id); // another user's id → InboxItemNotFoundException
$inbox->unread()->paginate(); // read(), archived(), withArchived()
$inbox->in($company)->paginate(); // or a key string: in('company:3')
$inbox->withoutContext(); // allContexts() is the default
$inbox->category('requests')->type('request.awaiting_approval')->since(now()->subDay())->get();
$inbox->unreadCount(); // 7
$inbox->counts(); // InboxCounts { unread, total, contexts: list<ContextCount{key, label, unread}> }Stránky načítajú aktérov a subjekty vopred — bez N+1 — a perPage sa obmedzí na notifications.inbox.max_per_page.
Zmeny
$inbox->markRead($item); // also by id; acknowledges an acknowledgedOnRead() reminder
$inbox->markUnread($item);
$inbox->in($company)->markAllRead(); // one UPDATE within the handle's filters; returns the count
$inbox->markAllRead(in: $company, category: 'requests'); // explicit arguments replace the handle's context / category
$inbox->archive($item);
$inbox->unarchive($item);
$inbox->delete($item); // soft deleteMetódy vracajú handle; markAllRead() vracia počet. markAllRead() rešpektuje každý filter handle — in() alebo withoutContext(), category(), type() a since() — takže $inbox->in($company)->markAllRead() vyčistí len daný priestor. Položka iného príjemcu je „nenájdená“ — rovnaká odpoveď ako pri chýbajúcom id, takže schránka neprezradí, čo existuje.
Resources
InboxItemResource vykreslí id, type, category, title, body, url (len http(s)), count, data (publicData() druhu), actor, subject, context, priority ({value, label}), read_at, archived_at, first_event_at a last_event_at (ISO-8601) v jazyku požiadavky. InboxCountsResource vykreslí InboxCounts.
use RoundlyConsulting\Notifications\Http\Resources\InboxItemResource;
// A page — eager-loads actors and subjects
return InboxItemResource::collection(Notifications::inbox($request->user())->unread()->paginate());
// One item: wrap it yourself — its own data field makes Laravel skip the wrapper
return ['data' => (new InboxItemResource($item))->resolve()];{
"id": 12, "type": "request.awaiting_approval", "category": "requests", "title": "…", "body": null,
"url": "https://app.test/requests/9", "count": 10, "data": {"reference": "PR-9"},
"actor": {"id": 4, "type": "User"}, "subject": {"id": 9, "type": "PurchaseRequest"},
"context": {"key": "company:3", "label": "Acme s.r.o.", "id": 3, "type": "Company"},
"priority": {"value": "normal", "label": "Normal"}, "read_at": null, "archived_at": null,
"first_event_at": "2026-11-09T10:00:00+00:00", "last_event_at": "2026-11-09T10:04:31+00:00"
}Žiadne názvy tried v odpovediach
Aktér, subjekt a kontext sa vykresľujú cez vymeniteľné resources. Nasmerujte kľúč na vlastný JsonResource, ak chcete pridať meno či avatar; prázdna hodnota alebo null je predvolené, čokoľvek, čo nie je inštanciovateľný potomok JsonResource, vyhodí výnimku s názvom kľúča a chýbajúci aktér či subjekt sa vykreslí ako null. Rola príjemcu neexistuje: žiadny endpoint ani udalosť nevykreslí iného používateľa.
| Rola | Kľúč konfigurácie | Dostane | Predvolený výstup |
|---|---|---|---|
actor | notifications.resources.actor | model aktéra | {id, type: class_basename} |
subject | notifications.resources.subject | model subjektu | {id, type: class_basename} |
context | notifications.resources.context | ContextReference (snímka, bez dotazu) | {key, label, id?, type?} |
// config/notifications.php
'resources' => [
'actor' => App\Http\Resources\NotificationActorResource::class,
],
// app/Http/Resources/NotificationActorResource.php — receives the actor model
final class NotificationActorResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->resource->getKey(),
'name' => $this->resource->name,
'avatar_url' => $this->resource->avatar_url,
];
}
}Vysielanie (Reverb)
Balík nikdy nevysiela; počúvajte jeho udalosti po commite a resource vysielajte sami:
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\Notifications\Events\InboxItemCreated;
use RoundlyConsulting\Notifications\Events\InboxItemUpdated;
use RoundlyConsulting\Notifications\Http\Resources\InboxItemResource;
Event::listen([InboxItemCreated::class, InboxItemUpdated::class], function ($event): void {
$item = $event->item->loadMissing(['actor', 'subject']);
broadcast(new App\Events\InboxChanged(
userId: $item->recipient_id,
item: (new InboxItemResource($item))->resolve(),
unread: Notifications::inbox($item->recipient)->unreadCount(),
));
});
// App\Events\InboxChanged: ShouldBroadcast on new PrivateChannel('App.Models.User.'.$this->userId)
// broadcastWith(): ['item' => $this->item, 'unread' => $this->unread] — the resource only, never a class name.Kanál inbox v Laraveli
Aj vlastná notifikácia Laravelu sa môže dostať do schránky cez rovnaký krok zlučovania. Platí kontrola prístupu druhu a preferencia schránky; e-mail sa nepoužije — na ten slúži Notifications::send():
use Illuminate\Notifications\Notification;
use RoundlyConsulting\Notifications\Mail\InboxMessage;
final class CommentPosted extends Notification
{
public function via(object $notifiable): array { return ['inbox', 'broadcast']; }
public function toInbox(object $notifiable): InboxMessage
{
return (new InboxMessage('comment.posted'))
->about($this->post)
->by($this->author)
->in($this->post->blog)
->with(['excerpt' => $this->excerpt]);
}
}
// Programmatically
Notifications::inboxMessage($user, new InboxMessage('comment.posted')); // ?InboxItemKeď sa subjekt zmaže
notifications.inbox.on_subject_deleted je keep (predvolené — položky sa vykreslia zo snímky a dát), archive alebo delete. Platí pre subjekty s HasNotificationReminders; pri ostatných zavolajte Notifications::for($subject)->revoke() sami.
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.