short-edition/knp-gaufrette-bundle
Symfony bundle integrating Gaufrette, the PHP filesystem abstraction library. Configure local and remote filesystem adapters as services, inject them into your app, and use Gaufrette's stream wrapper for uniform file access across storage backends.
Read this first: it is not a Laravel package. This is a Symfony Bundle. There is no service provider, no facade, no config/gaufrette.php, no KnpGaufretteBundle::class => ['all' => true] equivalent in bootstrap/app.php. It depends on Symfony's kernel, DI container, and YAML compiler passes. If the target is Laravel, stop reading the "how to use" parts and treat the decision as "use league/flysystem via Laravel's built-in Storage facade instead." Laravel already ships Flysystem; adding a Symfony bundle to that mix is not a migration path, it's a dead end.
If the target is a Symfony app (the only context where any of the rest applies):
composer require short-edition/knp-gaufrette-bundle, then register the bundle in config/bundles.php alongside the other Symfony bundles. Verify composer.json PHP and Symfony constraints against your composer.json before committing — this fork is old enough that a lockfile mismatch is common.config/packages/knp_gaufrette.yaml with a filesystems: map. Give each fs a name, an adapter, and optional wrappers.
knp_gaufrette:
adapters:
uploads_local: { local: { directory: '%kernel.project_dir%/var/uploads' } }
media_s3: { aws_s3: { service_id: 'app.s3_client', bucket: '%env(S3_BUCKET)%' } }
filesystems:
uploads: { adapter: uploads_local, stream_wrapper: true }
media: { adapter: media_s3, stream_wrapper: false }
knplabs/KnpGaufretteBundle. The whole reason this fork exists should be visible in Filesystem\DependencyInjection\ and the commit log. Do that diff before writing a line of application code.Gaufrette\Filesystem for one named fs and write a file. Day-to-day operations are write(), read(), has(), delete(), rename(), keys(), mimeType() — same API regardless of backend. If you can write a file to uploads in dev and to media in staging without changing application code, the abstraction is working. If not, the problem is config, not your code.gaufrette.<name> and also exposes a FilesystemMap. In a Symfony service, prefer arguments: ['@gaufrette.uploads'] with a Filesystem type-hint. Where there is exactly one fs, alias the type globally so services inject by type. Never call the container directly from a controller.dev, test, and prod YAML blocks and let the adapter differ. Dev → local, test → in-memory or a temp dir, prod → S3/GCS. This is the pattern that removes "works locally, fails in CI" defects from file handling, and it is the day-to-day reason to use the bundle at all.uploads, exports, backups, media should be distinct named filesystems even if two share an S3 bucket. That lets you swap an adapter for one domain without touching the others, and it lets the ops team rotate credentials per adapter.stream_wrapper: true only where PHP-native functions will be used (e.g. getimagesize('gaufrette://media/thumb.jpg')). Leave it off for filesystems that will only ever be touched through the Filesystem object — fewer moving parts, fewer boot-time registration surprises.Cache (APCu or Redis) when the same files are stat'd or listed repeatedly (gallery listings, template thumbnails). Do not wrap adapters that receive writes from outside the app — the cache goes stale immediately.Checksum on archives and backup filesystems where you need hash verification, and disable it elsewhere — it costs an extra read per file.config/packages/test/knp_gaufrette.yaml, point every filesystem at local (or in-memory) inside var/cache/test/. Never test against S3 in CI. If a test needs an fs that doesn't exist in test config, add it rather than mocking the Filesystem — mocking a filesystem abstraction is almost always the wrong tool.knplabs/KnpGaufretteBundle. For a Laravel roadmap the equivalent is Flysystem; for a greenfield Symfony roadmap the equivalent is league/flysystem-bundle. Adopt this bundle only when an existing Symfony codebase is already on Gaufrette.$fs->has('.health')) behind a console command so misconfiguration fails loudly and early.gaufrette:// wrappers are registered during kernel boot, and CLI vs FPM can behave differently if the bundle boots differently in each. If file_exists('gaufrette://media/x') silently returns false, run php -r 'print_r(stream_get_wrappers());' and confirm gaufrette is registered before debugging your code.gaufrette.<name> IDs are derived from YAML keys. Rename a filesystem in config and every hardcoded @gaufrette.<name> reference in services silently breaks at runtime rather than at compile time. Keep the name in one constant or a thin domain wrapper service if the name appears anywhere outside the YAML.Filesystem interface is lowest-common-denominator. Presigned URLs, multipart upload tuning, S3 lifecycle rules, object lock, GCS IAM — none of them are exposed. When you need them you will reach through the adapter to the native client and bypass the abstraction, which is the worst of both worlds. Decide up front which operations stay on the abstraction and which legitimately use the SDK directly, and document that split.bin/console. When "it works in web but not in commands" shows up, check posix_getpwuid(posix_geteuid()) in both contexts and align directory ownership.How can I help you explore Laravel packages today?