Recipient and subject models
Two traits and four small contracts connect your models to the package. Each is optional — implement only what your types use.
ReceivesNotifications — the recipient
Use it on your User next to Laravel’s Notifiable. Every call goes through the manager, so Notifications::fake() sees it:
$user->inbox()->unread()->paginate(); // = Notifications::inbox($user)
$user->notificationPreferences()->mute('comment.posted'); // = Notifications::preferences($user)
$user->unreadNotificationCount(); // 3HasNotificationReminders — the subject
Use it on a model whose dates drive reminders (a contract, a task, a trial). Reminders of every type whose subject() is this class — or a parent of it — follow its date attributes:
use RoundlyConsulting\Notifications\Traits\HasNotificationReminders;
class Contract extends Model
{
use HasNotificationReminders;
}
$contract->update(['expires_at' => now()->addYear()]); // pending reminders move; sent ones re-arm
$contract->delete(); // pending reminders and escalations are cancelled
$contract->restore(); // and scheduled again
$contract->notificationReminders(); // MorphMany<NotificationReminder>
$contract->syncNotificationReminders(); // int — a manual syncIt syncs on created, on updated when an anchor attribute of a registered rule (or of a pending ad-hoc reminder) changed, and on restored — after your commit, so a lock wait or a lost race never fails or rolls back your save() (errors are reported). A delete, soft or force, cancels with subject_deleted. It is also the subject-lifecycle hook for notifications.inbox.on_subject_deleted (keep, archive or delete the subject’s inbox items).
Contracts
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Notifications\Contracts\HasNotificationContext;
use RoundlyConsulting\Notifications\Contracts\HasNotificationOwner;
use RoundlyConsulting\Notifications\Contracts\HasNotificationTimezone;
use RoundlyConsulting\Notifications\Contracts\ProvidesNotificationRecipients;
// A recipient that names its own timezone — the first source the default resolver asks
class User extends Authenticatable implements HasNotificationTimezone
{
use Notifiable;
use ReceivesNotifications;
public function notificationTimezone(): ?string
{
return $this->settings['timezone'] ?? null;
}
}
// A group behind Recipients::role() / members(), and an inbox context with its own label
class Company extends Model implements ProvidesNotificationRecipients, HasNotificationContext
{
public function notificationRecipients(?string $role = null): iterable
{
return $role === null
? $this->users
: $this->users()->wherePivot('role', $role)->get();
}
public function notificationContextLabel(): string
{
return $this->legal_name; // "Acme s.r.o."
}
}
// A subject that names its owner, for Recipients::owner()
class Contract extends Model implements HasNotificationOwner
{
use HasNotificationReminders;
public function notificationOwner(): Model|iterable|null
{
return $this->accountManager;
}
}| Contract | Method | Used by |
|---|---|---|
HasNotificationTimezone | notificationTimezone(): ?string | The default timezone resolver — its first source. |
ProvidesNotificationRecipients | notificationRecipients(?string $role = null): iterable | The default group resolver behind Recipients::role() and members(). |
HasNotificationOwner | notificationOwner(): Model|iterable|null | Recipients::owner(). |
HasNotificationContext | notificationContextLabel(): string | The label of a model context, else its name attribute, else its basename and key. |
RecipientResolver | resolve(?Model $subject, array $args): iterable | Recipients::using(). |
ResolvesGroupMembers | members(Model $group, ?string $role = null): iterable | notifications.recipients.group_resolver. |
ResolvesMailAddress | address(Model $recipient, ?NotificationPayload $payload): ?string | notifications.mail.address_resolver. |
ResolvesTimezone | timezone(Model $recipient): string | notifications.timezone.resolver. |
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.