fix loading of unread addressees in notification

This commit is contained in:
Julien Fastré 2021-12-28 19:40:38 +01:00
parent d5d64cdf65
commit b323ddae05
3 changed files with 166 additions and 10 deletions

View File

@ -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;
}

View File

@ -1,23 +1,117 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Entity;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\User;
use PHPUnit\Framework\TestCase;
use Chill\MainBundle\Repository\UserRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use function count;
class NotificationTest extends TestCase
/**
* @internal
* @coversNothing
*/
final class NotificationTest extends KernelTestCase
{
private array $toDelete = [];
protected function setUp()
{
self::bootKernel();
}
protected function tearDown(): void
{
$em = self::$container->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);
}
}
}

View File

@ -0,0 +1,34 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\Migrations\Main;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20211228183221 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->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');
}
}