src/Controller/ChatController.php line 219

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\ChatMessage;
  4. use App\Repository\ChatMessageRepository;
  5. use App\Repository\TeamRepository;
  6. use App\Repository\SeasonRepository;
  7. use App\Repository\UserRepository;
  8. use App\Service\ChatService;
  9. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\Response;
  12. use Symfony\Component\Routing\Annotation\Route;
  13. use Symfony\Component\Serializer\SerializerInterface;
  14. use Symfony\Component\Serializer\Annotation\Groups;
  15. class ChatController extends AbstractController
  16. {
  17.     public function __construct(
  18.         private ChatService $chatService,
  19.         private ChatMessageRepository $chatMessageRepository,
  20.         private TeamRepository $teamRepository,
  21.         private SeasonRepository $seasonRepository,
  22.         private UserRepository $userRepository,
  23.         private SerializerInterface $serializer
  24.     ) {}
  25.     #[Route('/api/chat/messages'name'api_chat_send_message'methods: ['POST'])]
  26.     public function sendMessage(Request $request): Response
  27.     {
  28.         $data json_decode($request->getContent(), true);
  29.         
  30.         $content $data['content'] ?? null;
  31.         $type $data['type'] ?? null;
  32.         $attachmentUrl $data['attachmentUrl'] ?? null;
  33.         
  34.         if (!$content || !$type) {
  35.             return $this->json(['error' => 'Missing required fields'], Response::HTTP_BAD_REQUEST);
  36.         }
  37.         
  38.         try {
  39.             $team null;
  40.             $season null;
  41.             $recipient null;
  42.             
  43.             if ($type === 'team' && isset($data['teamId'])) {
  44.                 $team $this->teamRepository->find($data['teamId']);
  45.                 if (!$team) {
  46.                     return $this->json(['error' => 'Team not found'], Response::HTTP_NOT_FOUND);
  47.                 }
  48.             } elseif ($type === 'season' && isset($data['seasonId'])) {
  49.                 $season $this->seasonRepository->find($data['seasonId']);
  50.                 if (!$season) {
  51.                     return $this->json(['error' => 'Season not found'], Response::HTTP_NOT_FOUND);
  52.                 }
  53.             } elseif ($type === 'direct' && isset($data['recipientId'])) {
  54.                 $recipient $this->userRepository->find($data['recipientId']);
  55.                 if (!$recipient) {
  56.                     return $this->json(['error' => 'Recipient not found'], Response::HTTP_NOT_FOUND);
  57.                 }
  58.             } elseif ($type === 'global') {
  59.                 // For global messages, team, season, and recipient remain null.
  60.                 // No specific ID is needed.
  61.             } else {
  62.                 // This handles cases where type is not 'team', 'season', 'direct', or 'global',
  63.                 // or if the required ID for those types is missing.
  64.                 return $this->json(['error' => 'Invalid chat type or missing/invalid ID for the given type'], Response::HTTP_BAD_REQUEST);
  65.             }
  66.             
  67.             $message $this->chatService->sendMessage(
  68.                 $content,
  69.                 $type,
  70.                 $team,
  71.                 $season,
  72.                 $recipient,
  73.                 $attachmentUrl
  74.             );
  75.             
  76.             return $this->json($messageResponse::HTTP_CREATED, [], ['groups' => 'chat_message']);
  77.         } catch (\Exception $e) {
  78.             return $this->json(['error' => $e->getMessage()], Response::HTTP_BAD_REQUEST);
  79.         }
  80.     }
  81.     #[Route('/api/chat/team/{id}'name'api_chat_team_messages'methods: ['GET'])]
  82.     public function getTeamMessages(int $idRequest $request): Response
  83.     {
  84.         $team $this->teamRepository->find($id);
  85.         if (!$team) {
  86.             return $this->json(['error' => 'Team not found'], Response::HTTP_NOT_FOUND);
  87.         }
  88.         
  89.         $limit $request->query->getInt('limit'50);
  90.         $offset $request->query->getInt('offset'0);
  91.         
  92.         $messages $this->chatService->getMessages('team'$team$limit$offset);
  93.         
  94.         return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_message']);
  95.     }
  96.     #[Route('/api/chat/season/{id}'name'api_chat_season_messages'methods: ['GET'])]
  97.     public function getSeasonMessages(int $idRequest $request): Response
  98.     {
  99.         $season $this->seasonRepository->find($id);
  100.         if (!$season) {
  101.             return $this->json(['error' => 'Season not found'], Response::HTTP_NOT_FOUND);
  102.         }
  103.         
  104.         $limit $request->query->getInt('limit'50);
  105.         $offset $request->query->getInt('offset'0);
  106.         
  107.         $messages $this->chatService->getMessages('season'$season$limit$offset);
  108.         
  109.         return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_message']);
  110.     }
  111.     #[Route('/api/chat/direct/{id}'name'api_chat_direct_messages'methods: ['GET'])]
  112.     public function getDirectMessages(int $idRequest $request): Response
  113.     {
  114.         $recipient $this->userRepository->find($id);
  115.         if (!$recipient) {
  116.             return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
  117.         }
  118.         
  119.         $limit $request->query->getInt('limit'50);
  120.         $offset $request->query->getInt('offset'0);
  121.         
  122.         $messages $this->chatService->getMessages('direct'$recipient$limit$offset);
  123.         
  124.         return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_message']);
  125.     }
  126.     #[Route('/api/chat/team/{id}/new'name'api_chat_new_team_messages'methods: ['GET'])]
  127.     public function getNewTeamMessages(int $idRequest $request): Response
  128.     {
  129.         $team $this->teamRepository->find($id);
  130.         if (!$team) {
  131.             return $this->json(['error' => 'Team not found'], Response::HTTP_NOT_FOUND);
  132.         }
  133.         
  134.         $since = new \DateTime($request->query->get('since''now'));
  135.         
  136.         $messages $this->chatService->getNewMessages('team'$team$since);
  137.         
  138.         return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_message']);
  139.     }
  140.     #[Route('/api/chat/season/{id}/new'name'api_chat_new_season_messages'methods: ['GET'])]
  141.     public function getNewSeasonMessages(int $idRequest $request): Response
  142.     {
  143.         $season $this->seasonRepository->find($id);
  144.         if (!$season) {
  145.             return $this->json(['error' => 'Season not found'], Response::HTTP_NOT_FOUND);
  146.         }
  147.         
  148.         $since = new \DateTime($request->query->get('since''now'));
  149.         
  150.         $messages $this->chatService->getNewMessages('season'$season$since);
  151.         
  152.         return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_message']);
  153.     }
  154.     #[Route('/api/chat/direct/{id}/new'name'api_chat_new_direct_messages'methods: ['GET'])]
  155.     public function getNewDirectMessages(int $idRequest $request): Response
  156.     {
  157.         $recipient $this->userRepository->find($id);
  158.         if (!$recipient) {
  159.             return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
  160.         }
  161.         
  162.         $since = new \DateTime($request->query->get('since''now'));
  163.         
  164.         $messages $this->chatService->getNewMessages('direct'$recipient$since);
  165.         
  166.         return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_message']);
  167.     }
  168.     #[Route('/api/chat/messages/{id}/read'name'api_chat_mark_read'methods: ['POST'])]
  169.     public function markAsRead(int $id): Response
  170.     {
  171.         $message $this->chatMessageRepository->find($id);
  172.         if (!$message) {
  173.             return $this->json(['error' => 'Message not found'], Response::HTTP_NOT_FOUND);
  174.         }
  175.         
  176.         $this->chatService->markAsRead($message);
  177.         
  178.         return $this->json(['success' => true]);
  179.     }
  180.     #[Route('/api/chat/channels'name'api_chat_channels'methods: ['GET'])]
  181.     public function getChannels(): Response
  182.     {
  183.         $user $this->getUser();
  184.         
  185.         // Get all channels the user has access to
  186.         $channels $this->chatService->getAvailableChannels($user);
  187.         
  188.         // Use serialization groups to prevent circular references
  189.         return $this->json($channelsResponse::HTTP_OK, [], ['groups' => 'chat:channel:list']);
  190.     }
  191.     #[Route('/api/chat/channels/{id}/messages'name'api_chat_channel_messages'methods: ['GET'])]
  192.     public function getChannelMessages(string $idRequest $request): Response
  193.     {
  194.         // Parse the channel ID to determine type and actual ID
  195.         list($type$actualId) = $this->parseChannelId($id);
  196.         
  197.         $limit $request->query->getInt('limit'50);
  198.         $offset $request->query->getInt('offset'0);
  199.         
  200.         $messages $this->chatService->getMessagesByChannel($type$actualId$limit$offset);
  201.         
  202.         return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_message']);
  203.     }
  204.     #[Route('/api/chat/unread-counts'name'api_chat_unread_counts'methods: ['GET'])]
  205.     public function getUnreadCounts(): Response
  206.     {
  207.         $user $this->getUser();
  208.         $counts $this->chatService->getUnreadCountsByChannel($user);
  209.         
  210.         return $this->json($counts);
  211.     }
  212.     #[Route('/api/chat/channels/{id}/read'name'api_chat_mark_channel_read'methods: ['POST'])]
  213.     public function markChannelAsRead(string $id): Response
  214.     {
  215.         // Parse the channel ID to determine type and actual ID
  216.         list($type$actualId) = $this->parseChannelId($id);
  217.         
  218.         $this->chatService->markChannelAsRead($type$actualId);
  219.         
  220.         return $this->json(['success' => true]);
  221.     }
  222.     #[Route('/api/chat/widget-messages'name'api_chat_widget_messages'methods: ['GET'])]
  223.     public function getWidgetMessages(Request $request): Response
  224.     {
  225.         $user $this->getUser();
  226.         if (!$user) {
  227.             return $this->json(['error' => 'User not authenticated'], Response::HTTP_UNAUTHORIZED);
  228.         }
  229.         // Consider a small limit for widget messages, e.g., 5 messages per channel, up to 3-5 channels
  230.         $limitPerChannel $request->query->getInt('limit_per_channel'3);
  231.         $maxChannels $request->query->getInt('max_channels'3);
  232.         try {
  233.             $messages $this->chatService->getRecentMessagesForWidget($user$limitPerChannel$maxChannels);
  234.             // Ensure the response is structured as expected by ChatWidget.vue
  235.             // e.g., { "Channel Name 1": [msg1, msg2], "Channel Name 2": [msg3, msg4] }
  236.             return $this->json($messagesResponse::HTTP_OK, [], ['groups' => 'chat_widget_message']); // Define a new serialization group if needed
  237.         } catch (\Exception $e) {
  238.             // Log the exception $e->getMessage()
  239.             return $this->json(['error' => 'Could not retrieve widget messages'], Response::HTTP_INTERNAL_SERVER_ERROR);
  240.         }
  241.     }
  242.     // Helper method to parse channel IDs
  243.     private function parseChannelId(string $id): array
  244.     {
  245.         if ($id === 'global') {
  246.             return ['global'null];
  247.         }
  248.         
  249.         $parts explode('-'$id);
  250.         if (count($parts) !== 2) {
  251.             throw new \InvalidArgumentException('Invalid channel ID format');
  252.         }
  253.         
  254.         return [$parts[0], (int)$parts[1]];
  255.     }
  256.     #[Route('/chat'name'chat_index')]
  257.     public function index(): Response
  258.     {
  259.         return $this->render('chat/index.html.twig');
  260.     }
  261.     // Remove old chat routes
  262.     // #[Route('/chat/team/{id}', name: 'chat_team', methods: ['GET'])]
  263.     // ...
  264.     // #[Route('/chat/season/{id}', name: 'chat_season', methods: ['GET'])]
  265.     // ...
  266.     // #[Route('/chat/direct/{id}', name: 'chat_direct', methods: ['GET'])]
  267.     // ...
  268. }