Skip to content

Commit

Permalink
IBX-8736: Allowed to sent user notification via symfony/notifier (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamwojs authored Nov 23, 2024
1 parent 8e90d28 commit ac7528a
Show file tree
Hide file tree
Showing 14 changed files with 553 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/bundle/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ imports:
- { resource: services/mappers.yaml }
- { resource: services/papi.yaml }
- { resource: services/subscription_resolver.yaml }
- { resource: services/system_notifications.yaml }
16 changes: 16 additions & 0 deletions src/bundle/Resources/config/services/system_notifications.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

Ibexa\Notifications\SystemNotification\SystemNotificationChannel:
tags:
- name: notifier.channel
channel: ibexa

Ibexa\Notifications\SystemNotification\SystemNotificationRenderer:
tags:
- name: ibexa.notification.renderer
alias: system

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% extends '@ibexadesign/account/notifications/list_item.html.twig' %}

{% trans_default_domain 'ibexa_notification' %}

{% block icon %}
{% set icon = icon|default('info') %}
<span class="type__icon">
<svg class="ibexa-icon ibexa-icon--{{ icon }}">
<use xlink:href="{{ ibexa_icon_path(icon) }}"></use>
</svg>
</span>
{% endblock %}

{% block notification_type %}
<span class="type__text">
{{ subject|default('') }}
</span>
{% endblock %}

{% block message %}
{% embed '@ibexadesign/ui/component/table/table_body_cell.html.twig' with { class: 'ibexa-notifications-modal__description' } %}
{% block content %}
<p class="description__text">{{ content|default('') }}</p>
{% endblock %}
{% endembed %}
{% endblock %}
97 changes: 97 additions & 0 deletions src/contracts/SystemNotification/SystemMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Notifications\SystemNotification;

use Ibexa\Contracts\Core\Repository\Values\User\UserReference;
use Symfony\Component\Notifier\Message\MessageInterface;
use Symfony\Component\Notifier\Message\MessageOptionsInterface;

final class SystemMessage implements MessageInterface
{
public const DEFAULT_TYPE = 'system';

private UserReference $user;

private string $type = self::DEFAULT_TYPE;

/** @var array<string, mixed> */
private array $context;

private string $subject = '';

/**
* @param array<string, mixed> $context
*/
public function __construct(UserReference $user, array $context = [])
{
$this->user = $user;
$this->context = $context;
}

public function getUser(): UserReference
{
return $this->user;
}

public function setUser(UserReference $user): void
{
$this->user = $user;
}

public function getRecipientId(): ?string
{
return (string) $this->user->getUserId();
}

public function getSubject(): string
{
return $this->subject;
}

public function setSubject(string $subject): void
{
$this->subject = $subject;
}

public function getTransport(): ?string
{
return null;
}

public function getOptions(): ?MessageOptionsInterface
{
return null;
}

/**
* @return array<string, mixed>
*/
public function getContext(): array
{
return $this->context;
}

/**
* @param array<string, mixed> $context
*/
public function setContext(array $context): void
{
$this->context = $context;
}

public function getType(): string
{
return $this->type;
}

public function setType(string $type): void
{
$this->type = $type;
}
}
64 changes: 64 additions & 0 deletions src/contracts/SystemNotification/SystemNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Notifications\SystemNotification;

use Ibexa\Contracts\Notifications\Value\Recipent\UserRecipientInterface;
use Ibexa\Core\MVC\Symfony\Routing\RouteReference;
use Symfony\Component\Notifier\Notification\Notification;

final class SystemNotification extends Notification implements SystemNotificationInterface
{
private ?string $icon = null;

private ?RouteReference $route = null;

public function getIcon(): ?string
{
return $this->icon;
}

public function setIcon(?string $icon): void
{
$this->icon = $icon;
}

public function getRoute(): ?RouteReference
{
return $this->route;
}

public function setRoute(?RouteReference $route): void
{
$this->route = $route;
}

public function setContent(string $content): void
{
$this->content($content);
}

public function asSystemNotification(UserRecipientInterface $recipient, ?string $transport = null): SystemMessage
{
$context = [
'subject' => $this->getSubject(),
'content' => $this->getContent(),
];

if ($this->icon !== null) {
$context['icon'] = $this->icon;
}

if ($this->route !== null) {
$context['route_name'] = $this->route->getRoute();
$context['route_params'] = $this->route->getParams();
}

return new SystemMessage($recipient->getUser(), $context);
}
}
19 changes: 19 additions & 0 deletions src/contracts/SystemNotification/SystemNotificationInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Notifications\SystemNotification;

use Ibexa\Contracts\Notifications\Value\Recipent\UserRecipientInterface;

interface SystemNotificationInterface
{
public function asSystemNotification(
UserRecipientInterface $recipient,
?string $transport = null
): ?SystemMessage;
}
8 changes: 7 additions & 1 deletion src/contracts/Value/Recipent/UserRecipient.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
namespace Ibexa\Contracts\Notifications\Value\Recipent;

use Ibexa\Contracts\Core\Repository\Values\User\User;
use Ibexa\Contracts\Core\Repository\Values\User\UserReference;
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;

final class UserRecipient implements EmailRecipientInterface
final class UserRecipient implements EmailRecipientInterface, UserRecipientInterface
{
private User $user;

Expand All @@ -24,4 +25,9 @@ public function getEmail(): string
{
return $this->user->email;
}

public function getUser(): UserReference
{
return $this->user;
}
}
17 changes: 17 additions & 0 deletions src/contracts/Value/Recipent/UserRecipientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Notifications\Value\Recipent;

use Ibexa\Contracts\Core\Repository\Values\User\UserReference;
use Symfony\Component\Notifier\Recipient\RecipientInterface;

interface UserRecipientInterface extends RecipientInterface
{
public function getUser(): UserReference;
}
63 changes: 63 additions & 0 deletions src/lib/SystemNotification/SystemNotificationChannel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Notifications\SystemNotification;

use Ibexa\Contracts\Core\Repository\NotificationService;
use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Contracts\Core\Repository\Values\Notification\CreateStruct;
use Ibexa\Contracts\Notifications\SystemNotification\SystemNotificationInterface;
use Ibexa\Contracts\Notifications\Value\Recipent\UserRecipientInterface;
use Symfony\Component\Notifier\Channel\ChannelInterface;
use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\Recipient\RecipientInterface;
use Throwable;

final class SystemNotificationChannel implements ChannelInterface
{
private Repository $repository;

private NotificationService $notificationService;

public function __construct(Repository $repository, NotificationService $notificationService)
{
$this->repository = $repository;
$this->notificationService = $notificationService;
}

/**
* @param \Symfony\Component\Notifier\Notification\Notification&\Ibexa\Contracts\Notifications\SystemNotification\SystemNotificationInterface $notification
* @param \Ibexa\Contracts\Notifications\Value\Recipent\UserRecipientInterface $recipient
*/
public function notify(Notification $notification, RecipientInterface $recipient, ?string $transportName = null): void
{
$message = $notification->asSystemNotification($recipient, $transportName);
if ($message === null) {
return;
}

$createStruct = new CreateStruct();
$createStruct->ownerId = $message->getUser()->getUserId();
$createStruct->type = $message->getType();
$createStruct->data = $message->getContext();

$this->repository->beginTransaction();
try {
$this->notificationService->createNotification($createStruct);
$this->repository->commit();
} catch (Throwable $e) {
$this->repository->rollback();
throw $e;
}
}

public function supports(Notification $notification, RecipientInterface $recipient): bool
{
return $notification instanceof SystemNotificationInterface && $recipient instanceof UserRecipientInterface;
}
}
59 changes: 59 additions & 0 deletions src/lib/SystemNotification/SystemNotificationRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Notifications\SystemNotification;

use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;
use Ibexa\Core\Notification\Renderer\NotificationRenderer;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Twig\Environment;

final class SystemNotificationRenderer implements NotificationRenderer
{
private const KEY_ICON = 'icon';
private const KEY_ROUTE_NAME = 'route_name';
private const KEY_ROUTE_PARAMS = 'route_params';
private const KEY_CONTENT = 'content';
private const KEY_SUBJECT = 'subject';

private Environment $twig;

private UrlGeneratorInterface $urlGenerator;

public function __construct(Environment $twig, UrlGeneratorInterface $urlGenerator)
{
$this->twig = $twig;
$this->urlGenerator = $urlGenerator;
}

public function render(Notification $notification): string
{
return $this->twig->render(
'@ibexadesign/notification/system_notification.html.twig',
[
'notification' => $notification,
'icon' => $notification->data[self::KEY_ICON] ?? null,
'content' => $notification->data[self::KEY_CONTENT] ?? null,
'subject' => $notification->data[self::KEY_SUBJECT] ?? null,
'created_at' => $notification->created,
]
);
}

public function generateUrl(Notification $notification): ?string
{
if (!isset($notification->data[self::KEY_ROUTE_NAME])) {
return null;
}

return $this->urlGenerator->generate(
$notification->data[self::KEY_ROUTE_NAME],
$notification->data[self::KEY_ROUTE_PARAMS] ?? []
);
}
}
Empty file removed tests/integration/.gitkeep
Empty file.
Loading

0 comments on commit ac7528a

Please sign in to comment.