›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-approval
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Workflows and stages
  • Choosing the workflow
  • Approvers and resolvers
  • Requests and state
  • Conditional stages

Approval flow

  • Submitting for approval
  • Recording decisions
  • Attribute drafts
  • Returns and resubmission
  • Bulk decisions

Assignments and deadlines

  • Delegation and reassignment
  • SLAs and escalation

Reading and authorization

  • Eligibility and authorization
  • Queries and timelines
  • Events and listeners
  • Notifications
  • Notification content

Operations

  • Workflow definitions
  • Audit trail and evidence
  • Console commands
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Workflows and stages
  • Choosing the workflow
  • Approvers and resolvers
  • Requests and state
  • Conditional stages

Approval flow

  • Submitting for approval
  • Recording decisions
  • Attribute drafts
  • Returns and resubmission
  • Bulk decisions

Assignments and deadlines

  • Delegation and reassignment
  • SLAs and escalation

Reading and authorization

  • Eligibility and authorization
  • Queries and timelines
  • Events and listeners
  • Notifications
  • Notification content

Operations

  • Workflow definitions
  • Audit trail and evidence
  • Console commands
  • Testing
  • Troubleshooting

byrcsc/laravel-approval · 1.x

Notifications.

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=true

While 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.

The map

Enabling delivery activates approval.notifications.map:

EventNotificationRecipients
ApprovalSubmittedApprovalRequestedNotificationThe active stage's holders
StageCompletedApprovalRequestedNotificationThe newly active stage's holders
ApprovalApprovedApprovalApprovedNotificationThe requester
ApprovalRejectedApprovalRejectedNotificationThe requester
ApprovalReturnedApprovalReturnedNotificationThe requester
DraftConflictedApprovalConflictNotificationThe requester
ApprovalDelegatedApprovalAssignedNotificationThe delegate
DelegationEndedApprovalAssignedNotificationThe approver it went back to
ApproverReassignedApprovalAssignedNotificationThe new holder
ApproversResyncedApprovalAssignedNotificationThe holders a resync added
ApproversEscalatedApprovalAssignedNotificationThe holders escalation added
StageOverdueApprovalOverdueNotificationThe overdue stage's holders
StageOverdueReminderApprovalOverdueNotificationThe 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.

Channels

'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.

Silencing one event

Set its entry to null:

'map' => [
    Events\StageOverdueReminder::class => null,
    // ...
],

Replacing a message

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,
],

Notifications declare their own recipients

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 list

An empty result is valid and sends nothing. For example, a stage whose approver records were all deleted has no recipients.

Helpers on the instance

$this->event;          // the ApprovalEvent
$this->request();      // the ApprovalRequest
$this->approvable();   // the record, or null if deleted since
$this->subject();      // a readable name for the record

subject() 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".

Delivery is deferred to after commit

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.

Configuration is validated at boot

A typo in the map would otherwise go unnoticed until a notification fails to arrive. The package checks the map when it boots:

ProblemException
The event class does not existInvalidConfigurationException::unknownNotificationEvent()
The notification class does not existInvalidConfigurationException::unknownNotification()
It does not extend ApprovalNotificationInvalidConfigurationException::notificationIsNotANotification()

A null entry is not an error. A null entry is how you switch an event off.

Overdue notifications need the sweep

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.

What to read next

  • Notification content to publish and edit wording or mail views.
  • Events and listeners to handle lifecycle events without the included notifications.
  • SLAs and escalation to generate overdue notification events.
PreviousEvents and listenersNextNotification content
View source

On this page

  1. The map
  2. Channels
  3. Silencing one event
  4. Replacing a message
  5. Notifications declare their own recipients
  6. Helpers on the instance
  7. Delivery is deferred to after commit
  8. Configuration is validated at boot
  9. Overdue notifications need the sweep
  10. What to read next