diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 6616aa0adfed3..6861b3b365983 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.3 +--- + + * Add support for iterable of string in `StreamedResponse` + 7.2 --- @@ -40,7 +45,7 @@ CHANGELOG * Add `UriSigner` from the HttpKernel component * Add `partitioned` flag to `Cookie` (CHIPS Cookie) * Add argument `bool $flush = true` to `Response::send()` -* Make `MongoDbSessionHandler` instantiable with the mongodb extension directly + * Make `MongoDbSessionHandler` instantiable with the mongodb extension directly 6.3 --- diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php index 3acaade17d645..6eedf1c49d2e8 100644 --- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php +++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php @@ -14,7 +14,7 @@ /** * StreamedResponse represents a streamed HTTP response. * - * A StreamedResponse uses a callback for its content. + * A StreamedResponse uses a callback or an iterable of strings for its content. * * The callback should use the standard PHP functions like echo * to stream the response back to the client. The flush() function @@ -32,19 +32,36 @@ class StreamedResponse extends Response private bool $headersSent = false; /** - * @param int $status The HTTP status code (200 "OK" by default) + * @param callable|iterable|null $callbackOrChunks + * @param int $status The HTTP status code (200 "OK" by default) */ - public function __construct(?callable $callback = null, int $status = 200, array $headers = []) + public function __construct(callable|iterable|null $callbackOrChunks = null, int $status = 200, array $headers = []) { parent::__construct(null, $status, $headers); - if (null !== $callback) { - $this->setCallback($callback); + if (\is_callable($callbackOrChunks)) { + $this->setCallback($callbackOrChunks); + } elseif ($callbackOrChunks) { + $this->setChunks($callbackOrChunks); } $this->streamed = false; $this->headersSent = false; } + /** + * @param iterable $chunks + */ + public function setChunks(iterable $chunks): static + { + $this->callback = static function () use ($chunks): void { + foreach ($chunks as $chunk) { + echo $chunk; + } + }; + + return $this; + } + /** * Sets the PHP callback associated with this Response. * diff --git a/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php index 2a2b7e7318b2e..78a777aeabd82 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php @@ -25,6 +25,17 @@ public function testConstructor() $this->assertEquals('text/plain', $response->headers->get('Content-Type')); } + public function testConstructorWithChunks() + { + $chunks = ['foo', 'bar', 'baz']; + $callback = (new StreamedResponse($chunks))->getCallback(); + + ob_start(); + $callback(); + + $this->assertSame('foobarbaz', ob_get_clean()); + } + public function testPrepareWith11Protocol() { $response = new StreamedResponse(function () { echo 'foo'; });