@@ -951,6 +951,121 @@ This way, browsers can start downloading the assets immediately; like the
951951``sendEarlyHints() `` method also returns the ``Response `` object, which you
952952must use to create the full response sent from the controller action.
953953
954+ .. _controller-server-sent-events :
955+
956+ Streaming Server-Sent Events
957+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
958+
959+ `Server-Sent Events (SSE) `_ is a standard that allows a server to push updates
960+ to the client over a single HTTP connection. It's a simple and efficient way
961+ to send real-time updates from the server to the browser, such as live
962+ notifications, progress updates, or data feeds.
963+
964+ .. versionadded :: 7.3
965+
966+ The ``EventStreamResponse `` and ``ServerEvent `` classes were introduced in Symfony 7.3.
967+
968+ The :class: `Symfony\\ Component\\ HttpFoundation\\ EventStreamResponse ` class
969+ allows you to stream events to the client using the SSE protocol. It automatically
970+ sets the required headers (``Content-Type: text/event-stream ``, ``Cache-Control: no-cache ``,
971+ ``Connection: keep-alive ``) and provides a simple API to send events::
972+
973+ use Symfony\Component\HttpFoundation\EventStreamResponse;
974+ use Symfony\Component\HttpFoundation\ServerEvent;
975+
976+ // ...
977+
978+ public function liveNotifications(): EventStreamResponse
979+ {
980+ return new EventStreamResponse(function (): iterable {
981+ foreach ($this->getNotifications() as $notification) {
982+ yield new ServerEvent($notification->toJson());
983+
984+ sleep(1); // simulate a delay between events
985+ }
986+ });
987+ }
988+
989+ The :class: `Symfony\\ Component\\ HttpFoundation\\ ServerEvent ` class is a DTO
990+ that represents an SSE event following `the WHATWG specification `_. You can
991+ customize each event using its constructor arguments::
992+
993+ // basic event with just data
994+ yield new ServerEvent('Some message');
995+
996+ // event with a custom type (client listens via addEventListener('my-event', ...))
997+ yield new ServerEvent(
998+ data: json_encode(['status' => 'completed']),
999+ type: 'my-event'
1000+ );
1001+
1002+ // event with an ID (useful for resuming streams with Last-Event-ID header)
1003+ yield new ServerEvent(
1004+ data: 'Update content',
1005+ id: 'event-123'
1006+ );
1007+
1008+ // event that tells the client to retry after a specific time (in milliseconds)
1009+ yield new ServerEvent(
1010+ data: 'Retry info',
1011+ retry: 5000
1012+ );
1013+
1014+ // event with a comment (can be used for keep-alive)
1015+ yield new ServerEvent(comment: 'keep-alive');
1016+
1017+ For use cases where generators are not feasible, you can use the
1018+ :method: `Symfony\\ Component\\ HttpFoundation\\ EventStreamResponse::sendEvent `
1019+ method for manual control::
1020+
1021+ use Symfony\Component\HttpFoundation\EventStreamResponse;
1022+ use Symfony\Component\HttpFoundation\ServerEvent;
1023+
1024+ // ...
1025+
1026+ public function liveProgress(): EventStreamResponse
1027+ {
1028+ return new EventStreamResponse(function (EventStreamResponse $response) {
1029+ $redis = new \Redis();
1030+ $redis->connect('127.0.0.1');
1031+ $redis->subscribe(['message'], function (/* ... */, string $message) use ($response) {
1032+ $response->sendEvent(new ServerEvent($message));
1033+ });
1034+ });
1035+ }
1036+
1037+ On the client side, you can listen to events using the native ``EventSource `` API:
1038+
1039+ .. code-block :: javascript
1040+
1041+ const eventSource = new EventSource (' /live-notifications' );
1042+
1043+ // listen to all events (without a specific type)
1044+ eventSource .onmessage = (event ) => {
1045+ console .log (' Received:' , event .data );
1046+ };
1047+
1048+ // listen to events with a specific type
1049+ eventSource .addEventListener (' my-event' , (event ) => {
1050+ console .log (' My event:' , JSON .parse (event .data ));
1051+ });
1052+
1053+ // handle connection errors
1054+ eventSource .onerror = (error ) => {
1055+ console .error (' SSE error:' , error);
1056+ eventSource .close ();
1057+ };
1058+
1059+ .. warning ::
1060+
1061+ ``EventStreamResponse `` is designed for small applications with limited
1062+ concurrent connections. Because SSE keeps HTTP connections open, it consumes
1063+ server resources (memory and connection limits) for each connected client.
1064+
1065+ For high-traffic applications that need to broadcast updates to many clients
1066+ simultaneously, consider using :doc: `Mercure </mercure >`, which is built on
1067+ top of SSE but uses a dedicated hub to manage connections efficiently.
1068+
9541069Final Thoughts
9551070--------------
9561071
@@ -991,3 +1106,5 @@ Learn more about Controllers
9911106.. _`Validate Filters` : https://www.php.net/manual/en/filter.constants.php
9921107.. _`phpstan/phpdoc-parser` : https://packagist.org/packages/phpstan/phpdoc-parser
9931108.. _`phpdocumentor/type-resolver` : https://packagist.org/packages/phpdocumentor/type-resolver
1109+ .. _`Server-Sent Events (SSE)` : https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
1110+ .. _`the WHATWG specification` : https://html.spec.whatwg.org/multipage/server-sent-events.html
0 commit comments