PPPHP

Notifications – Notification Class & No-Code Rules

The Notification class raises in-app notifications — the little messages that light up the bell in your generated app's navbar. It creates its own table, self-heals its schema, colour-codes messages by severity, and ships targeting helpers so you can notify one user, a role, a group, everyone, or the record's owner in a single line.

There are two ways to send notifications:

  1. No-code rules — the Notifications module (project sidebar 🔔). Point-and-click: “When a record is added / edited / deleted, notify these people with this message.” Compiled into event hooks at build time. Recommended for most cases.
  2. Code — call the Notification API from any Event (afterAdd / afterEdit / …) or custom page when you need full control.

Contents

Severity types

Every notification has a type. It sets the icon and accent colour automatically — you never pick an icon unless you want to override it.

typeAuto iconAccentUse for
info (default)info-circleBlueGeneral FYI, mentions, assignments
successcheck-circleGreenCreated / approved / completed
warningexclamation-triangleAmberNeeds attention, nearing a limit
errorx-circleRedFailed / rejected / overdue

Pass 'icon' => 'bi-cart' to override the auto icon. Any Bootstrap-Icons name works.

No-code Notification Rules

Open the Notifications page in the project sidebar (🔔). Click a one-click template or New rule, then fill in four steps:

StepChoose
1. WhenA table + trigger — record added, edited, or deleted.
2. NotifyAudience — Everyone, a Role, a Group, specific Users, the record owner, or the actor (who did it).
3. MessageTitle + message + type. Insert live field values with {field} chips.
4. LinkWhere clicking the notification goes — the record, nothing, or a custom URL.

Placeholders: put any column of the saved row in curly braces and it is substituted at send time. For an orders rule:

Title:   New order #{id}
Message: {customer_name} placed an order for {total}

Rules are stored per-project and compiled into the table's afterAdd / afterEdit / afterDelete event hooks at build time — no runtime overhead, and they sit alongside any hand-written event code (they never overwrite it). Enabling any rule automatically provisions the notification bell, its API endpoint, and the table in the generated app.

Sending from code — Add()

$id = Notification::Add([
    'user_id' => 5,                       // recipient (null = everyone)
    'title'   => 'Orders',
    'message' => 'New order #1234 has been placed.',
    'type'    => 'success',                // info | success | warning | error
    'url'     => '/generated/orders/view.php?id=1234',
    'icon'    => 'bi-cart',                // optional — overrides the type icon
    'expire'  => '2026-12-31 23:59:59',    // optional auto-expiry
]);
KeyMeaning
user_idRecipient user id. null / omitted = broadcast to all. (userId also accepted.)
titleBold heading shown above the message.
messageThe notification body. Required.
typeSeverity — drives colour + icon. Defaults to info.
urlWhere clicking navigates. (link also accepted.)
iconOverride the auto icon (Bootstrap-Icons name).
expireAuto-hide after this timestamp.

You don't have to enable anything first — Add() creates the table on demand and self-heals its columns, so the rich fields (title / icon / url / type) work even if a leaner feature (e.g. the Calendar reminders) created the table earlier.

Targeting helpers

Skip the “look up the user ids” boilerplate — these do it for you and return how many were sent:

HelperSends to
AddForUsers(array $ids, array $data)Each id in the list (deduped).
AddForRole(string $role, array $data)Every user whose role matches.
AddForGroup(int $groupId, array $data)Every member of the group.
AddForEveryone(array $data)All users (one broadcast row).
AddForRecordOwner(array $row, string $ownerField, array $data)Whoever created the record (reads the id from $ownerField).
// Alert every admin, green tick, links to the record
Notification::AddForRole('admin', [
    'title'   => 'New order',
    'message' => 'Order #' . $id . ' was placed',
    'type'    => 'success',
    'url'     => '/generated/orders/view.php?id=' . $id,
]);

// Tell the person who created the ticket it was answered
Notification::AddForRecordOwner($data, 'created_by', [
    'title'   => 'Ticket updated',
    'message' => 'Your ticket "' . $data['subject'] . '" was answered',
    'type'    => 'info',
]);

// Broadcast an announcement to everyone
Notification::AddForEveryone([
    'title'   => 'Maintenance tonight',
    'message' => 'The app will be read-only from 10–11pm.',
    'type'    => 'warning',
]);

Reading, counting & marking read

// 20 most recent for the current user
$items  = Notification::Get(Security::CurrentUserData()['id'], 20);

// Only unread
$unread = Notification::Get($userId, 10, true);

// Unread badge count
$count  = Notification::Count($userId);

// Mark one / all read
Notification::MarkRead(12);
Notification::MarkAllRead($userId);

// Housekeeping — drop anything older than 60 days
Notification::DeleteOld(60);

The bell — badge, animation & toast

The generated app's navbar bell is wired automatically whenever notifications are in use. It:

Need to refresh the bell after your own AJAX action? Call window.ppNotifyRefresh() on the page.

Enabling the table

Usually you don't — a Notification rule, a Notification::Add() call, or the Calendar's in-app reminders each provision everything on their own. To turn it on explicitly, use Misc → Advanced → Notifications (set the table name, default notifications), or programmatically:

Notification::Enable('notifications');   // create + self-heal the table
Notification::SetTableName('notifications');

Real-world examples

afterAdd — notify admins a customer signed up

Notification::AddForRole('admin', [
    'title'   => 'New customer',
    'message' => "'{$data['name']}' just registered",
    'type'    => 'success',
    'url'     => '/generated/customers/view.php?id=' . $id,
]);

afterEdit — warn the owner their order shipped

if (($data['status'] ?? '') === 'shipped') {
    Notification::AddForRecordOwner($data, 'created_by', [
        'title'   => 'Order shipped',
        'message' => 'Order #' . $id . ' is on its way',
        'type'    => 'info',
        'url'     => '/generated/orders/view.php?id=' . $id,
    ]);
}

Approaching a limit — a warning to managers

if ((int)$data['stock'] < 5) {
    Notification::AddForRole('manager', [
        'title'   => 'Low stock',
        'message' => $data['name'] . ' is down to ' . $data['stock'],
        'type'    => 'warning',
    ]);
}

🔗 Related Help Topics

Email API SMS API Calendar Security API