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

Filesystem Laravel Package

sfcod/filesystem

Sfcod Filesystem is a Laravel package that simplifies working with files and directories through convenient helpers for uploads, storage, copying, moving, and deletion, while integrating cleanly with Laravel's Storage and filesystem abstractions.

View on GitHub
Deep Wiki
Context7

Getting Started

The published description is the only prose documentation that ships with this package, so treat the source as the spec. Budget 30–45 minutes to read it before writing any code.

Install and pin

composer require sfcod/filesystem:^1.1

Pin to ^1.1 rather than dev-main. With 9 stars, 0 dependents, and a single release in 2022, you want a lockfile entry you can diff and roll back, not a moving target.

Where to look first, in this order

  1. composer.json of the package — the require block is the real documentation. Check the illuminate/* / laravel/framework constraint and the league/flysystem constraint. The 1.1.0 changelog says only "Updated to SD 5.4"; if SD is an upstream storage dependency, this constraint tells you whether the package targets Flysystem 1/2 (Laravel ≤8 era) or Flysystem 3 (Laravel 9+). If it caps you below Flysystem 3, it will not install cleanly on a modern Laravel app — stop here.
  2. src/ — find the service provider first (auto-discovery or manual registration), then the class the provider binds. That class is the API surface; read every public method signature. Most thin wrappers expose a handful of read/write/copy/delete/exists/files-style methods plus path helpers.
  3. The facade, if one exists — check getFacadeAccessor() and any alias registered in extra.laravel.aliases.
  4. The GitHub README/issues — but expect little; the description you already have is the README.

Your first use case

The package's stated value is removing Storage::disk('s3')->put(...) boilerplate for everyday read/write/copy/delete. So the smallest useful trial is:

  • Configure a disk exactly as you normally would in config/filesystems.php (the package claims to drop into existing Storage config, so no new config file should be required — verify by checking the provider for publishes() and mergeConfigFrom()).
  • In a throwaway route or tinker session, perform one write, one read, one copy, and one delete against local, then repeat against an S3-compatible disk.
  • Compare the return values and exception types against the raw Storage call. That single exercise tells you whether the wrapper is a faithful pass-through or has its own conventions.

Do not integrate it into application code until you have confirmed three things: it resolves on your Laravel/Flysystem version, it delegates to the Storage facade (not its own Flysystem instantiation), and its return/exception contract matches what your error handling expects.

Implementation Patterns

Treat it as sugar, not architecture. The package is infrastructure and explicitly not a differentiator. Put it behind your own small interface — a FileStore contract with the four or five operations you actually use — and let one adapter call sfcod/filesystem while another calls Storage directly. If the package stalls (last release 2022, single maintainer), swapping the adapter is a one-file change instead of a grep across the codebase. This is the single highest-leverage pattern for a 9-star dependency.

Disk selection. Decide up front whether you pass a disk name per call or rely on the default. Per-call is more verbose but survives multi-tenant or multi-bucket setups where FILESYSTEM_DISK varies by environment. If the wrapper only reads the default disk, you lose a capability you had with Storage::disk() — check before committing.

Keep business logic out of the wrapper. Use it at the edges: controllers, jobs, import/export services. Do not let helper calls leak into domain models. The abstraction is thinner than your requirements will be, and it will not survive a change of storage backend on its own.

Testing. Laravel's Storage::fake() only intercepts the Storage facade. If the package resolves its own Filesystem instance from the container, fakes will silently no-op and your tests will write to the real disk. Write one test asserting a fake disk received a file before you trust the suite. If fakes don't work, fall back to a real temp directory with storage_path/sys_get_temp_dir() in tearDown.

Jobs and queues. For anything user-uploaded or larger than a few MB, check whether the helper streams or buffers. A convenience read that returns a string will OOM on a 500 MB file. If the wrapper lacks streaming, drop to Storage::disk()->readStream() for those paths and use the package only for small metadata-style files.

Directory helpers. Path joining and directory listing are where wrappers most often diverge from native behaviour (trailing slashes, recursive flags, hidden files). Normalize paths at your boundary — ltrim($path, '/') — and write a test for folder/ vs folder before you rely on either.

Migration pattern. If you adopt it mid-project, replace Storage:: call sites file-by-file rather than in one sweep, and run the suite after each file. The changelog gives you no signal about behavioural changes between versions, so the only reliable regression check is your own tests.

Gotchas and Tips

  • "Updated to SD 5.4" is the entire changelog. It tells you what moved, not whether your code is affected. Before upgrading in a real app, confirm with composer why sfcod/filesystem and composer update --dry-run that the transitive dependency resolves, and note in the PR whether you actually exercise the affected path. Unverified is unverified.
  • Flysystem major version is the silent killer. A 2022 package may target Flysystem 1 or 2. Laravel 9+ ships Flysystem 3, where League\Flysystem\FileNotFoundException became UnableToReadFile. If the package type-hints or catches the old classes, your try/catch blocks will not fire. Grep the source for League\Flysystem imports before assuming compatibility.
  • Exception contract. Thin wrappers frequently swallow exceptions and return false. If yours does, code that checks if (!$result) will work but code that relies on exceptions will not — and a failed S3 write will look like a successful no-op. Wrap every call in a check and log the disk name plus path on failure.
  • Return values. Verify whether put/copy/delete return bool or void. Laravel's own API changed here historically, and wrappers copy whatever they were written against.
  • Path normalisation across disks. local resolves relative to storage/app; S3 treats the key as a root-level object key. A leading slash that is harmless locally creates an empty-named folder on S3. Strip it centrally.
  • Visibility and ACLs. Local public visibility is a filesystem permission; S3 visibility is an object ACL or a bucket policy. If the wrapper's helpers do not accept a visibility argument, you cannot serve public assets from S3 without a separate call.
  • Service provider registration. If the package predates auto-discovery or has a malformed extra.laravel block, you will get a container binding error with no helpful message. Confirm the provider appears in php artisan about or bootstrap/cache/packages.php; if not, register it manually in config/app.php.
  • Config publishing. If a publish tag exists, publish and commit the config file so environment-specific settings are reviewable in diffs. If none exists, do not assume the package reads your filesystems.disks array — check where it gets its disk config.
  • Debugging tip. Storage::disk('name')->getAdapter() and Storage::disk('name')->path('') are the fastest way to confirm which root a wrapper call actually hit. Add a temporary Log::debug() of the resolved disk and path inside your adapter the first time something lands in the wrong place.
  • Extension points. The realistic ones are: subclass the wrapper and override a method, or bind your own implementation of its contract in a service provider via $this->app->bind(). Forking is a last resort but is legitimate here — at 9 stars and one maintainer, vendoring is the documented fallback if the package becomes load-bearing.
  • Maintenance signal, not a feature signal. The 1.1.0 release should not pull you off committed work. Schedule the bump inside a normal maintenance window, run CI plus a staging pass, and keep the bump in its own commit so rollback is one revert.
  • Do not adopt it to avoid writing five lines. If your usage is a single disk and three call sites, Storage is already the right tool. The package earns its dependency only when you have multiple disks and genuinely repetitive boilerplate — and even then, only if the source review above comes back clean.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource