Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Symfony2 Stream Response Laravel Package

nercury/symfony2-stream-response

Symfony2 Stream Response adds a simple streamed response type to Symfony 2, enabling applications to send large files or dynamically generated content to the client incrementally instead of buffering the full output in memory. Useful for downloads, exports, and real-time data.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the mismatch: this is a Symfony2 bundle, not a Laravel package. There is no service provider, no facade, no config/ publish tag. If you are working in a Laravel codebase you will not composer require this and get anything useful — you will use response()->stream() instead. The value of reading this repo is the pattern, not the dependency.

If you genuinely are on a legacy Symfony2 app (or maintaining one):

  1. Add to composer.json — the package is unmaintained and likely needs "minimum-stability": "dev" and possibly a "replace"/fork to install against modern PHP.
  2. Register the bundle in app/AppKernel.php:
    new Nercury\StreamResponseBundle\StreamResponseBundle(),
    
  3. Look first at the bundle's response class (it extends Symfony\Component\HttpFoundation\StreamedResponse) and its stream()/callback contract — that callback is the whole package.
  4. First use case: a long-running export/report page that writes progress to the browser as it works, instead of hanging on a white screen for 60 seconds.

If you are on Laravel, the equivalent first step is:

Route::get('/export', function () {
    return response()->stream(function () {
        foreach (range(1, 10) as $i) {
            echo "Chunk {$i}\n";
            ob_flush(); flush();
            sleep(1);
        }
    }, 200, ['Content-Type' => 'text/plain', 'X-Accel-Buffering' => 'no']);
});

That is the same idea this bundle wraps, and it is what you should reach for on day one.

Implementation Patterns

The core pattern — write, flush, repeat. Every streaming implementation, Symfony2 or Laravel, is a callback that emits a chunk and forces it out the door:

// Symfony2 with this bundle (shape of the API, verify against the class)
$response = $this->get('nercury.stream_response')->create(function ($out) {
    foreach ($rows as $row) {
        $out->write(json_encode($row) . "\n");
        $out->flush();
    }
});
$response->headers->set('Content-Type', 'application/x-ndjson');
return $response;

Progress/status pattern (the real day-to-day use): emit JSON lines the frontend consumes with fetch + a ReadableStream reader, or an EventSource if you keep it text/event-stream. Keep each chunk a complete, parseable unit — newline-delimited JSON is the least fragile choice.

Heartbeat pattern: for anything that can idle (queued job polling, slow DB cursor), emit a comment/ping line on a timer so proxies and load balancers don't kill an apparently dead connection. In SSE that is : ping\n\n.

Detach the session before streaming. Both Symfony2 and Laravel hold a session write lock for the request. Call session_write_close() (Laravel: session()->save() or just close it) at the top of the callback, otherwise the user's next request blocks until the stream ends — a classic self-inflicted deadlock.

Laravel-side translation of the pattern: use response()->stream() for callback-style streaming, response()->streamDownload() when you want the browser to save a file, and Response::stream() directly if you need to build the callback outside a route. For a job-progress UI, the modern Laravel idiom is a cached progress value polled by the frontend, with streaming reserved for genuinely incremental output.

Integration tip: put the chunk-producing logic in a plain class that yields rows, and keep the controller as a thin adapter that writes whatever the generator yields. Then the same generator serves the streaming route, the queued-job version, and a test that iterates it without touching HTTP.

Gotchas and Tips

  • It is abandoned. Symfony2 itself is EOL. Treat this as reference material; do not introduce it into new work, and do not expect a security patch.
  • Output buffering eats your stream. ob_get_level() may be non-zero (framework, gzip, mod_deflate). You usually need while (ob_get_level()) ob_end_flush(); before the loop or nothing appears until the end. This is the bug people file as "my streaming doesn't stream."
  • Nginx buffers by default. fastcgi_buffering off; or a X-Accel-Buffering: no response header; Apache needs SetEnv no-gzip / flush() discipline. Works on your machine, hangs in staging, because the proxy is different.
  • Do not set Content-Length on a stream, and beware anything upstream that computes one for you. Chunked transfer is the point.
  • Timeouts cut long streams silently. max_execution_time, PHP-FPM request_terminate_timeout, and the proxy's read timeout all apply. Send periodic bytes to keep every layer warm.
  • fastcgi_finish_request() is for the opposite case — post-response work with a normal response. Don't mix it into a stream callback.
  • Errors mid-stream are unrecoverable. Once bytes and a 200 are sent you cannot change the status code. Catch inside the callback, emit an error line in your chunk format, and let the client decide.
  • Debugging: curl -N is your friend — it disables curl's buffering and shows arrival timing. Chrome DevTools' network panel also shows chunk arrival. If curl -N streams but the browser doesn't, it is a browser/proxy/header problem, not your PHP.
  • Testing: never assert on streamed output via a normal HTTP test client that buffers the whole body — you'll test correctness but not streaming. Test the generator separately, and smoke-test streaming manually.
  • Extension point, if you fork it: the only worthwhile surface is the write/flush abstraction. Keep it small — one write(string), one flush(), one close() — so you can swap in an SSE formatter or an NDJSON formatter without touching controllers.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums