alexusmai/laravel-file-manager
A full-featured file manager for Laravel with a responsive UI, multi-user support, ACL permissions, image thumbnails, CKEditor and TinyMCE integration, and a simple API for managing files and folders inside your applications.
composer require <vendor>/file-manager:^3.2 and confirm intervention/image resolves to ^3.0 plus intervention/image-laravel. The abandoned intervention/imagecache is gone — if it's still in your composer.json (directly or via a lock entry), remove it explicitly or composer update will keep dragging it in.php artisan vendor:publish --tag=file-manager-config --force (check the tag with php artisan vendor:publish --list). Diff the published config/file-manager.php against yours before overwriting — the cache key no longer exists.php artisan storage:link, a writable storage/app/public (or your configured disk), and a filesystem disk entry in config/filesystems.php whose url is set if you serve files publicly.php artisan vendor:publish --tag=image-laravel-config (or whatever the provider exposes) creates config/image.php with the driver (gd or imagick).Storage::disk(...)->url().config/file-manager.php (disk, directory, ACL/middleware, allowed mimetypes/extensions), the package's route file (prefix + middleware group), and any place in your app that called config('file-manager.cache') — that's the one guaranteed breakage point.Disk-scoped usage. Keep one disk per concern (public for CMS assets, s3 for user documents) and instantiate/resolve the manager per request rather than toggling the config at runtime. If the package reads disk/dir from config only, wrap it in a small service of your own that takes a disk name and forwards it — this keeps multi-tenant setups (per-tenant directory) clean and testable.
Upload endpoint pattern. Validate in a FormRequest (file, mimes, max), then hand the UploadedFile to the manager rather than calling Storage::putFileAs yourself, so naming/collision rules stay consistent between UI uploads and API uploads. Return the relative path plus a url from a small API resource so the frontend never string-concatenates storage URLs.
Image handling moves to intervention/image-laravel. The package no longer caches derivatives for you. The v3 flow is:
use Intervention\Image\Laravel\Facades\Image;
$image = Image::read(Storage::disk('public')->path($path))
->scale(width: 800);
Storage::disk('public')->put($thumbPath, (string) $image->encodeByExtension('webp'));
Resolve the facade (driver from config/image.php) and build your own derivative pipeline: original → named variant path (products/42/thumb.webp) → store → return URL. Register this in a dedicated ImageVariantService so controllers stay thin and you can swap driver per environment.
Do your own caching. With the cache config key removed, replace it with an explicit layer:
Storage::exists() before regenerating./img/{path}?w=800) behind Cache::remember() or a response-cache middleware, keyed by path + variant + mtime.Cache-Control/Last-Modified/ETag yourself — nothing does it for you now.Queued processing. For large images, dispatch a job after upload that generates variants; the upload response returns the original immediately and the frontend swaps to the derivative when ready. This is also a good place to enforce a max dimension to avoid memory blowups.
Integration with models. Store only the relative path in a media table (path, disk, mime, size, model_type, model_id), never absolute URLs — the URL is derived at render time, so a disk/CDN change doesn't require a data migration.
Auth/ACL. Put the package's routes behind your own middleware group (auth, can:manage-files). If the config exposes an ACL/allow-list hook, use it instead of forking the route file; otherwise wrap the routes with Route::middleware(...)->group() in your own service provider and disable the package's route registration.
cache key is gone. Any config('file-manager.cache'), .env var (FILE_MANAGER_CACHE) or cached-config artifact referencing it will silently return null. Grep for it, then remove the env line and run php artisan config:clear (and config:cache in deploy).intervention/imagecache removal. If your code called Image::cache(...) or ->cache(...) on an image, it will fatal. Delete the abandoned dependency, then rewrite the call site as an explicit store-and-check (see above). Also check composer why intervention/imagecache — it may be pulled in transitively by another package you'll need to bump.Image::make() → Image::read(); managers are constructed with a driver (new ImageManager(new Driver())); most operations return a new instance rather than mutating, so $img->resize(...) without reassignment is a silent no-op. ->save($path, quality) is now ->save($path) / ->encodeByExtension(...) with quality passed via the encoder.Intervention\Image\Laravel\Facades\Image, which collides conceptually with the old Intervention\Image\Facades\Image. If any file still imports the v2 facade, you'll get "class not found" at runtime, not at build time — run a broad grep -rn "Intervention\\\\Image\\\\Facades" through app/, tests/ and any custom package code.gd is the safe default but lacks some formats (notably good WebP/AVIF and EXIF-aware behaviour is inconsistent); imagick needs the PHP extension. Set the driver explicitly per environment and test on the same PHP build as production — "works locally" is usually this.autoOrient(); without it, phone uploads appear rotated after resize. Call it first in the pipeline, before scale().memory_limit once decoded. Cap dimensions before decode where possible and catch Intervention\Image\Exceptions\* — the exception namespace changed in v3.php artisan view:clear and re-publish the config; a stale config/file-manager.php in the app (Laravel merges app config over package config) means the removed cache key may persist and lull you into thinking the feature still works.Storage::fake('public') plus Image::fake() isn't a thing — assert on Storage::assertExists($variantPath) instead, and keep real image fixtures tiny (a 2×2 PNG) so CI doesn't need Imagick.How can I help you explore Laravel packages today?