Notifly в Drupal
В Drupal удобнее всего сделать собственный custom-модуль notifly_alerts —
один файл и info.yml. Никаких composer-зависимостей не требуется,
используется встроенный \Drupal::httpClient().
Структура модуля
Заголовок раздела «Структура модуля»modules/custom/notifly_alerts/├── notifly_alerts.info.yml├── notifly_alerts.module└── src/ └── Notifly.phpnotifly_alerts.info.yml:
name: 'Notifly Alerts'type: moduledescription: 'Push-уведомления через сервер Notifly.'core_version_requirement: ^9 || ^10package: Customsrc/Notifly.php:
<?php
namespace Drupal\notifly_alerts;
class Notifly { public static function send(string $title, string $message, int $priority = 5): void { $config = \Drupal::config('notifly_alerts.settings'); $url = $config->get('url') ?: getenv('NOTIFLY_URL'); $token = $config->get('token') ?: getenv('NOTIFLY_TOKEN'); if (!$url || !$token) { return; } try { \Drupal::httpClient()->post("$url/message?token=$token", [ 'json' => [ 'title' => mb_substr($title, 0, 200), 'message' => mb_substr($message, 0, 1500), 'priority' => $priority, ], 'timeout' => 5, ]); } catch (\Throwable $e) { // Никогда не ломаем основной запрос Drupal из-за нотификации. } }}notifly_alerts.module:
<?php
use Drupal\notifly_alerts\Notifly;use Drupal\node\NodeInterface;use Drupal\user\UserInterface;use Drupal\Core\Logger\RfcLogLevel;
/** * Новый узел опубликован. */function notifly_alerts_entity_insert($entity) { if ($entity instanceof NodeInterface) { Notifly::send( "📝 Новый узел: {$entity->getTitle()}", "Тип: {$entity->bundle()}\n" . "Автор: {$entity->getOwner()->getAccountName()}\n" . "URL: " . $entity->toUrl('canonical', ['absolute' => TRUE])->toString(), 4 ); }}
/** * Регистрация пользователя. */function notifly_alerts_user_insert(UserInterface $account) { Notifly::send( "👤 Регистрация: {$account->getAccountName()}", "Email: {$account->getEmail()}\n" . "Roles: " . implode(', ', $account->getRoles()), 5 );}
/** * Ошибки PHP / watchdog уровня ERROR и выше. */function notifly_alerts_logger_factory_alter(&$factory) { // см. реализацию ниже — нужен отдельный сервис-логгер}Watchdog → Notifly
Заголовок раздела «Watchdog → Notifly»Чтобы ловить вообще все события, добавим собственный logger. Создайте
notifly_alerts.services.yml:
services: logger.notifly: class: Drupal\notifly_alerts\Logger\NotiflyLogger arguments: ['@logger.log_message_parser'] tags: - { name: logger }И src/Logger/NotiflyLogger.php:
<?php
namespace Drupal\notifly_alerts\Logger;
use Drupal\Core\Logger\LogMessageParserInterface;use Drupal\Core\Logger\RfcLoggerTrait;use Drupal\notifly_alerts\Notifly;use Psr\Log\LoggerInterface;
class NotiflyLogger implements LoggerInterface { use RfcLoggerTrait;
public function __construct(private LogMessageParserInterface $parser) {}
public function log($level, string|\Stringable $message, array $context = []): void { // 0=Emergency, 3=Error. if ($level > 3) return;
$vars = $this->parser->parseMessagePlaceholders($message, $context); $body = strtr((string) $message, $vars);
Notifly::send( sprintf('🐞 %s [%s]', $context['channel'] ?? 'php', match ((int)$level) { 0,1 => 'CRITICAL', 2 => 'CRITICAL', 3 => 'ERROR', default => 'WARN', }), $body . "\n\nRequest: " . ($context['request_uri'] ?? '-'), $level <= 2 ? 10 : 8 ); }}После добавления — drush cr. Все события watchdog уровня ERROR/CRITICAL/EMERGENCY
будут уходить в Notifly.
Конфигурация через UI (опционально)
Заголовок раздела «Конфигурация через UI (опционально)»Создайте config/install/notifly_alerts.settings.yml:
url: 'https://your-notifly.example.com'token: 'AGdjfk_L.dKe8q'И страницу настроек в админке — это уже стандартный паттерн ConfigForm Drupal.
Защита от спама
Заголовок раздела «Защита от спама»Можно использовать встроенный cache.default:
$cache_id = 'notifly_throttle:' . md5($title);if (\Drupal::cache()->get($cache_id)) return;\Drupal::cache()->set($cache_id, 1, time() + 60);Notifly::send(/* ... */);- Полная видимость watchdog в кармане. Не нужно лазить в Reports → Recent log.
- Узлы и регистрации в реальном времени. Удобно для модерации.
- Дешёвая альтернатива внешним сервисам ошибок.
Что улучшить дальше
Заголовок раздела «Что улучшить дальше»- Отдельный канал Notifly для контента и для технических событий.
- Включать ID узла/пользователя в
extras, чтобы клиент Notifly мог предоставлять deep-link.