4.6 KiB
Developing notifications for Pony.fm
Pony.fm's notification system is designed around "drivers" for various
notification delivery methods. The types of notification one can receive
are defined in the
NotificationHandler
interface, which is implemented by every class that needs to know about
the various notification types.
Sending a notification
The Notification
facade is used to send notifications as follows:
use Notification;
// Something happens, like a new track getting published.
$track = new Track();
...
// The "something" is done happening! Time to send a notification.
Notification::publishedNewTrack($track);
This facade has a method for every notification type, drawn from the
NotificationHandler
interface.
Each of these methods accepts the data needed to build a notification
message and a list of the notification's recipients.
Adding new notification types
-
Add a method for the new notification type to the
NotificationHandler
interface. -
Implement the new methods in every class that implements the interface. Use your IDE to find these. An inexhaustive list:
-
Create a migration to add the new notification type to the
activity_types
table. Add a constant for it to theActivity
class. -
Ensure you create HTML and plaintext templates, as well as a subclass of
BaseNotification
for the email version of the notification. -
Call the new method on the
Notification
facade from wherever the new notification gets triggered. -
Implement any necessary logic for the new notification type in the
Activity
model.
Adding new notification drivers
-
Create a new class for the driver that implements the
NotificationHandler
interface. -
Make each method from the above interface send the corresponding type of notification to everyone who is to receive it via that driver. Implement UI and API integrations as needed.
-
Modify the
RecipientFinder
class to build recipient lists for the new driver.
Architectural notes
The notification system is designed around two ideas: being as type-safe as PHP allows it to be, and doing all the processing and sending of notifications asynchronously.
To that end, the
NotificationManager
class is a thin wrapper around the SendNotifications
job. The job
calls the notification drivers asynchronously to actually send the
notifications. This job should run on a dedicated queue in production.
The NotificationHandler
interface is key to maintaining type safety - it ensures that drivers
and NotificationManager
all support every type of notification. All
classes that have logic specific to a notification type implement this
interface to ensure that all notification types are handled.
There's one exception to the use of NotificationHandler
- the
Activity
model. The logic for mapping the
data we store about an activity in the database to a notification's API
representation had to go somewhere, and using the NotificationHandler
interface here would have made this logic a lot more obtuse.
Data flow
-
Some action that triggers a notification calls the
NotificationManager
facade. -
An asynchronous job is kicked off that figures out how to send the notification.
-
An
Activity
record is created for the action. -
A
Notification
record is created for every user who is to receive a notification about that activity. These records act as Pony.fm's on-site notifications and cannot be disabled. -
Depending on subscription preferences, push and email notifications will be sent out as well, each creating their own respective database records. These are linked to a
Notification
record for unified read/unread tracking. -
A
Notification
record is marked read when it is viewed on-site or any other notification type associated with it (like an email or push notification) is clicked.