›
byrcsc/laravel-approval · 1.x
Enable, replace, or silence approval notifications and their channels.
Notification delivery is opt-in and disabled by default. Installing the package sends no external messages, and your application's own notification rules still apply.
APPROVAL_NOTIFICATIONS_ENABLED=trueWhile the setting is false, the package registers no notification listeners. An application that leaves notifications off runs none of the notification code.
This page covers which notifications are sent and to whom. To reword, translate, or restructure the emails, see notification content. You can publish the translations or the mail views without replacing any notification class.
Enabling delivery activates approval.notifications.map:
| Event | Notification | Recipients |
|---|---|---|
ApprovalSubmitted | ApprovalRequestedNotification | The active stage's holders |
StageCompleted | ApprovalRequestedNotification | The newly active stage's holders |
ApprovalApproved | ApprovalApprovedNotification | The requester |
ApprovalRejected | ApprovalRejectedNotification | The requester |
ApprovalReturned | ApprovalReturnedNotification | The requester |
DraftConflicted | ApprovalConflictNotification | The requester |
ApprovalDelegated | ApprovalAssignedNotification | The delegate |
DelegationEnded | ApprovalAssignedNotification | The approver it went back to |
ApproverReassigned | ApprovalAssignedNotification | The new holder |
ApproversResynced | ApprovalAssignedNotification | The holders a resync added |
ApproversEscalated | ApprovalAssignedNotification | The holders escalation added |
StageOverdue | ApprovalOverdueNotification | The overdue stage's holders |
StageOverdueReminder | ApprovalOverdueNotification | The overdue stage's holders |
Not every event is mapped. The mapped events are the state changes that leave somebody waiting on an action. You can listen to the rest yourself.
'notifications' => [
'channels' => ['mail', 'database'],
],The default is ['mail']. The setting applies to every shipped notification.
A replacement class can override via() to choose its own channels.
Set its entry to null:
'map' => [
Events\StageOverdueReminder::class => null,
// ...
],Point the entry at your own class. It must extend ApprovalNotification:
use ByRcsc\LaravelApproval\Events\ApprovalEvent;
use ByRcsc\LaravelApproval\Notifications\ApprovalNotification;
use Illuminate\Notifications\Messages\MailMessage;
final class PurchaseOrderNeedsApproval extends ApprovalNotification
{
public static function recipients(ApprovalEvent $event): iterable
{
return self::activeApprovers($event);
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Purchase order awaiting your approval')
->line($this->subject().' needs your sign-off.')
->action('Review', route('purchase-orders.approvals.show', $this->request()));
}
}'map' => [
Events\ApprovalSubmitted::class => PurchaseOrderNeedsApproval::class,
],Laravel notifications do not usually choose their own recipients. This package puts recipients on the notification class because applications change recipients most often. One entry in the map then replaces both the message and its audience, and you do not replace any listener.
The base class provides the helpers the shipped notifications use:
self::activeApprovers($event); // holders of the request's active stage
self::approversOf($stage); // holders of a specific stage
self::requesterOf($event); // the requester, as a listAn empty result is valid and sends nothing. For example, a stage whose approver records were all deleted has no recipients.
$this->event; // the ApprovalEvent
$this->request(); // the ApprovalRequest
$this->approvable(); // the record, or null if deleted since
$this->subject(); // a readable name for the recordsubject() tries name, title, reference, and label on the record. If
none is set, it returns ClassName #key, so a subject line always identifies
the record. A deleted record reads as "a deleted record".
Every approval event fires inside a transaction. If that transaction rolls
back, nobody should have received a message about the request. The shipped
listener wraps the send in DB::afterCommit(). Outside a transaction, the
callback runs immediately.
A typo in the map would otherwise go unnoticed until a notification fails to arrive. The package checks the map when it boots:
| Problem | Exception |
|---|---|
| The event class does not exist | InvalidConfigurationException::unknownNotificationEvent() |
| The notification class does not exist | InvalidConfigurationException::unknownNotification() |
It does not extend ApprovalNotification | InvalidConfigurationException::notificationIsNotANotification() |
A null entry is not an error. A null entry is how you switch an event off.
StageOverdue and StageOverdueReminder fire only when approval:escalate
runs. The record_only escalation default sends nothing on its own. Enable
notifications to turn the recorded overdue state into a message. See
SLAs and escalation.