Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
27 / 27 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
1 / 1 |
| NotificationPreferenceRepository | |
100.00% |
27 / 27 |
|
100.00% |
4 / 4 |
6 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getByUserId | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
| upsert | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
| getEnabledRecipientsForAdminType | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace App\Domain\Notification\Repository; |
| 6 | |
| 7 | use App\Domain\Notification\Data\NotificationPreference; |
| 8 | use App\Domain\Notification\Data\NotificationType; |
| 9 | use PDO; |
| 10 | |
| 11 | /** |
| 12 | * PDO-backed access to the notification_preferences table. |
| 13 | * |
| 14 | * Recipient resolution for a given notification type goes through |
| 15 | * {@see getEnabledRecipientsForAdminType()} — which joins users to filter |
| 16 | * by role. Investor-targeted types will get their own resolver method |
| 17 | * once those types are added. |
| 18 | */ |
| 19 | final class NotificationPreferenceRepository implements NotificationPreferenceRepositoryInterface |
| 20 | { |
| 21 | public function __construct( |
| 22 | private readonly PDO $pdo, |
| 23 | ) {} |
| 24 | |
| 25 | /** |
| 26 | * @param int $userId |
| 27 | * @return list<NotificationPreference> |
| 28 | */ |
| 29 | public function getByUserId(int $userId): array |
| 30 | { |
| 31 | $sql = ' |
| 32 | SELECT |
| 33 | preference_id AS "preferenceId", |
| 34 | user_id AS "userId", |
| 35 | notification_type AS "notificationType", |
| 36 | channel, |
| 37 | enabled, |
| 38 | created_at AS "createdAt", |
| 39 | updated_at AS "updatedAt" |
| 40 | FROM notification_preferences |
| 41 | WHERE user_id = :user_id |
| 42 | ORDER BY notification_type |
| 43 | '; |
| 44 | |
| 45 | $stmt = $this->pdo->prepare($sql); |
| 46 | $stmt->execute(['user_id' => $userId]); |
| 47 | |
| 48 | $rows = []; |
| 49 | /** @var array<string, mixed> $row */ |
| 50 | foreach ($stmt->fetchAll() as $row) { |
| 51 | $rows[] = new NotificationPreference($row); |
| 52 | } |
| 53 | |
| 54 | return $rows; |
| 55 | } |
| 56 | |
| 57 | /** |
| 58 | * Insert or update a single preference. UPSERT keyed on the unique |
| 59 | * (user_id, notification_type, channel) combination. |
| 60 | * @param int $userId |
| 61 | * @param string $notificationType |
| 62 | * @param string $channel |
| 63 | * @param bool $enabled |
| 64 | */ |
| 65 | public function upsert(int $userId, string $notificationType, string $channel, bool $enabled): void |
| 66 | { |
| 67 | $sql = ' |
| 68 | INSERT INTO notification_preferences (user_id, notification_type, channel, enabled) |
| 69 | VALUES (:user_id, :notification_type, :channel, :enabled) |
| 70 | ON CONFLICT (user_id, notification_type, channel) |
| 71 | DO UPDATE SET |
| 72 | enabled = EXCLUDED.enabled, |
| 73 | updated_at = CURRENT_TIMESTAMP |
| 74 | '; |
| 75 | |
| 76 | $stmt = $this->pdo->prepare($sql); |
| 77 | $stmt->execute([ |
| 78 | 'user_id' => $userId, |
| 79 | 'notification_type' => $notificationType, |
| 80 | 'channel' => $channel, |
| 81 | 'enabled' => $enabled ? 't' : 'f', |
| 82 | ]); |
| 83 | } |
| 84 | |
| 85 | /** |
| 86 | * Return the email addresses of admin / super_admin users who have |
| 87 | * opted into the given admin notification type. |
| 88 | * |
| 89 | * @param string $notificationType |
| 90 | * @return list<string> |
| 91 | */ |
| 92 | public function getEnabledRecipientsForAdminType(string $notificationType): array |
| 93 | { |
| 94 | $sql = ' |
| 95 | SELECT u.email |
| 96 | FROM notification_preferences np |
| 97 | JOIN users u ON u.user_id = np.user_id |
| 98 | WHERE np.notification_type = :notification_type |
| 99 | AND np.channel = :channel |
| 100 | AND np.enabled = TRUE |
| 101 | AND u.is_active = TRUE |
| 102 | AND u.role IN (\'admin\', \'super_admin\') |
| 103 | '; |
| 104 | |
| 105 | $stmt = $this->pdo->prepare($sql); |
| 106 | $stmt->execute([ |
| 107 | 'notification_type' => $notificationType, |
| 108 | 'channel' => NotificationType::CHANNEL_EMAIL, |
| 109 | ]); |
| 110 | |
| 111 | /** @var list<string> $emails */ |
| 112 | $emails = $stmt->fetchAll(PDO::FETCH_COLUMN); |
| 113 | |
| 114 | return $emails; |
| 115 | } |
| 116 | } |