Свой канал доставки v200.1.0
Как реализовать ChannelInterface и зарегистрировать канал
Базовые каналы модуля: сайт, почта, личные сообщения. Свой канал — отдельный класс с ChannelInterface и регистрация в ChannelRegistry.
Когда слать — другой текст: Своё событие. Здесь — куда слать.
Контракт
ChannelInterface
namespace DevCraft\Modules\Notifications\Channels;
interface ChannelInterface {
public function id(): string;
public function deliver(ChannelDeliveryContext $ctx): bool;
}| Метод | Назначение |
|---|---|
id() | Короткий ключ канала, например webhook. Им же передают флаг в $channels у notifySend. |
deliver() | Отправка одному получателю. true — успех, false — пропуск или ошибка (без исключения наружу). |
ChannelDeliveryContext
Поля контекста (readonly, кроме entity):
| Поле | Тип | Смысл |
|---|---|---|
recipientId | int | Кому слать |
senderId | int | Кто инициировал (0 — система) |
body | string | Готовый текст (уже из сценария / $message) |
vars | array | Плейсхолдеры {title}, {full-link}, … |
cfg | array | Конфиг модуля Notifications |
level | string | info / success / warning / … |
contentType / contentTypeId | Тип сущности в ленте | |
verb / targetType / targetId / data | служебные поля события | |
entity | ?Notification | Запись ленты (если уже создана каналом site) |
newsRow | array | Строка новости, если событие о материале |
Права и «включён ли канал» соседний модуль проверяет сам в deliver(). Ядро только решает, вызывать ли канал.
Когда вызывается ваш канал
notifySend/ штатный сценарий собирает тело.- Для
site/email/pm— настройки модуля + права + личные настройки. - Для любого другого
idиз реестра:- если
$channels === []→ канал считается желаемым (true); - если передан массив → нужен
'ваш_id' => true; - затем
UserPrefsService::wants($scenario, $channelId, …); - затем
deliver($ctx).
- если
Пример принудительно только свой канал:
notifySend(
$userId,
'Текст',
'custom',
0,
0,
'info',
['site' => false, 'email' => false, 'pm' => false, 'discord' => true],
);Минимальный канал
Шаг 1: класс канала
Файл, например, в своём модуле DevCraft:
devcraft/src/modules/MyNotifyDiscord/Channels/DiscordChannel.php
<?php
declare(strict_types=1);
namespace DevCraft\Modules\MyNotifyDiscord\Channels;
use DevCraft\Modules\Notifications\Channels\ChannelDeliveryContext;
use DevCraft\Modules\Notifications\Channels\ChannelInterface;
final class DiscordChannel implements ChannelInterface {
public function id(): string {
return 'discord';
}
public function deliver(ChannelDeliveryContext $ctx): bool {
$webhook = trim((string) ($ctx->cfg['discord_webhook'] ?? ''));
// лучше брать из конфига своего модуля через DataManager::getConfig(...)
if($webhook === '' || $ctx->body === '') {
return false;
}
$text = strip_tags($ctx->body);
$link = trim((string) ($ctx->vars['{full-link}'] ?? ''));
if($link !== '') {
$text .= "\n" . $link;
}
$payload = json_encode(['content' => $text], JSON_UNESCAPED_UNICODE);
if($payload === false) {
return false;
}
$ch = curl_init($webhook);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
curl_exec($ch);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $code >= 200 && $code < 300;
}
}Шаг 2: регистрация при boot
Два рабочих варианта.
А. Соседний модуль уведомлений — каталог Notifications* рядом с модулем уведомлений, файл boot.php. SatelliteLoader подхватит его сам:
<?php
declare(strict_types=1);
use DevCraft\Modules\Notifications\Channels\ChannelRegistry;
use DevCraft\Modules\MyNotifyDiscord\Channels\DiscordChannel;
if(!defined('DATALIFEENGINE') || !defined('DEVCRAFT_BOOTSTRAPPED')) {
return;
}
// Включайте канал только если настройка соседнего модуля активна
ChannelRegistry::instance()->register(new DiscordChannel());Имя каталога: NotificationsDiscord (префикс Notifications обязателен для автозагрузки boot.php).
Б. Свой модуль DevCraft — зарегистрируйте канал из своего запуска / include после DEVCRAFT_BOOTSTRAPPED, тем же ChannelRegistry::instance()->register(...).
Шаг 3: права и настройки (рекомендуется)
| Что | Куда |
|---|---|
| Включатель канала | settings.schema.php вашего модуля |
| Право группы | permissions.defs.php → подхватывается страницей «Права групп» Notifications через SatelliteLoader::permissionFiles() |
Проверка в deliver() | PermissionService::allows($ctx->recipientId, 'notifications_receive_discord') |
Файл permissions.defs.php в каталоге соседнего модуля:
<?php
declare(strict_types=1);
return [
'notifications_receive_discord' => [
'label' => __('Получать уведомления в Discord'),
'default' => false,
],
];Шаг 4: пункт в админке
Запись в dle_admin_sections (name = mod из манифеста) или положитесь на SatelliteLoader::ensureAdminSections() для известных каталогов / пропишите секцию в install.xml.
После этого: Админка → Уведомления — … → Настройки.
Чеклист
- Класс реализует
ChannelInterface,id()уникален. deliver()не бросает наружу — ловит ошибки и возвращаетfalse.- Канал зарегистрирован до первой отправки (
boot.php/ запуск DevCraft). - При
$channels === []канал будет вызываться всегда (если prefs не запретят) — держите выключатель внутриdeliver(). - Для подписки пользователя на свой канал в кабинете нужна отдельная логика; базовый кабинет знает
site/email/pm.