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

Symfony Temp File Bundle Laravel Package

tourze/symfony-temp-file-bundle

Symfony bundle for managing temporary files: create, track, and automatically clean up temp files through a simple service. Integrates with Symfony's DI container and Filesystem component, giving scratch data a predictable location and lifecycle instead of scattered tempnam() calls.

View on GitHub
Deep Wiki
Context7

Getting Started

tourze/symfony-temp-file-bundle is a small Symfony bundle from the Tourze ecosystem that provides a temp-file service: you ask it for a file (CSV export, generated PDF, downloaded attachment, intermediate upload chunk), it creates it in a managed temp location and hands back the path/handle, and it owns cleanup so your storage/app doesn't fill with orphans.

Be aware up front: this is a Symfony bundle, not a Laravel package. There is no Illuminate\Support\ServiceProvider, no extra.laravel.providers, and no auto-discovery. Installing it gives you a Bundle class, a DI extension, and one or two plain PHP service classes. In a Laravel app you either (a) instantiate the service class directly, or (b) write a two-line service provider that binds it, and skip the Symfony bundle machinery entirely.

Minimal path:

composer require tourze/symfony-temp-file-bundle:^1.1

Then look, in this order:

  1. src/ — the bundle class and, more importantly, the actual temp-file service class(es). This is the only code you'll call; everything else is Symfony plumbing you can ignore.
  2. DependencyInjection/ and the service-definition file (Resources/config/services.php or config/services.php, depending on the release) — this tells you the real constructor arguments and whether the service is shared/singleton.
  3. composer.json — check the symfony/* constraints. If it requires symfony/http-kernel + symfony/framework-bundle at a version incompatible with your Laravel-adjacent stack (or with laravel/framework's Symfony constraints), you'll get resolution conflicts.
  4. tests/ — usually the most reliable documentation of intended usage in Tourze packages.

First use case that pays for itself immediately: a queued export job that writes a temp CSV, mails/downloads it, and lets the temp layer reap the file instead of you hand-rolling tempnam() + unlink() in a finally block.

$path = app(TempFileService::class)->create('csv'); // or similar factory method
// write, hand off, forget

Implementation Patterns

Bind it in a provider rather than loading the bundle. The bundle's build()/load() methods only make sense under a Symfony kernel; calling them from Laravel is a no-op at best. Bind the concrete service:

// app/Providers/TempFileServiceProvider.php
public function register(): void
{
    $this->app->singleton(TempFileService::class, function () {
        return new TempFileService(sys_get_temp_dir()); // match the real ctor
    });
}

Wrap it in your own tiny abstraction. One interface — TempFileFactory with make(string $prefix): TempFile — means your jobs depend on your contract, not on a Tourze class that may be renamed between minor releases. You can then swap in a Storage-disk-backed implementation for tests or for S3.

Controller download with delete-after-send. The natural pairing is Laravel's streamed response with a cleanup callback, so the file survives exactly as long as the transfer:

return response()->streamDownload(function () use ($path) {
    readfile($path);
}, 'export.csv')->deleteFileAfterSend(true);

Queue jobs. Create the temp file inside handle(), never in the constructor (serialized job payloads can't carry a file handle, and the file may be reaped before the job runs). Keep the path, not the object, in any state you persist.

Scheduled reap as a belt-and-braces. Register Schedule::call(fn () => app(TempFileService::class)->cleanup())->hourly() if the package exposes a cleanup entry point; if it only cleans on destruct, you need this for crash-interrupted requests.

Testing. Because the files are not on a Laravel disk, Storage::fake() is irrelevant. Point the service at a per-test directory (sys_get_temp_dir().'/test-'.Str::random()) in setUp(), assert the file exists after the call, and assert it's gone after cleanup — that's the behaviour you actually care about.

Version pinning. Pin ^1.1 and commit the lock file. Tourze publishes many small packages on a fast, largely automated cadence; treating minor bumps as reviewable-but-low-risk and reading the diff is the sane posture.

Gotchas and Tips

  • 1.1.0 ships with an empty changelog — the release notes are just a compare link. Before upgrading, run composer update tourze/symfony-temp-file-bundle --with-dependencies -W on a branch and read git diff 1.0.0..1.1.0 -- src/. Realistically this is dependency churn and test/docs tweaks (the 1.x line has no deprecation surface to break), but "realistically" is not "verified".
  • Symfony bundle ≠ Laravel package. Do not add the bundle class to config/app.php providers. Do not expect php artisan vendor:publish to find anything. There is no config file to publish, and none of Laravel's container conventions apply to the bundle's extension.
  • Temp dir differs between web and CLI. FPM and your queue worker can have different TMPDIR/sys_get_temp_dir() values, and open_basedir may block the queue path. If a job succeeds but the file "vanishes", this is the cause — log sys_get_temp_dir() in both contexts once.
  • Destructor-based cleanup doesn't survive everything. Fatal errors, exit, killed workers, and Octane's long-lived workers all break the assumption that the object goes out of scope promptly. Under Octane a singleton holding temp files will happily live for the whole process lifetime — prefer per-request resolution ($this->app->make(...) inside the method, not constructor injection into a singleton).
  • Not suitable for secrets or long-lived artifacts. Anything security-sensitive should go through Storage with an explicit delete(), where the lifecycle is yours and observable.
  • Permission and ownership mismatch. Files created by the queue user may be unreadable by FPM (and vice versa) if your umask differs; the download will fail with a bare readfile(): failed to open stream. Set a group-writable temp dir or keep creation and consumption in the same process.
  • Cross-platform paths. On Windows the returned path may contain backslashes and realpath() returns false once the file is deleted — assert with file_exists() on the raw path, not realpath().
  • Extension points are limited by design. There's no Laravel-friendly config, so the practical extension surface is: bind your own implementation of the service class, decorate it, or fork the class into app/Support/. For a package this small, forking is often cheaper than fighting the Symfony DI assumptions — and it removes a dependency from your audit surface.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin