withServiceAccount($firebaseServiceAccount); $this->messaging = $factory->createMessaging(); $this->db = $dbConnection; } /** * Envoie une notification à un utilisateur pour un nouveau message */ public function sendMessageNotification($userId, $messageId, $senderId, $content, $conversationId) { try { // Récupérer les préférences de notification de l'utilisateur $settings = $this->getUserNotificationSettings($userId); if (!$settings['enable_notifications']) { return ['status' => 'skipped', 'reason' => 'notifications_disabled']; } // Vérifier si la conversation est en silencieux if (in_array($conversationId, $settings['muted_conversations'])) { return ['status' => 'skipped', 'reason' => 'conversation_muted']; } // Vérifier le mode Ne pas déranger if ($this->isInDoNotDisturbPeriod($settings)) { return ['status' => 'skipped', 'reason' => 'do_not_disturb']; } // Obtenir le token du device $deviceToken = $this->getUserDeviceToken($userId); if (!$deviceToken) { return ['status' => 'error', 'reason' => 'no_device_token']; } // Obtenir les informations de l'expéditeur $sender = $this->getSenderInfo($senderId); // Obtenir le nom de la conversation $conversationName = $this->getConversationName($conversationId, $userId); // Préparation du contenu de la notification $title = $conversationName ?? $sender['name']; $body = $settings['show_preview'] ? $content : 'Nouveau message'; // Créer le message Firebase $message = CloudMessage::withTarget('token', $deviceToken) ->withNotification(Notification::create($title, $body)) ->withData([ 'type' => 'chat_message', 'messageId' => $messageId, 'conversationId' => $conversationId, 'senderId' => $senderId, 'click_action' => 'FLUTTER_NOTIFICATION_CLICK', ]) ->withAndroidConfig([ 'priority' => 'high', 'notification' => [ 'sound' => $settings['sound_enabled'] ? 'default' : null, 'channel_id' => 'chat_messages', 'icon' => 'ic_launcher', ], ]) ->withApnsConfig([ 'payload' => [ 'aps' => [ 'sound' => $settings['sound_enabled'] ? 'default' : null, 'badge' => 1, // TODO: Calculer le nombre réel de messages non lus ], ], ]); // Envoyer la notification $result = $this->messaging->send($message); // Enregistrer la notification dans la base de données $this->saveNotificationToDatabase($userId, $messageId, $conversationId, $title, $body); return [ 'status' => 'success', 'message_id' => $result, ]; } catch (Exception $e) { return [ 'status' => 'error', 'reason' => $e->getMessage(), ]; } } /** * Envoie une notification de type broadcast */ public function sendBroadcastNotification($audienceTargets, $messageId, $content, $conversationId) { $results = []; // Résoudre les cibles d'audience $userIds = $this->resolveAudienceTargets($audienceTargets); foreach ($userIds as $userId) { $result = $this->sendMessageNotification($userId, $messageId, null, $content, $conversationId); $results[$userId] = $result; } return $results; } /** * Enregistre la notification dans la base de données */ private function saveNotificationToDatabase($userId, $messageId, $conversationId, $title, $body) { $stmt = $this->db->prepare(" INSERT INTO chat_notifications (fk_user, fk_message, fk_room, type, contenu, statut) VALUES (?, ?, ?, 'chat_message', ?, 'non_lue') "); $stmt->execute([$userId, $messageId, $conversationId, json_encode([ 'title' => $title, 'body' => $body, ])]); } /** * Récupère les préférences de notification de l'utilisateur */ private function getUserNotificationSettings($userId) { // Implémenter la logique pour récupérer les paramètres return [ 'enable_notifications' => true, 'sound_enabled' => true, 'vibration_enabled' => true, 'muted_conversations' => [], 'show_preview' => true, 'do_not_disturb' => false, 'do_not_disturb_start' => null, 'do_not_disturb_end' => null, ]; } /** * Vérifie si on est dans la période Ne pas déranger */ private function isInDoNotDisturbPeriod($settings) { if (!$settings['do_not_disturb']) { return false; } $now = new DateTime(); $start = new DateTime($settings['do_not_disturb_start']); $end = new DateTime($settings['do_not_disturb_end']); if ($start < $end) { return $now >= $start && $now <= $end; } else { // Période qui chevauche minuit return $now >= $start || $now <= $end; } } /** * Récupère le token du device de l'utilisateur */ private function getUserDeviceToken($userId) { $stmt = $this->db->prepare(" SELECT device_token FROM notification_settings WHERE user_id = ? AND device_token IS NOT NULL ORDER BY updated_at DESC LIMIT 1 "); $stmt->execute([$userId]); return $stmt->fetchColumn(); } /** * Récupère les informations de l'expéditeur */ private function getSenderInfo($senderId) { $stmt = $this->db->prepare(" SELECT id, name, username FROM users WHERE id = ? "); $stmt->execute([$senderId]); return $stmt->fetch(PDO::FETCH_ASSOC); } /** * Récupère le nom de la conversation */ private function getConversationName($conversationId, $userId) { $stmt = $this->db->prepare(" SELECT title FROM chat_rooms WHERE id = ? "); $stmt->execute([$conversationId]); return $stmt->fetchColumn(); } /** * Résout les cibles d'audience en une liste d'IDs utilisateur */ private function resolveAudienceTargets($targets) { $userIds = []; foreach ($targets as $target) { switch ($target['target_type']) { case 'all': // Récupérer tous les utilisateurs $stmt = $this->db->query("SELECT id FROM users WHERE chk_active = 1"); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; case 'role': // Récupérer les utilisateurs par rôle $stmt = $this->db->prepare("SELECT id FROM users WHERE fk_role = ?"); $stmt->execute([$target['role_filter']]); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; case 'entity': // Récupérer les utilisateurs par entité $stmt = $this->db->prepare("SELECT id FROM users WHERE fk_entite = ?"); $stmt->execute([$target['entity_filter']]); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; case 'combined': // Récupérer les utilisateurs par combinaison de rôle et entité $stmt = $this->db->prepare(" SELECT id FROM users WHERE fk_role = ? AND fk_entite = ? "); $stmt->execute([$target['role_filter'], $target['entity_filter']]); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; } } return array_unique($userIds); } }