From b323ddae0597cb66be4b9748d245a0188a45379f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 28 Dec 2021 19:40:38 +0100 Subject: [PATCH] fix loading of unread addressees in notification --- .../ChillMainBundle/Entity/Notification.php | 40 +++++-- .../Tests/Entity/NotificationTest.php | 102 +++++++++++++++++- .../migrations/Version20211228183221.php | 34 ++++++ 3 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/migrations/Version20211228183221.php diff --git a/src/Bundle/ChillMainBundle/Entity/Notification.php b/src/Bundle/ChillMainBundle/Entity/Notification.php index b50b9de53..1fa4e668e 100644 --- a/src/Bundle/ChillMainBundle/Entity/Notification.php +++ b/src/Bundle/ChillMainBundle/Entity/Notification.php @@ -20,19 +20,21 @@ use Doctrine\ORM\Mapping as ORM; * @ORM\Entity * @ORM\Table( * name="chill_main_notification", - * uniqueConstraints={ - * @ORM\UniqueConstraint(columns={"relatedEntityClass", "relatedEntityId"}) - * } * ) + * @ORM\HasLifecycleCallbacks */ class Notification { + private array $addedAddresses = []; + /** * @ORM\ManyToMany(targetEntity=User::class) * @ORM\JoinTable(name="chill_main_notification_addresses_user") */ private Collection $addressees; + private ?ArrayCollection $addressesOnLoad = null; + /** * @ORM\Column(type="datetime_immutable") */ @@ -60,6 +62,8 @@ class Notification */ private int $relatedEntityId; + private array $removedAddresses = []; + /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(nullable=false) @@ -83,7 +87,7 @@ class Notification { if (!$this->addressees->contains($addressee)) { $this->addressees[] = $addressee; - $this->addUnreadBy($addressee); + $this->addedAddresses[] = $addressee; } return $this; @@ -103,6 +107,11 @@ class Notification */ public function getAddressees(): Collection { + // keep a copy to compute changes later + if (null === $this->addressesOnLoad) { + $this->addressesOnLoad = new ArrayCollection($this->addressees->toArray()); + } + return $this->addressees; } @@ -156,10 +165,29 @@ class Notification return $this->addUnreadBy($user); } + /** + * @ORM\PreFlush + */ + public function registerUnread() + { + foreach ($this->addedAddresses as $addressee) { + $this->addUnreadBy($addressee); + } + + if (null !== $this->addressesOnLoad) { + foreach ($this->addressees as $existingAddresse) { + if (!$this->addressesOnLoad->contains($existingAddresse)) { + $this->addUnreadBy($existingAddresse); + } + } + } + } + public function removeAddressee(User $addressee): self { - $this->addressees->removeElement($addressee); - $this->removeUnreadBy($addressee); + if ($this->addressees->removeElement($addressee)) { + $this->removedAddresses[] = $addressee; + } return $this; } diff --git a/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php b/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php index 9be00dde3..6343800d5 100644 --- a/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php @@ -1,23 +1,117 @@ get(EntityManagerInterface::class); + + foreach ($this->toDelete as [$className, $id]) { + $object = $em->find($className, $id); + $em->remove($object); + } + + $em->flush(); + } + + public function generateNotificationData() + { + self::bootKernel(); + $userRepository = self::$container->get(UserRepository::class); + + $senderId = $userRepository + ->findOneBy(['username' => 'center b_social']) + ->getId(); + + $addressesIds = []; + $addressesIds[] = $userRepository + ->findOneBy(['username' => 'center b_direction']) + ->getId(); + + yield [ + $senderId, + $addressesIds, + ]; + } + public function testAddAddresseeStoreAnUread() { $notification = new Notification(); $notification->addAddressee($user1 = new User()); $notification->addAddressee($user2 = new User()); + $notification->getAddressees()->add($user3 = new User()); - $this->assertCount(2, $notification->getAddressees()); - $this->assertCount(2, $notification->getUnreadBy()); + $this->assertCount(3, $notification->getAddressees()); + + // launch listener + $notification->registerUnread(); + $this->assertCount(3, $notification->getUnreadBy()); $this->assertContains($user1, $notification->getUnreadBy()->toArray()); $this->assertContains($user2, $notification->getUnreadBy()->toArray()); + $this->assertContains($user3, $notification->getUnreadBy()->toArray()); } + /** + * @dataProvider generateNotificationData + */ + public function testPrePersistComputeUnread(int $senderId, array $addressesIds) + { + $em = self::$container->get(EntityManagerInterface::class); + $notification = new Notification(); + $notification + ->setSender($em->find(User::class, $senderId)) + ->setRelatedEntityId(0) + ->setRelatedEntityClass(AccompanyingPeriod::class) + ->setMessage('Fake message'); + + foreach ($addressesIds as $addresseeId) { + $notification + ->getAddressees()->add($em->find(User::class, $addresseeId)); + } + + $em->persist($notification); + $em->flush(); + $em->refresh($notification); + + $this->toDelete[] = [Notification::class, $notification->getId()]; + + $this->assertEquals($senderId, $notification->getSender()->getId()); + $this->assertCount(count($addressesIds), $notification->getUnreadBy()); + + $unreadIds = $notification->getUnreadBy()->map(static function (User $u) { return $u->getId(); }); + + foreach ($addressesIds as $addresseeId) { + $this->assertContains($addresseeId, $unreadIds); + } + } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211228183221.php b/src/Bundle/ChillMainBundle/migrations/Version20211228183221.php new file mode 100644 index 000000000..b74579959 --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20211228183221.php @@ -0,0 +1,34 @@ +addSql('create unique index uniq_5bdc8067567988b4440f6072 + on chill_main_notification (relatedentityclass, relatedentityid)'); + } + + public function getDescription(): string + { + return 'remove unique index which prevent to notify twice an entity'; + } + + public function up(Schema $schema): void + { + $this->addSql('DROP INDEX uniq_5bdc8067567988b4440f6072'); + } +}