<?php
namespace App\Service;
use App\Entity\DiscussionGroup;
use App\Entity\Message;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Campaign;
use App\Entity\Mission;
use App\Entity\User;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Twig\Environment;
use Symfony\Component\Security\Core\Security;
use App\Service\MessageService;
/**
* author : anthony@softibox.com
*/
class ChatService
{
private HubInterface $hub;
private EntityManagerInterface $entityManager;
private RouterInterface $router;
private SerializerInterface $serializer;
private $twig;
private $security;
private $messageService;
public function __construct(
HubInterface $hub,
EntityManagerInterface $entityManager,
RouterInterface $router,
SerializerInterface $serializer,
Environment $twig,
Security $security,
MessageService $messageService
)
{
$this->hub = $hub;
$this->entityManager = $entityManager;
$this->router = $router;
$this->serializer = $serializer;
$this->twig = $twig;
$this->security = $security;
$this->messageService = $messageService;
}
public function marqueAllInMissionMessageReadWithGroup($mission,$user,$groupedMessage){
$this->messageService->marqueAllInMissionMessageReadWithGroup(mission: $mission,user: $user,groupedMessage: $groupedMessage);
}
/**
* Publie une notification liée à une campagne via une mission donnée.
*
* Cette méthode récupère une mission spécifique, puis publie des notifications
* associées à toutes les missions de la campagne liée.
*
* @param string $idMission L'identifiant de la mission à partir de laquelle la notification sera publiée.
* @param array|object $message Le message de la notification. Peut être un tableau ou un objet.
*/
public function publishMessageNotificationCampaignHashed(string $idMission, $message,$group = null): void
{
// Récupère l'entité Mission correspondant à l'identifiant fourni.
$mission = $this->entityManager->getRepository(Mission::class)->find($idMission);
// Vérifie que la mission existe et qu'elle est liée à une campagne
if (!$mission || !$mission->getCampaign()) {
throw new \InvalidArgumentException('Mission ou campagne introuvable.');
}
// Parcourt toutes les missions associées à la campagne de la mission initiale.
foreach ($mission->getCampaign()->getMissions() as $mission) {
// Génère l'URL absolue pour la page d'édition de la mission.
$absoluteUrl = !is_null($group) ? $this->router->generate('mission_discussion_group', ['id' => $mission->getId(),'groupId'=>$group->getId()], RouterInterface::ABSOLUTE_URL) : $this->router->generate('mission_edit', ['id' => $mission->getId()], RouterInterface::ABSOLUTE_URL);
$absoluteUrl = DataHasherService::hash($absoluteUrl);
// Si le message est un objet, il est sérialisé avec un groupe de normalisation .
$message = is_object($message)
? $this->serializer->normalize($message, null, [AbstractNormalizer::GROUPS => ['message_read']])
: $message;
$update = new Update(
$absoluteUrl,
json_encode($message)
);
try {
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
// Crée une mise à jour (Update) contenant l'URL et le message encodé en JSON.
// Publie la mise à jour via le hub (messagerie en temps réel ou système de notifications).
}
$update = new Update(
"messageUpdate/{$mission->getCampaign()->getId()}",
'messageUpdated'
);
try {
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
$this->publicOnCampaignUpdate();
}
/**
* Publie une notification à un sujet.
*
* @param string $topic Le sujet auquel la notification est envoyée.
* @param array $message Le message de la notification.
*/
public function publishNotificationMessageUnread(string $topic, array $message): void
{
try {
$update = new Update(
$topic,
json_encode($message)
);
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
}
/**
* Publie une notification liée à une campagne via une mission donnée.
*
* Cette méthode récupère une mission spécifique, puis publie des notifications
* associées à toutes les missions de la campagne liée.
*
* @param string $idMission L'identifiant de la mission à partir de laquelle la notification sera publiée.
* @param array|object $message Le message de la notification. Peut être un tableau ou un objet.
*/
public function publishMessageNotificationCampaign(string $idMission, $message,$group = null): void
{
// Récupère l'entité Mission correspondant à l'identifiant fourni.
$mission = $this->entityManager->getRepository(Mission::class)->find($idMission);
// Vérifie que la mission existe et qu'elle est liée à une campagne
if (!$mission || !$mission->getCampaign()) {
throw new \InvalidArgumentException('Mission ou campagne introuvable.');
}
// Parcourt toutes les missions associées à la campagne de la mission initiale.
foreach ($mission->getCampaign()->getMissions() as $mission) {
// Génère l'URL absolue pour la page d'édition de la mission.
$absoluteUrl = !is_null($group) ? $this->router->generate('mission_discussion_group', ['id' => $mission->getId(),'groupId'=>$group->getId()], RouterInterface::ABSOLUTE_URL) : $this->router->generate('mission_edit', ['id' => $mission->getId()], RouterInterface::ABSOLUTE_URL);
// Si le message est un objet, il est sérialisé avec un groupe de normalisation .
$message = is_object($message)
? $this->serializer->normalize($message, null, [AbstractNormalizer::GROUPS => ['message_read']])
: $message;
$update = new Update(
$absoluteUrl,
json_encode($message)
);
try {
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
// Crée une mise à jour (Update) contenant l'URL et le message encodé en JSON.
// Publie la mise à jour via le hub (messagerie en temps réel ou système de notifications).
}
$update = new Update(
"messageUpdate/{$mission->getCampaign()->getId()}",
'messageUpdated'
);
try {
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
$this->publicOnCampaignUpdate();
}
public function publicOnCampaignUpdate(){
$update = new Update(
"campaignUpdate",
"campaignUpdate"
);
$this->hub->publish($update);
}
public function publishUserDesktopEnterInTchat(Message $message){
$campaignId = $message->getCampaign()->getId();
$message = $this->serializer->normalize($message, null, [AbstractNormalizer::GROUPS => ['message_read']]);
$update = new Update(
"campaign/message-read-in-entered-desktop/$campaignId",
json_encode($message)
);
$this->hub->publish($update);
}
public function publishUserReadMessage(Message $message){
$message->setUserListWhoRead($this->messageService->getBullUsersWhoReadMessageByIds($message));
$campaignId = $message->getCampaign()->getId();
$message = $this->serializer->normalize($message, null, [AbstractNormalizer::GROUPS => ['message_read']]);
;
$update = new Update(
"campaign/message-read/$campaignId",
json_encode($message)
);
$this->hub->publish($update);
}
public function publishUserEnterInDiscussion(Message $message){
$message->setUserListWhoRead($this->messageService->getBullUsersWhoReadMessageByIds($message));
$campaignId = $message->getCampaign()->getId();
$message = $this->serializer->normalize($message, null, [AbstractNormalizer::GROUPS => ['message_read']]);
;
$update = new Update(
"campaign/user-entered-in-discussion/$campaignId",
json_encode($message)
);
try {
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
}
public function publishOnMessagePinned($message){
$update = new Update(
"pinnedMessage/{$message->getCampaign()->getId()}",
$this->serializer->serialize( $message, 'json', ['groups' => 'message_read'])
);
try {
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
}
public function publishOnDiscussionGroupUpdate(string $type, DiscussionGroup $discussionGroup){
$data = [
'group'=>$discussionGroup,
'type'=>$type
];
$update = new Update(
"discussionEditGroup/{$discussionGroup->getCampaign()->getId()}",
$this->serializer->serialize( $data, 'json', ['groups' => 'message_read'])
);
try {
if($this->security->getUser() instanceof User)
$this->hub->publish($update);
} catch (\Throwable $th) {
//throw $th;
}
}
public function getHtmlToRenderInViewForLastMessage(?Mission $mission,$message,$dateOffSetHour)
{
return $this->twig->render("mission/_chat_by_item.html.twig", [
"message" => $message,
"mission" => $mission,
"date_off_setHour" => abs($dateOffSetHour),
'currentUser' => $this->security->getUser()
]);
}
public function getHtmlContentToRenderInViewForLastMessage(?Mission $mission,$message,$dateOffSetHour)
{
return $this->twig->render("mission/_chat_content_by_item.html.twig", [
"message" => $message,
"mission" => $mission,
"date_off_setHour" => abs($dateOffSetHour),
'currentUser' => $this->security->getUser(),
'position'=>0
]);
}
/*
* "planning" => $this->twig->render("mission/_planning_item.html.twig", [
"mission" => $mission,
"campaign" => $mission->getCampaign(),
]),
*/
public function getHtmlToRenderPlanning(?Mission $mission)
{
return $this->twig->render("mission/_planning_item.html.twig", [
"mission" => $mission,
"campaign" => $mission->getCampaign(),
'currentUser' => $this->security->getUser()
]);
}
public function getHtmlToRenderPlanningByUser(User $user , ?Mission $mission)
{
return $this->twig->render("mission/_planning_item_by_user.html.twig", [
"mission" => $mission,
"campaign" => $mission->getCampaign(),
'currentUser' => $this->security->getUser(),
'user' => $user
]);
}
public function userTyping(User $user)
{
return $this->twig->render('services/messages/one_user_typing_message.html.twig',[
'user_is_typing' => $user
]);
}
public function userWhoRead($message)
{
$users = $this->messageService->getBullUsersWhoReadMessage($message);
return $this->twig->render('services/messages/all_users_who_read.html.twig',[
'user_list' => $users
]);
}
public function messagePinned($message,$user,$dateOffSetHour){
return $this->twig->render('mission/Ux/_one_pinned_message.html.twig',[
'pinned' => $message,
'currentUser' => $user,
'date_off_setHour' => abs($dateOffSetHour),
]);
}
public function extractReplyMetadata(string $text){
$patterns = [
'/(.+)##-+\[CAMPAIGN_ID=(.+)\] +\[MESSAGE_ID=(.+)\]-## /ms',
'/(.+)##- Conservez cette ligne sur vos réponses\. Tout ce qui se trouve au-dessus de cette ligne sera inséré sur la mission et partagé avec l\'ensemble des participants au projet +\[CAMPAIGN_ID=(.+)\] +\[MESSAGE_ID=(.+)\]-## /ms',
'/(.+)##- Conservez cette ligne sur vos réponses\. Tout ce qui se trouve au-dessus de cette ligne sera inséré sur la mission et partagé avec l\'ensemble des participants au projet +\[CAMPAIGN_ID=(.+)\] -## /ms',
] ;
foreach ($patterns as $pattern) {
preg_match($pattern, $text, $matches);
if(isset($matches[1]) && isset($matches[2])){
return [
'messageText'=> $matches[1],
'campaignId'=> $matches[2] ?? null,
'messageId'=>$matches[3] ?? null,
] ;
}
}
return [
'messageText'=> null,
'campaignId'=> null ,
'messageId'=> null ,
];
}
}