Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
WebmailEventsApiController
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
2 / 2
2
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 stream
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Modules\Mail\Presentation\Api;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Modules\Mail\Application\Service\WebmailAuthService;
12use Psr\Http\Message\ResponseFactoryInterface;
13use Psr\Http\Message\ResponseInterface;
14use Yiisoft\User\CurrentUser;
15
16/**
17 * Server-Sent Events (SSE) Push Controller for Webmail Live Notifications.
18 *
19 * Keeps a single lightweight, non-blocking stream per client browser session,
20 * broadcasting instant mailbox changes and unread counters without polling mail servers.
21 *
22 * @package App\Modules\Mail\Presentation\Api
23 */
24final readonly class WebmailEventsApiController
25{
26    /**
27     * WebmailEventsApiController constructor.
28     *
29     * @param ResponseFactoryInterface $responseFactory PSR-17 response factory.
30     * @param CurrentUser              $currentUser     Authenticated identity.
31     * @param WebmailAuthService       $authService     Auth service.
32     */
33    public function __construct(
34        private ResponseFactoryInterface $responseFactory,
35        private CurrentUser $currentUser,
36        private WebmailAuthService $authService
37    ) {
38    }
39
40    /**
41     * Handles GET /api/v1/mail/events (SSE Stream).
42     */
43    public function stream(): ResponseInterface
44    {
45        $userId = (int) $this->currentUser->getId();
46        $mailboxes = $this->authService->getUserMailboxes($userId);
47
48        $payload = sprintf(
49            ": connected\r\nevent: initial_state\r\ndata: %s\r\n\r\n",
50            json_encode([
51                'user_id'         => $userId,
52                'mailboxes_count' => count($mailboxes),
53                'timestamp'       => time(),
54            ])
55        );
56
57        $response = $this->responseFactory->createResponse(200)
58            ->withHeader('Content-Type', 'text/event-stream; charset=utf-8')
59            ->withHeader('Cache-Control', 'no-cache, no-transform')
60            ->withHeader('Connection', 'keep-alive')
61            ->withHeader('X-Accel-Buffering', 'no');
62
63        $response->getBody()->write($payload);
64        return $response;
65    }
66}