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

Gaufrette Extras Laravel Package

kphoen/gaufrette-extras

Extra adapters and utilities for the Gaufrette filesystem abstraction library. Extends Gaufrette with additional storage backends and helpers, letting PHP applications manage local and remote files through a consistent interface with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install alongside Gaufrette (the package is a set of decorators, not a standalone filesystem):

    composer require kphoen/gaufrette-extras
    

    Check what Gaufrette version constraint Composer resolves — the package dates from 2015 and targets the 0.2/0.3 era API, so expect to pin gaufrette/gaufrette accordingly.

  2. Read the README and src/ first. The library is small (a handful of classes), so the fastest path is to skim the resolver interface and the filesystem decorator rather than looking for docs. There is no official documentation site and no Laravel/Symfony bundle.

  3. Identify the one problem it solves: generating a public URL for a file held in a Gaufrette filesystem. Gaufrette gives you read/write/has, but not "where do I point a browser at this?" — this package fills that gap by decorating a Filesystem with a resolver.

  4. Minimal first use case:

    use Gaufrette\Filesystem;
    use Gaufrette\Adapter\Local;
    use Gaufrette\Extras\ResolvableFilesystem;
    use Gaufrette\Extras\Resolvable\Resolver\LocalResolver;
    
    $adapter     = new Local('/var/www/app/storage/uploads');
    $filesystem  = new ResolvableFilesystem(
        new Filesystem($adapter),
        new LocalResolver('/uploads') // public base URL
    );
    
    $filesystem->write('avatars/42.png', $binary);
    echo $filesystem->resolve('avatars/42.png'); // /uploads/avatars/42.png
    

    That decorator is the package's reason to exist — everything else is supporting glue.

  5. If you're on Laravel, wrap that construction in a small service provider and bind ResolvableFilesystem (or an app-specific interface) into the container. Don't try to swap Laravel's Storage facade for it unless you specifically need a Gaufrette adapter (FTP, GridFS, custom S3 layout) that Laravel doesn't ship.

Implementation Patterns

Decorator-over-existing-filesystem. The idiomatic pattern is to keep your existing Gaufrette Filesystem for reads/writes and wrap it only where URLs are needed:

$base = new Filesystem($adapter);              // used elsewhere
$resolvable = new ResolvableFilesystem($base, $resolver);

Because it decorates rather than replaces, you can register both in the container and inject the plain Filesystem for I/O and the resolvable one for view/URL concerns.

Resolver-per-backend. Keep URL construction out of your domain code by giving each storage backend its own resolver. A LocalResolver with a public base path in dev; a bucket/CDN-aware resolver in production. The ResolverInterface is the seam to implement if the package's built-in resolvers don't cover your backend (e.g. a custom signed-URL generator):

class SignedS3Resolver implements ResolverInterface
{
    public function resolve($path) { /* return pre-signed URL */ }
}

Chain / fallback resolvers. For multi-bucket or multi-drive setups, compose resolvers: try the primary, fall back to a read-only archive resolver. This keeps "where does this file live?" logic in one place instead of scattered if statements.

Presenter / Twig / Blade integration. Never expose raw paths. Resolve at the rendering boundary — a Blade directive, a small present() method on a view model, or a dedicated transformer — so the filesystem remains a data concern:

// Blade: {{ $url->forPath($user->avatar_path) }}

Config-driven wiring. Put base URLs, bucket names, and CDN hosts in config, not in resolver constructors scattered through the app. In Laravel this is a config/filesystems.php-style entry plus a singleton binding; in plain PHP it's a small factory.

Testing. Use Gaufrette's in-memory/local adapter in tests and a fake resolver that returns deterministic URLs (https://cdn.test/{path}). This lets you assert URL generation without touching real storage, and avoids the common trap of tests that "pass" because the file happens to exist on the dev machine.

Gotchas and Tips

  • It's effectively abandoned. Last release 2015-09-29, 8 stars, 0 dependents. Treat it as vendored code: pin the exact version, read every class before relying on it, and be prepared to fork. MIT license makes that painless.
  • PHP 5 era constraints. Composer metadata will fight modern PHP (^8.x) and modern Gaufrette. You may need to fork with updated composer.json constraints, or drop the package and copy the two or three classes you actually use into your app — often the sanest choice for something this small.
  • Gaufrette API drift. Filesystem, Adapter, and metadata signatures changed across Gaufrette 0.2 → 0.9. A decorator written against 0.2 can silently break (or fatal) on newer versions. Verify the resolved Gaufrette version and run the package's own test suite against it.
  • resolve() does not check existence. It builds a URL from a key; it won't tell you the file is missing. Pair it with $filesystem->has($path) (or catch FileNotFound) at the boundary where you build the URL, otherwise you'll emit dead links.
  • LocalResolver assumes the web server serves that directory. It just concatenates a base URL and path. If your uploads live outside public/, the URL will 404 — either symlink, serve via a controller, or use a signed resolver instead.
  • No caching, no invalidation. If you front storage with a CDN, URL stability and cache-busting are your problem, not the package's. Consider versioned keys (avatars/42-v3.png) rather than expecting the resolver to handle it.
  • Path traversal and encoding. Resolvers generally do not sanitize keys. Don't pass user-supplied keys straight through; normalize and validate before resolving, and be careful with keys containing spaces or ...
  • No framework integration. There is no Laravel service provider or Symfony bundle here. You write the wiring yourself; keep it in one place (a service provider) so swapping the library out later is a one-file change.
  • Debugging tip. Because the decorator delegates most calls to the inner filesystem, var_dump/dd on the resolvable instance is noisy. When something misbehaves, test the resolver in isolation ($resolver->resolve('foo/bar.txt')) before suspecting the filesystem.
  • Extension point. ResolverInterface is the intended customization seam. If you need signed URLs, CDN host rewriting, or per-tenant buckets, implement it rather than subclassing the filesystem — that keeps you compatible if you later replace the package.
  • Consider whether you need it at all. For a greenfield Laravel app, Storage::url() already covers this. Reach for Gaufrette + these extras only when you're already committed to a Gaufrette adapter Laravel lacks (FTP, GridFS, a legacy S3 layout), or when maintaining an older codebase that already depends on it.
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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel