Skip to content

Commit 8414b4a

Browse files
committed
IBX-9060: Added bulk mark-as-read functionality for user notifications
1 parent 566e5ee commit 8414b4a

File tree

17 files changed

+267
-23
lines changed

17 files changed

+267
-23
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41394,12 +41394,6 @@ parameters:
4139441394
count: 1
4139541395
path: tests/integration/Core/Repository/LanguageServiceAuthorizationTest.php
4139641396

41397-
-
41398-
message: '#^Comparison operation "\<" between int\<70400, 80499\> and 50400 is always false\.$#'
41399-
identifier: smaller.alwaysFalse
41400-
count: 1
41401-
path: tests/integration/Core/Repository/LanguageServiceMaximumSupportedLanguagesTest.php
41402-
4140341397
-
4140441398
message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\LanguageServiceMaximumSupportedLanguagesTest\:\:testCreateMaximumLanguageLimit\(\) has no return type specified\.$#'
4140541399
identifier: missingType.return
@@ -41412,12 +41406,6 @@ parameters:
4141241406
count: 1
4141341407
path: tests/integration/Core/Repository/LanguageServiceMaximumSupportedLanguagesTest.php
4141441408

41415-
-
41416-
message: '#^Result of && is always false\.$#'
41417-
identifier: booleanAnd.alwaysFalse
41418-
count: 1
41419-
path: tests/integration/Core/Repository/LanguageServiceMaximumSupportedLanguagesTest.php
41420-
4142141409
-
4142241410
message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) with ''Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Language'' and Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\Language will always evaluate to true\.$#'
4142341411
identifier: method.alreadyNarrowedType

src/contracts/Persistence/Notification/Handler.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ public function createNotification(CreateStruct $createStruct): Notification;
3333
*/
3434
public function updateNotification(APINotification $notification, UpdateStruct $updateStruct): Notification;
3535

36+
/**
37+
* @param int[] $notificationIds
38+
*
39+
* @return int[]
40+
*/
41+
public function bulkUpdateUserNotifications(
42+
int $ownerId,
43+
UpdateStruct $updateStruct,
44+
bool $pendingOnly = false,
45+
array $notificationIds = []
46+
): array;
47+
3648
/**
3749
* Count users unread Notifications.
3850
*

src/contracts/Repository/Decorator/NotificationServiceDecorator.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ public function getNotification(int $notificationId): Notification
4141
return $this->innerService->getNotification($notificationId);
4242
}
4343

44+
/**
45+
* @param int[] $notificationIds
46+
*/
47+
public function markUserNotificationsAsRead(array $notificationIds = []): void
48+
{
49+
$this->innerService->markUserNotificationsAsRead($notificationIds);
50+
}
51+
4452
public function markNotificationAsRead(Notification $notification): void
4553
{
4654
$this->innerService->markNotificationAsRead($notification);

src/contracts/Repository/NotificationService.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public function findNotifications(?NotificationQuery $query = null): Notificatio
3434
*/
3535
public function getNotification(int $notificationId): Notification;
3636

37+
/**
38+
* @param int[] $notificationIds
39+
*/
40+
public function markUserNotificationsAsRead(array $notificationIds = []): void;
41+
3742
/**
3843
* Mark notification as read so it no longer bother the user.
3944
*

src/lib/Persistence/Cache/NotificationHandler.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,37 @@ public function createNotification(CreateStruct $createStruct): Notification
3838
return $this->persistenceHandler->notificationHandler()->createNotification($createStruct);
3939
}
4040

41+
public function bulkUpdateUserNotifications(
42+
int $ownerId,
43+
UpdateStruct $updateStruct,
44+
bool $pendingOnly = false,
45+
array $notificationIds = []
46+
): array {
47+
$this->logger->logCall(__METHOD__, [
48+
'userId' => $ownerId,
49+
'notificationIds' => $notificationIds,
50+
]);
51+
52+
$updatedNotificationIds = $this->persistenceHandler
53+
->notificationHandler()
54+
->bulkUpdateUserNotifications($ownerId, $updateStruct, $pendingOnly, $notificationIds);
55+
56+
$cacheKeys = array_map(
57+
fn (int $id) => $this->cacheIdentifierGenerator->generateKey(self::NOTIFICATION_IDENTIFIER, [$id], true),
58+
$updatedNotificationIds
59+
);
60+
61+
$cacheKeys[] = $this->cacheIdentifierGenerator->generateKey(
62+
self::NOTIFICATION_PENDING_COUNT_IDENTIFIER,
63+
[$ownerId],
64+
true
65+
);
66+
67+
$this->cache->deleteItems($cacheKeys);
68+
69+
return $updatedNotificationIds;
70+
}
71+
4172
/**
4273
* {@inheritdoc}
4374
*/

src/lib/Persistence/Legacy/Notification/Gateway.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ abstract public function getNotificationById(int $notificationId): array;
4242
*/
4343
abstract public function updateNotification(Notification $notification): void;
4444

45+
/**
46+
* @param int[] $notificationIds
47+
*
48+
* @return int[]
49+
*/
50+
abstract public function bulkUpdateUserNotifications(
51+
Notification $notification,
52+
bool $pendingOnly = false,
53+
array $notificationIds = []
54+
): array;
55+
4556
abstract public function countUserNotifications(int $userId, ?NotificationQuery $query = null): int;
4657

4758
/**

src/lib/Persistence/Legacy/Notification/Gateway/DoctrineDatabase.php

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,62 @@ public function getNotificationById(int $notificationId): array
8282
return $query->execute()->fetchAllAssociative();
8383
}
8484

85+
/**
86+
* @param int[] $notificationIds
87+
*
88+
* @return int[]
89+
*/
90+
public function bulkUpdateUserNotifications(
91+
Notification $notification,
92+
bool $pendingOnly = false,
93+
array $notificationIds = []
94+
): array {
95+
if (!is_int($notification->ownerId) || $notification->ownerId <= 0) {
96+
throw new InvalidArgumentException('ownerId', 'Cannot bulk update notifications without valid ownerId');
97+
}
98+
99+
$queryBuilder = $this->connection->createQueryBuilder();
100+
$queryBuilder
101+
->select(self::COLUMN_ID)
102+
->from(self::TABLE_NOTIFICATION)
103+
->andWhere($queryBuilder->expr()->eq(self::COLUMN_OWNER_ID, ':ownerId'))
104+
->setParameter(':ownerId', $notification->ownerId, PDO::PARAM_INT);
105+
106+
if ($pendingOnly) {
107+
$queryBuilder->andWhere($queryBuilder->expr()->eq(self::COLUMN_IS_PENDING, ':isPendingFlag'))
108+
->setParameter(':isPendingFlag', true, PDO::PARAM_BOOL);
109+
}
110+
111+
if (!empty($notificationIds)) {
112+
$queryBuilder->andWhere(
113+
$queryBuilder->expr()->in(
114+
self::COLUMN_ID,
115+
array_map('strval', $notificationIds)
116+
)
117+
);
118+
}
119+
120+
$rows = $queryBuilder->execute()->fetchAllAssociative();
121+
if (empty($rows)) {
122+
return [];
123+
}
124+
125+
$idsToUpdate = array_map('intval', array_column($rows, self::COLUMN_ID));
126+
127+
$updateQuery = $this->connection->createQueryBuilder();
128+
$updateQuery
129+
->update(self::TABLE_NOTIFICATION)
130+
->set(self::COLUMN_IS_PENDING, ':is_pending')
131+
->andWhere(
132+
$updateQuery->expr()->in(self::COLUMN_ID, array_map('strval', $idsToUpdate))
133+
)
134+
->setParameter(':is_pending', $notification->isPending, PDO::PARAM_BOOL);
135+
136+
$updateQuery->execute();
137+
138+
return $idsToUpdate;
139+
}
140+
85141
public function updateNotification(Notification $notification): void
86142
{
87143
if (!isset($notification->id) || !is_numeric($notification->id)) {
@@ -113,7 +169,7 @@ public function countUserNotifications(int $userId, ?NotificationQuery $query =
113169
$this->applyFilters($queryBuilder, $query->getCriteria());
114170
}
115171

116-
return (int)$queryBuilder->execute()->fetchColumn();
172+
return (int)$queryBuilder->execute()->fetchOne();
117173
}
118174

119175
public function countUserPendingNotifications(int $userId): int

src/lib/Persistence/Legacy/Notification/Gateway/ExceptionConversion.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ public function getNotificationById(int $notificationId): array
4444
}
4545
}
4646

47+
public function bulkUpdateUserNotifications(Notification $notification, bool $pendingOnly = false, array $notificationIds = []): array
48+
{
49+
try {
50+
return $this->innerGateway->bulkUpdateUserNotifications($notification, $pendingOnly, $notificationIds);
51+
} catch (DBALException | PDOException $e) {
52+
throw DatabaseException::wrap($e);
53+
}
54+
}
55+
4756
public function updateNotification(Notification $notification): void
4857
{
4958
try {

src/lib/Persistence/Legacy/Notification/Handler.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,18 @@ public function getNotificationById(int $notificationId): Notification
7272
return reset($notification);
7373
}
7474

75+
public function bulkUpdateUserNotifications(
76+
int $ownerId,
77+
UpdateStruct $updateStruct,
78+
bool $pendingOnly = false,
79+
array $notificationIds = []
80+
): array {
81+
$notification = $this->mapper->createNotificationFromUpdateStruct($updateStruct);
82+
$notification->ownerId = $ownerId;
83+
84+
return $this->gateway->bulkUpdateUserNotifications($notification, $pendingOnly, $notificationIds);
85+
}
86+
7587
/**
7688
* {@inheritdoc}
7789
*

src/lib/Repository/NotificationService.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ public function getNotification(int $notificationId): APINotification
109109
return $this->buildDomainObject($notification);
110110
}
111111

112+
/**
113+
* @param int[] $notificationIds
114+
*/
115+
public function markUserNotificationsAsRead(array $notificationIds = []): void
116+
{
117+
$currentUserId = $this->getCurrentUserId();
118+
$updateStruct = new UpdateStruct();
119+
$updateStruct->isPending = false;
120+
121+
$this->persistenceHandler->bulkUpdateUserNotifications($currentUserId, $updateStruct, true, $notificationIds);
122+
}
123+
112124
public function markNotificationAsRead(APINotification $notification): void
113125
{
114126
$currentUserId = $this->getCurrentUserId();

0 commit comments

Comments
 (0)