Skip to content

Ibexa Notifications#3090

Draft
adriendupuis wants to merge 12 commits into5.0from
notifications
Draft

Ibexa Notifications#3090
adriendupuis wants to merge 12 commits into5.0from
notifications

Conversation

@adriendupuis
Copy link
Contributor

Question Answer
JIRA Ticket
Versions
Edition

Document ibexa/notifications

Checklist

  • Text renders correctly
  • Text has been checked with vale
  • Description metadata is up to date
  • Redirects cover removed/moved pages
  • Code samples are working
  • PHP code samples have been fixed with PHP CS fixer
  • Added link to this PR in relevant JIRA ticket or code PR

@github-actions
Copy link

github-actions bot commented Mar 17, 2026

adriendupuis and others added 10 commits March 17, 2026 08:55
Mainly to avoid confusion with administration/back_office/notifications.md and fix duplicate:

WARNING -  Doc file 'administration/back_office/notifications.md' contains a link 'users/notifications.md', but the target 'administration/back_office/users/notifications.md' is not found among documentation files.
WARNING -  AutoLinksPlugin: Duplicate filename referred to in 'docs/administration/project_organization/bundles.md': 'notifications.md' exists at ['docs/administration/back_office/notifications.md', 'docs/users/notifications.md']
WARNING -  AutoLinksPlugin: Duplicate filename referred to in 'docs/api/event_reference/other_events.md': 'notifications.md' exists at ['docs/administration/back_office/notifications.md', 'docs/users/notifications.md']
WARNING -  AutoLinksPlugin: Duplicate filename referred to in 'docs/resources/new_in_doc.md': 'notifications.md' exists at ['docs/administration/back_office/notifications.md', 'docs/users/notifications.md']
Trying to fix "Cannot call method info() on Psr\Log\LoggerInterface|null."
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

@github-actions
Copy link

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/user_management/notifications/config/packages/custom_notifications.yaml


code_samples/user_management/notifications/config/packages/custom_notifications.yaml

docs/users/notification_channels.md@62:``` yaml
docs/users/notification_channels.md@63:[[= include_file('code_samples/user_management/notifications/config/packages/custom_notifications.yaml', 0, 18) =]]
docs/users/notification_channels.md@64:```

001⫶framework:
002⫶ notifier:
003⫶ chatter_transports:
004⫶ slack: '%env(SLACK_DSN)%'
005⫶ibexa:
006⫶ system:
007⫶ default:
008⫶ notifier:
009⫶ subscriptions:
010⫶ Ibexa\OrderManagement\Notification\OrderStatusChange:
011⫶ channels:
012⫶ - chat
013⫶ Ibexa\Payment\Notification\PaymentStatusChange:
014⫶ channels:
015⫶ - chat
016⫶ Ibexa\Shipping\Notification\ShipmentStatusChange:
017⫶ channels:
018⫶ - chat

docs/users/notification_channels.md@106:``` yaml
docs/users/notification_channels.md@107:[[= include_file('code_samples/user_management/notifications/config/packages/custom_notifications.yaml', 5, 9) =]] # …
docs/users/notification_channels.md@108:[[= include_file('code_samples/user_management/notifications/config/packages/custom_notifications.yaml', 18) =]]
docs/users/notification_channels.md@109:```

001⫶ system:
002⫶ default:
003⫶ notifier:
004⫶ subscriptions:
005⫶ # …


code_samples/user_management/notifications/config/services.yaml


code_samples/user_management/notifications/config/services.yaml

docs/users/notification_channels.md@129:``` yaml
docs/users/notification_channels.md@130:[[= include_file('code_samples/user_management/notifications/config/services.yaml') =]]
docs/users/notification_channels.md@131:```

001⫶services:
002⫶ App\Notifier\Channel\LogChannel:
003⫶ tags:
004⫶ - { name: 'notifier.channel', channel: 'log' }


code_samples/user_management/notifications/src/Command/NotificationSenderCommand.php


code_samples/user_management/notifications/src/Command/NotificationSenderCommand.php

docs/users/notification_channels.md@113:``` php
docs/users/notification_channels.md@114:[[= include_file('code_samples/user_management/notifications/src/Command/NotificationSenderCommand.php') =]]
docs/users/notification_channels.md@115:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\src\Command;
006⫶
007⫶use App\Notifications\CommandExecuted;
008⫶use Ibexa\Contracts\Core\Repository\UserService;
009⫶use Ibexa\Contracts\Notifications\Service\NotificationServiceInterface;
010⫶use Ibexa\Contracts\Notifications\Value\Notification\SymfonyNotificationAdapter;
011⫶use Ibexa\Contracts\Notifications\Value\Recipent\SymfonyRecipientAdapter;
012⫶use Ibexa\Contracts\Notifications\Value\Recipent\UserRecipient;
013⫶use Symfony\Component\Console\Attribute\AsCommand;
014⫶use Symfony\Component\Console\Command\Command;
015⫶use Symfony\Component\Console\Input\InputInterface;
016⫶use Symfony\Component\Console\Output\OutputInterface;
017⫶use Symfony\Component\Notifier\Recipient\RecipientInterface;
018⫶
019⫶#[AsCommand(name: 'app:send_notification', description: 'Example of command sending a notification')]
020⫶class NotificationSenderCommand extends Command
021⫶{
022⫶ /** @param array<int, string> $recipientLogins */
023⫶ public function __construct(
024⫶ private readonly NotificationServiceInterface $notificationService,
025⫶ private readonly UserService $userService,
026⫶ private readonly array $recipientLogins = ['admin'],
027⫶ ) {
028⫶ parent::__construct();
029⫶ }
030⫶
031⫶ protected function execute(InputInterface $input, OutputInterface $output): int
032⫶ {
033⫶ /** @var array<int, \Throwable> $exceptions */
034⫶ $exceptions = [];
035⫶
036⫶ try {
037⫶ // Do something
038⫶ if (rand(0, 1) == 1) {
039⫶ throw new \RuntimeException('Something went wrong');
040⫶ }
041⫶ $exitCode = Command::SUCCESS;
042⫶ } catch (\Exception $exception) {
043⫶ $exceptions[] = $exception;
044⫶ $exitCode = Command::FAILURE;
045⫶ }
046⫶
047⫶ $recipients = [];
048⫶ foreach ($this->recipientLogins as $login) {
049⫶ try {
050⫶ $user = $this->userService->loadUserByLogin($login);
051⫶ $recipients[] = new UserRecipient($user);
052⫶ } catch (\Exception $exception) {
053⫶ $exceptions[] = $exception;
054⫶ }
055⫶ }
056⫶
057⫶ $this->notificationService->send(
058⫶ new SymfonyNotificationAdapter(new CommandExecuted($this, $exitCode, $exceptions)),
059⫶ array_map(
060⫶ static fn (RecipientInterface $recipient): SymfonyRecipientAdapter => new SymfonyRecipientAdapter($recipient),
061⫶ $recipients
062⫶ )
063⫶ );
064⫶
065⫶ return $exitCode;
066⫶ }
067⫶}


code_samples/user_management/notifications/src/Notifications/CommandExecuted.php


code_samples/user_management/notifications/src/Notifications/CommandExecuted.php

docs/users/notification_channels.md@100:``` php
docs/users/notification_channels.md@101:[[= include_file('code_samples/user_management/notifications/src/Notifications/CommandExecuted.php') =]]
docs/users/notification_channels.md@102:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\Notifications;
004⫶
005⫶use Ibexa\Contracts\Notifications\SystemNotification\SystemMessage;
006⫶use Ibexa\Contracts\Notifications\SystemNotification\SystemNotificationInterface;
007⫶use Ibexa\Contracts\Notifications\Value\Recipent\UserRecipientInterface;
008⫶use Symfony\Bridge\Twig\Mime\NotificationEmail;
009⫶use Symfony\Component\Console\Command\Command;
010⫶use Symfony\Component\Notifier\Message\EmailMessage;
011⫶use Symfony\Component\Notifier\Notification\EmailNotificationInterface;
012⫶use Symfony\Component\Notifier\Notification\Notification;
013⫶use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;
014⫶use Throwable;
015⫶
016⫶class CommandExecuted extends Notification implements SystemNotificationInterface, EmailNotificationInterface
017⫶{
018⫶ /** @param array<int, Throwable> $exceptions */
019⫶ public function __construct(
020⫶ private readonly Command $command,
021⫶ private readonly int $exitCode,
022⫶ private readonly array $exceptions
023⫶ ) {
024⫶ parent::__construct((Command::SUCCESS === $this->exitCode ? '✔' : '✖') . $this->command->getName());
025⫶ $this->importance(Command::SUCCESS === $this->exitCode ? Notification::IMPORTANCE_LOW : Notification::IMPORTANCE_HIGH);
026⫶ }
027⫶
028⫶ public function asEmailMessage(EmailRecipientInterface $recipient, ?string $transport = null): ?EmailMessage
029⫶ {
030⫶ $body = '';
031⫶ foreach ($this->exceptions as $exception) {
032⫶ $body .= $exception->getMessage() . '<br>';
033⫶ }
034⫶
035⫶ $email = NotificationEmail::asPublicEmail()
036⫶ ->to($recipient->getEmail())
037⫶ ->subject($this->getSubject())
038⫶ ->html($body);
039⫶
040⫶ return new EmailMessage($email);
041⫶ }
042⫶
043⫶ public function asSystemNotification(UserRecipientInterface $recipient, ?string $transport = null): ?SystemMessage
044⫶ {
045⫶ $message = new SystemMessage($recipient->getUser());
046⫶ $message->setContext([
047⫶ 'icon' => Command::SUCCESS === $this->exitCode ? 'check-circle' : 'discard-circle',
048⫶ 'subject' => $this->command->getName(),
049⫶ 'content' => Command::SUCCESS === $this->exitCode ? 'No error' : count($this->exceptions) . ' error' . (count($this->exceptions) > 1 ? 's' : ''),
050⫶ ]);
051⫶
052⫶ return $message;
053⫶ }
054⫶}


code_samples/user_management/notifications/src/Notifier/Channel/LogChannel.php


code_samples/user_management/notifications/src/Notifier/Channel/LogChannel.php

docs/users/notification_channels.md@125:``` php
docs/users/notification_channels.md@126:[[= include_file('code_samples/user_management/notifications/src/Notifier/Channel/LogChannel.php') =]]
docs/users/notification_channels.md@127:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\Notifier\Channel;
004⫶
005⫶use Psr\Log\LoggerAwareInterface;
006⫶use Psr\Log\LoggerAwareTrait;
007⫶use Symfony\Component\Notifier\Channel\ChannelInterface;
008⫶use Symfony\Component\Notifier\Notification\Notification;
009⫶use Symfony\Component\Notifier\Recipient\RecipientInterface;
010⫶
011⫶class LogChannel implements ChannelInterface, LoggerAwareInterface
012⫶{
013⫶ use LoggerAwareTrait;
014⫶
015⫶ public function notify(Notification $notification, RecipientInterface $recipient, ?string $transportName = null): void
016⫶ {
017⫶ if (isset($this->logger)) {
018⫶ $this->logger->info($notification->getSubject(), [
019⫶ 'class' => get_class($notification),
020⫶ 'importance' => $notification->getImportance(),
021⫶ 'content' => $notification->getContent(),
022⫶ ]);
023⫶ }
024⫶ }
025⫶
026⫶ public function supports(Notification $notification, RecipientInterface $recipient): bool
027⫶ {
028⫶ return true;
029⫶ }
030⫶}

Download colorized diff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant