feat(core) : move notification into core and expose notifier contract
This commit is contained in:
@@ -68,3 +68,5 @@ services:
|
||||
App\Service\Share\FileSource: '@App\Service\Share\SmbFileSource'
|
||||
|
||||
App\Module\Core\Domain\Repository\UserRepositoryInterface: '@App\Module\Core\Infrastructure\Doctrine\DoctrineUserRepository'
|
||||
|
||||
App\Shared\Domain\Contract\NotifierInterface: '@App\Module\Core\Infrastructure\Notifier'
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\NotificationRepository;
|
||||
use App\Module\Core\Infrastructure\Doctrine\DoctrineNotificationRepository;
|
||||
use App\Shared\Domain\Contract\UserInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -14,7 +14,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
class MarkAllReadController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly NotificationRepository $notificationRepository,
|
||||
private readonly DoctrineNotificationRepository $notificationRepository,
|
||||
) {}
|
||||
|
||||
#[Route('/api/notifications/mark-all-read', name: 'notification_mark_all_read', methods: ['POST'], priority: 1)]
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\NotificationRepository;
|
||||
use App\Module\Core\Infrastructure\Doctrine\DoctrineNotificationRepository;
|
||||
use App\Shared\Domain\Contract\UserInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
@@ -14,7 +14,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
class NotificationUnreadCountController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly NotificationRepository $notificationRepository,
|
||||
private readonly DoctrineNotificationRepository $notificationRepository,
|
||||
) {}
|
||||
|
||||
#[Route('/api/notifications/unread-count', name: 'notification_unread_count', methods: ['GET'], priority: 1)]
|
||||
|
||||
@@ -4,10 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\EventListener;
|
||||
|
||||
use App\Entity\Notification;
|
||||
use App\Entity\Task;
|
||||
use App\Shared\Domain\Contract\NotifierInterface;
|
||||
use App\Shared\Domain\Contract\UserInterface;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
|
||||
use Doctrine\ORM\Event\OnFlushEventArgs;
|
||||
use Doctrine\ORM\Event\PostFlushEventArgs;
|
||||
@@ -21,7 +20,10 @@ final class TaskNotificationListener
|
||||
/** @var list<array{user: UserInterface, type: string, task: Task}> */
|
||||
private array $pending = [];
|
||||
|
||||
public function __construct(private readonly Security $security) {}
|
||||
public function __construct(
|
||||
private readonly Security $security,
|
||||
private readonly NotifierInterface $notifier,
|
||||
) {}
|
||||
|
||||
public function onFlush(OnFlushEventArgs $args): void
|
||||
{
|
||||
@@ -84,25 +86,10 @@ final class TaskNotificationListener
|
||||
$pending = $this->pending;
|
||||
$this->pending = [];
|
||||
|
||||
$em = $args->getObjectManager();
|
||||
foreach ($pending as $item) {
|
||||
$em->persist($this->buildNotification($item['user'], $item['type'], $item['task']));
|
||||
[$title, $message] = $this->render($item['type'], $item['task']);
|
||||
$this->notifier->notify($item['user'], $item['type'], $title, $message);
|
||||
}
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
private function buildNotification(UserInterface $user, string $type, Task $task): Notification
|
||||
{
|
||||
[$title, $message] = $this->render($type, $task);
|
||||
|
||||
$notification = new Notification();
|
||||
$notification->setUser($user);
|
||||
$notification->setType($type);
|
||||
$notification->setTitle($title);
|
||||
$notification->setMessage($message);
|
||||
$notification->setCreatedAt(new DateTimeImmutable());
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
namespace App\Module\Core\Domain\Entity;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use App\Repository\NotificationRepository;
|
||||
use App\Module\Core\Infrastructure\ApiPlatform\State\NotificationProvider;
|
||||
use App\Module\Core\Infrastructure\Doctrine\DoctrineNotificationRepository;
|
||||
use App\Shared\Domain\Contract\UserInterface;
|
||||
use App\State\NotificationProvider;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
@@ -29,7 +29,7 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
denormalizationContext: ['groups' => ['notification:write']],
|
||||
order: ['createdAt' => 'DESC'],
|
||||
)]
|
||||
#[ORM\Entity(repositoryClass: NotificationRepository::class)]
|
||||
#[ORM\Entity(repositoryClass: DoctrineNotificationRepository::class)]
|
||||
#[ORM\Index(columns: ['user_id'], name: 'idx_notification_user')]
|
||||
#[ORM\Index(columns: ['user_id', 'is_read'], name: 'idx_notification_user_read')]
|
||||
class Notification
|
||||
+4
-4
@@ -2,14 +2,14 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\State;
|
||||
namespace App\Module\Core\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\Pagination\Pagination;
|
||||
use ApiPlatform\State\Pagination\TraversablePaginator;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Entity\Notification;
|
||||
use App\Repository\NotificationRepository;
|
||||
use App\Module\Core\Domain\Entity\Notification;
|
||||
use App\Module\Core\Infrastructure\Doctrine\DoctrineNotificationRepository;
|
||||
use ArrayIterator;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
@@ -23,7 +23,7 @@ final readonly class NotificationProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private Security $security,
|
||||
private NotificationRepository $notificationRepository,
|
||||
private DoctrineNotificationRepository $notificationRepository,
|
||||
private Pagination $pagination,
|
||||
) {}
|
||||
|
||||
+3
-3
@@ -2,9 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
namespace App\Module\Core\Infrastructure\Doctrine;
|
||||
|
||||
use App\Entity\Notification;
|
||||
use App\Module\Core\Domain\Entity\Notification;
|
||||
use App\Shared\Domain\Contract\UserInterface as SharedUserInterface;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
@@ -14,7 +14,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Notification>
|
||||
*/
|
||||
class NotificationRepository extends ServiceEntityRepository
|
||||
class DoctrineNotificationRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Infrastructure;
|
||||
|
||||
use App\Module\Core\Domain\Entity\Notification;
|
||||
use App\Shared\Domain\Contract\NotifierInterface;
|
||||
use App\Shared\Domain\Contract\UserInterface;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
final readonly class Notifier implements NotifierInterface
|
||||
{
|
||||
public function __construct(private EntityManagerInterface $em) {}
|
||||
|
||||
public function notify(UserInterface $user, string $type, string $title, string $message): void
|
||||
{
|
||||
$notification = new Notification();
|
||||
$notification->setUser($user);
|
||||
$notification->setType($type);
|
||||
$notification->setTitle($title);
|
||||
$notification->setMessage($message);
|
||||
$notification->setCreatedAt(new DateTimeImmutable());
|
||||
|
||||
$this->em->persist($notification);
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace App\Tests\Functional\EventListener;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Task;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Repository\NotificationRepository;
|
||||
use App\Module\Core\Infrastructure\Doctrine\DoctrineNotificationRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
@@ -19,7 +19,7 @@ use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
class TaskNotificationListenerTest extends KernelTestCase
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
private NotificationRepository $notifications;
|
||||
private DoctrineNotificationRepository $notifications;
|
||||
private TokenStorageInterface $tokenStorage;
|
||||
private Project $project;
|
||||
private User $actor;
|
||||
@@ -31,7 +31,7 @@ class TaskNotificationListenerTest extends KernelTestCase
|
||||
self::bootKernel();
|
||||
$c = self::getContainer();
|
||||
$this->em = $c->get(EntityManagerInterface::class);
|
||||
$this->notifications = $c->get(NotificationRepository::class);
|
||||
$this->notifications = $c->get(DoctrineNotificationRepository::class);
|
||||
$this->tokenStorage = $c->get(TokenStorageInterface::class);
|
||||
|
||||
$project = $this->em->getRepository(Project::class)->findOneBy([]);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Functional\Module\Core;
|
||||
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Shared\Domain\Contract\NotifierInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class NotifierTest extends KernelTestCase
|
||||
{
|
||||
public function testNotifyPersistsANotificationForTheUser(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
$notifier = self::getContainer()->get(NotifierInterface::class);
|
||||
|
||||
$user = $em->getRepository(User::class)->findOneBy(['username' => 'alice']);
|
||||
self::assertNotNull($user);
|
||||
|
||||
$title = 'Titre-'.uniqid('', true);
|
||||
$notifier->notify($user, 'task_assigned', $title, 'Message');
|
||||
|
||||
$count = (int) $em->createQuery(
|
||||
'SELECT COUNT(n.id) FROM App\Module\Core\Domain\Entity\Notification n WHERE n.user = :u AND n.title = :t'
|
||||
)->setParameter('u', $user)->setParameter('t', $title)->getSingleScalarResult();
|
||||
|
||||
self::assertSame(1, $count);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user