Administrator > User > all */ public function getAuthorizedRecipients($user) { $recipients = ['all']; if ($user->hasRole('Developer')) { return ['Developer', 'Administrator', 'User', 'all']; } if ($user->hasRole('Administrator')) { return ['Administrator', 'User', 'all']; } // Default: only see notifications for 'User' and 'all' return ['User', 'all']; } /** * Get ALL notifications for a user based on their roles, * BUT exclude those they have personally deleted/hidden. */ public function getActiveNotificationsForUser($user, $offset = 0, $limit = 10) { $query = $this->model->query(); // 1. Filter by roles (Broadcast targeting) hierarchical $authorizedRecipients = $this->getAuthorizedRecipients($user); $query->whereIn('recipient', $authorizedRecipients); // 2. Left Join personal interactions $query->leftJoin('system_notification_user', function ($join) use ($user) { $join->on('system_notifications.id', '=', 'system_notification_user.notification_id') ->where('system_notification_user.user_id', '=', $user->id); }); // 3. Exclude personally deleted ones $query->whereNull('system_notification_user.deleted_at'); // 4. Select needed columns (avoiding ID collision with Join) return $query->select('system_notifications.*', 'system_notification_user.read_at as personal_read_at') ->latest('system_notifications.created_at') ->skip($offset) ->take($limit) ->get(); } /** * Get personal unread count. */ public function getUnreadCount($user) { $query = $this->model->query(); // Target filtering hierarchical $authorizedRecipients = $this->getAuthorizedRecipients($user); $query->whereIn('recipient', $authorizedRecipients); // Join to check read/deleted status $query->leftJoin('system_notification_user', function ($join) use ($user) { $join->on('system_notifications.id', '=', 'system_notification_user.notification_id') ->where('system_notification_user.user_id', '=', $user->id); }); // Unread = (Global read_at is null AND Personal read_at is null) AND not deleted $query->whereNull('system_notification_user.read_at') ->whereNull('system_notification_user.deleted_at'); return $query->count(); } /** * Personal Mark As Read */ public function markAsRead($notificationId, $userId) { \DB::table('system_notification_user')->updateOrInsert( ['notification_id' => $notificationId, 'user_id' => $userId], ['read_at' => now(), 'updated_at' => now()] ); } /** * Personal Delete (Hide) */ public function personalDelete($notificationId, $userId) { \DB::table('system_notification_user')->updateOrInsert( ['notification_id' => $notificationId, 'user_id' => $userId], ['deleted_at' => now(), 'updated_at' => now()] ); } /** * Mark ALL visible notifications as read for this user. */ public function markAllAsReadForUser($user) { $authorizedRecipients = $this->getAuthorizedRecipients($user); // 1. Get IDs of notifications that are visible to user but either: // - Have no entry in pivot (meaning unread) // - Have an entry with read_at IS NULL and deleted_at IS NULL $unreadIds = $this->model->query() ->whereIn('recipient', $authorizedRecipients) ->leftJoin('system_notification_user', function ($join) use ($user) { $join->on('system_notifications.id', '=', 'system_notification_user.notification_id') ->where('system_notification_user.user_id', '=', $user->id); }) ->whereNull('system_notification_user.read_at') ->whereNull('system_notification_user.deleted_at') ->pluck('system_notifications.id'); if ($unreadIds->isEmpty()) { return; } // 2. Perform batch updateOrInsert for each (or just loop if small, but let's stick to markAsRead helper) foreach ($unreadIds as $id) { $this->markAsRead($id, $user->id); } } }