Sending
use Anvil\Notifications\Notification;
service('notifications')->send($userId, Notification::make('Export ready') ->body('deals.xlsx, 120 rows') ->url('/admin/deals') ->type(Notification::SUCCESS));
service('notifications')->send([$userA, $userB], Notification::make('Maintenance tonight'));The notification
Section titled “The notification”| Method | Rule | Default |
|---|---|---|
Notification::make($title) |
title of 1 to 200 characters | |
body($text) |
up to 2000 characters; longer text is cut | none |
url($path) |
a path of the application (/admin/…), up to 500 characters |
no link |
type($type) |
Notification::INFO, SUCCESS, WARNING or DANGER |
INFO |
Invalid values throw an InvalidArgumentException: an empty or too long
title, an unknown type, or a link that is not a path of the application.
Title and body are plain text; they are escaped when shown.
Links must be paths of the application. Other hosts, //… and
javascript: are rejected, so a notification can never send a user to a
foreign site. Build them with the URL helpers of resources and panels:
$resource = service('panels')->get('admin')->resourceByClass(OrderResource::class);
Notification::make('Order approved')->url($resource->path('view', $orderUuid));Use path() (not url()), because a link is stored as a path. The page
checks the permissions of the user when it is opened; a notification never
grants access.
Recipients
Section titled “Recipients”send() takes one internal user id or a list; duplicates are sent once.
Typical ways to find the users:
// The users of the current tenant with a permission (through their roles)$approvers = service('roleRepository')->usersWith('orders.approve');
// The users of a role$team = service('roleRepository')->usersOf($roleId);
// The user who is logged in$me = (int) auth()->id();usersWith() also finds users with orders.* and with a role of full
access. Never take user ids from the request.
Tenants
Section titled “Tenants”Notifications belong to the current tenant: users see them only while
they work in that tenant. In panels the tenant is set by the request; in
queue jobs, commands and anvil:tick set it yourself:
service('tenantContext')->runAs($tenantId, function () use ($userId): void { service('notifications')->send($userId, Notification::make('Import finished'));});Without a tenant in a multi-tenant application the model fails closed and nothing is stored.
In transactions
Section titled “In transactions”send() writes through an Anvil model. Inside an action handler or
afterSave() it is part of the transaction: if the change rolls back, the
notification is not sent either.
Writing good notifications
Section titled “Writing good notifications”- Title: what happened, in a few words (“Task overdue: Laptop for Ada”).
- Body: the detail the user needs to decide whether to open it.
- Link: the page where the user can act.
- Type:
WARNING/DANGERonly for things that need attention. - Use the language of the recipient where it differs from the sender’s – texts are stored as sent.